2012年1月13日星期五

x86 inline assembly gcc/gas

每次都忘記, 每次都搞不清楚, 這次我決定記下來並且搞清楚。

gcc 的 inline assembly 有好幾種語法, 有簡單的、有複雜的, 這裡只介紹最複雜的那種 (placeholders : 那個 %0, %1, 完全搞不清楚。), 因為有這種最複雜的語法就可以搞定一切。我用一個對照的語法來說明, 這樣會比較好了解。這邊示範的是 x86 組合語言。

12-15, 26-29 直接拿來比對就知道 placeholders 到底怎麼用。
先把 "d"(data1) -> "r"(data1), "c"(data2) -> "r"(data2),
"=a"(result) -> "=r"(result), 夠簡單吧!
d 表示使用 edx
c 表示使用 ecx
a 表示使用 eax
r 表示使用任何可用的 general-purpose register
所以用 r 可能還是會用到 edx, ecx, eax 的組合, 或是 ebx, edx, eax, 讓 compiler 來煩惱就好。

再來是神奇的 %0, %1, %2

imull %%edx, %%ecx
20 行注解寫到 %1 -> data1, data1 在 15 行是 "d"(data1), d 表示 edx, 所以換掉 %%edx =>
imull %1, %%ecx

"movl %%ecx, %%eax"
參照 line 28, 14 =>
"movl %%ecx, %0"

參照 line 29, 15
依樣畫葫蘆得到
%%ecx -> %2
所以
imull %1, %%ecx
imull %1, %2

"movl %%ecx, %0"
"movl %2, %0"

這就變成 line 26 - 29 的 placeholders 版本。

看看產生的組合語言程式 (inline_asm_placeholders.s line 20, 21), 使用 r 的版本 (placeholders) 只用了 eax, edx, 沒有用到 ecx register。placeholders 的語法還可以最佳化轉譯出來的組合語言程式碼。

inline_asm.c
 1 #include <stdio.h>
2
3 #define PLACEHOLDERS
4
5 #ifndef PLACEHOLDERS
6 int main(void)
7 {
8 int data1=10;
9 int data2=20;
10 int result;
11
12 asm ("imull %%edx, %%ecx\n\t" (%edx, %ecx 暫存器的值相乘後存回 %ecx (這是 at&t 語法的關係) )
13 "movl %%ecx, %%eax" (這麼簡單不用說明吧!)
14 :"=a"(result) (a (eax) 的值存入 result, = 表示從暫存器 output 到變數, 名為 Constraint Modifiers)
15 :"d"(data1), "c"(data2)); // data1 存入 d(edx), data2 存入 c (ecx)
16 printf("the result is %d\n", result);
17 return 0;
18 }
19 #else
20 int main(void)
21 {
22 int data1=10;
23 int data2=20;
24 int result;
25
26 asm ("imull %1, %2\n\t"
27 "movl %2, %0"
28 :"=r"(result) // %0 (result)
29 :"r"(data1), "r"(data2)); // %1 (data1), %2 (data2)
30 printf("placeholders : the result is %d\n", result);
31 return 0;
32 }
33 #endif




inline_asm.s
 1  .file "inline_asm.c"
2 .section .rodata
3 .LC0:
4 .string "the result is %d\n"
5 .text
6 .globl main
7 .type main, @function
8 main:
9 pushl %ebp
10 movl %esp, %ebp
11 andl $-16, %esp
12 subl $32, %esp
13 movl $10, 28(%esp)
14 movl $20, 24(%esp)
15 movl 28(%esp), %eax
16 movl 24(%esp), %ecx
17 movl %eax, %edx
18 #APP
19 # 12 "inline_asm.c" 1
20 imull %edx, %ecx
21 movl %ecx, %eax
22 # 0 "" 2
23 #NO_APP
24 movl %eax, 20(%esp)
25 movl $.LC0, %eax
26 movl 20(%esp), %edx
27 movl %edx, 4(%esp)
28 movl %eax, (%esp)
29 call printf
30 movl $0, %eax
31 leave
32 ret
33 .size main, .-main
34 .ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
35 .section .note.GNU-stack,"",@progbits




inline_asm_placeholders.s
 1  .file "inline_asm.c"
2 .section .rodata
3 .align 4
4 .LC0:
5 .string "placeholders : the result is %d\n"
6 .text
7 .globl main
8 .type main, @function
9 main:
10 pushl %ebp
11 movl %esp, %ebp
12 andl $-16, %esp
13 subl $32, %esp
14 movl $10, 28(%esp)
15 movl $20, 24(%esp)
16 movl 28(%esp), %eax
17 movl 24(%esp), %edx
18 #APP
19 # 26 "inline_asm.c" 1
20 imull %eax, %edx
21 movl %edx, %eax
22 # 0 "" 2
23 #NO_APP
24 movl %eax, 20(%esp)
25 movl $.LC0, %eax
26 movl 20(%esp), %edx
27 movl %edx, 4(%esp)
28 movl %eax, (%esp)
29 call printf
30 movl $0, %eax
31 leave
32 ret
33 .size main, .-main
34 .ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
35 .section .note.GNU-stack,"",@progbits



ref:
professional assembly language p372 - 374
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s6

0 意見: