GCC内联汇编(1)Get started
- 作者:柳大·Poechant(钟超)
- 邮箱:zhongchao.ustc#gmail.com(# -> @)
- 博客:Blog.CSDN.net/Poechant
- 日期:July 7th, 2012
1. Intel vs. AT&T
其实并不是要说 Intel 和 AT&T PK 的故事,哈哈。因为首先要熟悉 Intel syntax 的汇编指令写法和 AT&T syntax 汇编指令的写法,所以看下表:
+------------------------------+------------------------------------+ | Intel Code | AT&T Code | +------------------------------+------------------------------------+ | mov eax,1 | movl $1,%eax | | mov ebx,0ffh | movl $0xff,%ebx | | int 80h | int $0x80 | | mov ebx, eax | movl %eax, %ebx | | mov eax,[ecx] | movl (%ecx),%eax | | mov eax,[ebx+3] | movl 3(%ebx),%eax | | mov eax,[ebx+20h] | movl 0x20(%ebx),%eax | | add eax,[ebx+ecx*2h] | addl (%ebx,%ecx,0x2),%eax | | lea eax,[ebx+ecx] | leal (%ebx,%ecx),%eax | | sub eax,[ebx+ecx*4h-20h] | subl -0x20(%ebx,%ecx,0x4),%eax | +------------------------------+------------------------------------+
2. 示例
看一个用内联汇编写的例子,计算两数的和:
#include <stdio.h> int main(void) { int foo = 10, bar = 15; __asm__ __volatile__ ( "addl %%ebx, %%eax" :"=a"(foo) :"a"(foo), "b"(bar) :"%eax" ); printf("foo + bar = %d\n", foo); return 0; }
该程序作如下解释:
__asm__
用于表示这是一个内联汇编代码段;- 如果使用了
__volatile
修饰符,则这段内联汇编代码不会被编译器优化掉,但是如果只是做简单的计算,不会产生任何可能的 side effects,则最好不要加这个修饰符,这样可以使编译器帮助我们优化代码; "=a"(foo)"
表示这段内联汇编代码运行结束后,输出结果放在寄存器%eax
中,然后%eax
中的内容再放到foo
C变量中;"a"(foo)
表示这段内联汇编代码开始运行时,foo
C变量输入到%eax
寄存器中,多个输入值可以用上面示例中的方式表达。- 以冒号开始的那两行,其实都是“约束”,这个是
constraint
的直译,其实你可以理解为边界条件,即输入输出条件。 - 最后一个冒号开始的行,是告诉编译器,哪些寄存器的值会在内联汇编代码的运行过程中被篡改,因此不要使用这些寄存器去保存值。这里就是
%eax
的值会被篡改的意思。
3. 寄存器缩写
+---+--------------------+ | r | Register(s) | +---+--------------------+ | a | %eax, %ax, %al | | b | %ebx, %bx, %bl | | c | %ecx, %cx, %cl | | d | %edx, %dx, %dl | | S | %esi, %si | | D | %edi, %di | +---+--------------------+
Reference
- http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html