作为一项任务,我必须阅读汇编代码并编写其高级C程序。这种情况下的结构是switch
语句,因此对于每种情况,汇编代码都转换为C代码中的大小写。以下只是其中一个案例。如果你能帮助我解释这一点,它应该让我更好地理解其他案例。
p1 is in %ebp+8
p2 is in %ebp+12
action is in %ebp+16
result is in %edx
...
.L13:
movl 8(%ebp), %eax # get p1
movl (%eax), %edx # result = *p1?
movl 12(%ebp), %ecx # get p2
movl (%ecx), %eax # p1 = *p2
movl 8(%ebp), %ecx # p2 = p1
movl %eax, (%ecx) # *p1 = *p2?
jmp .L19 #jump to default
...
.L19
movl %edx, %eax # set return value
当然,我添加了评论以试图理解它,除了它让我更加困惑。这意味着交换吗?可能不是;格式会有所不同。第2和第6行真的发生了什么?为什么%edx只是如此早更改一次,如果它是返回值?请回答一些指导原则来解释此代码。
答案 0 :(得分:4)
以上片段是(IMO已破坏)AT& T语法中的x86_32程序集。
AT& T语法为每个操作数附加一个大小后缀。
movl
表示32位操作数。 (l长)b
movw
表示16位操作数(w表示单词)
movb
表示8位操作数(b表示字节)
操作数按顺序颠倒,因此目标位于右侧,源位于左侧 这与几乎所有其他编程语言相反。
寄存器名称以%
为前缀,以区别于变量名称。
如果寄存器被括号()
包围,则意味着使用寄存器指向的存储器地址,而不是寄存器本身内的值。
这是有道理的,因为EBP被用作指向堆栈帧的指针
Stackframes用于访问函数中的参数和局部变量。
而不是写:mov eax, dword ptr [ebp+8]
(英特尔语法)
AT& T语法将其列为:movl 8(%ebp), %eax
(gas syntax)
这意味着:将(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寄存器中。 (或EAX:EDX,如果它是INT64)
在散文中:p1和p2是指向数据的指针,在这个数据指针指针中
此代码看起来像操纵链表
p2->next
设置为p1->next
除此之外,该片段看起来不完整,因为p2->next
中的任何内容都没有开始,因此可能会有更多代码没有显示。
除了令人困惑的AT&amp; 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&amp; T和Intel语法之间差异的更多信息,请访问:http://www.ibm.com/developerworks/linux/library/l-gas-nasm/index.html