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
L29 注解寫著 %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

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。