其实并不是要说 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 | +------------------------------+------------------------------------+
看一个用内联汇编写的例子,计算两数的和:
#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
的值会被篡改的意思。+---+--------------------+ | 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 | +---+--------------------+