上面的代码片段是(IMO 损坏的)AT&T 语法中的 x86_32 程序集。
AT&T 语法为每个操作数附加一个大小后缀。
movl
表示 32 位操作数。(l for long)
movw
表示 16 位操作数 (w for word)
movb
表示 8 位操作数 (b for byte)
操作数的顺序颠倒了,所以目标在右边,源在左边。
这与几乎所有其他编程语言相反。
寄存器名称以 a 为前缀,%
以区别于变量名称。如果寄存器被括号括()
起来,则表示使用的是寄存器指向的内存地址,而不是寄存器本身内部的值。
这是有道理的,因为 EBP 被用作指向堆栈帧的指针。
Stackframes 用于访问函数中的参数和局部变量。
而不是写成:mov eax, dword ptr [ebp+8]
(Intel 语法)
AT&T 语法将其列为:movl 8(%ebp), %eax
(gas 语法)
这意味着:将(ebp + 8)指向的内存地址的竞争放入eax。
这是翻译:
.L13: <<-- label used as a jump target.
movl 8(%ebp), %eax <<-- p1, stored at ebp+8 goes into EAX
movl (%eax), %edx <<-- p1 is a pointer, EDX = p1->next
movl 12(%ebp), %ecx <<-- p2, stored at ebp+12 goes in ECX
movl (%ecx), %eax <<-- p2 is (again) a pointer, EAX = p2->next
movl 8(%ebp), %ecx <<-- ECX = p1
movl %eax, (%ecx) <<-- p2->next = p1->next
jmp .L19 <<-- jump to exit
...
.L19
movl %edx, %eax <<-- EAX is always the return value
<<-- return p1->data.
在 x86 上的所有许多调用约定中,函数的返回值都放入 EAX 寄存器。(如果是 INT64,则为 EAX:EDX)
在散文中:p1 和 p2 是指向数据的指针,在这个数据中是指向指针的指针。
这段代码看起来像是在操作一个链表。
p2->next
设置为p1->next
。
除此之外,该片段看起来不完整,因为一p2->next
开始的任何内容都没有处理,因此您可能没有显示更多代码。
除了令人困惑的 AT&T 语法之外,它实际上是非常简单的代码。
在 C 中,代码如下所示:
(void *)p2->next = (void *)p1->next;
请注意,该代码效率非常低,并且没有像样的编译器(或人类)会生成此代码。
以下等价物会更有意义:
mov eax,[ebp+8]
mov ecx,[ebp+12]
mov eax,[eax]
mov [ecx],eax
jmp done
有关 AT&T 和 Intel 语法之间差异的更多信息,请参见此处:http ://www.ibm.com/developerworks/linux/library/l-gas-nasm/index.html