从汇编到 C 代码
Posted
技术标签:
【中文标题】从汇编到 C 代码【英文标题】:Going from Assembly to C code 【发布时间】:2015-12-15 02:33:14 【问题描述】:这是 AT&T 语法
.global bar
.type bar, @function
bar:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
movl 8($ebp), %ebx
movl $1, %eax
cmpl $1, %ebx
jle .L3
leal -1(%ebx), %eax //subtracts 1 from ebx and stores into eax
movl %eax, (%esp) //putting on stack frame
call bar //recursive call
addl %ebx, %eax // adds %ebx and %eax
.L3 //returns %eax
addl $20, %esp
popl %ebx
popl %ebp
ret //end of bar
所以我认为这里发生的基本上是它检查 %ebx 是否
所以我的 C 代码是:
int bar (int x)
if (x<= 1)
return 1;
else
return x + bar(x-1);
递归调用真的把我骗到这里了。我意识到它使用新的 %eax 寄存器(基本上变成 x-1)调用 bar 。那么它只是返回数字的总和吗?
【问题讨论】:
我看不到你在哪里得到x+(x-1)
的递归调用参数。有一个add
after 通话,您似乎与通话before 发生的事情混为一谈。 leal -1(%ebx),%eax
是加载有效地址指令。它记录在 x86 手册中(很多是在线的)。它用于存储带有偏移量的地址,但有时它用于通过一次执行移动和常量添加来保存一条指令。我没有看到 将eax
添加到堆栈 的位置。您必须将其移动到堆栈,这是将其作为arg传递给bar
的必要条件。
@lurker 我意识到我搞砸了它的递归调用,我正在努力追溯它。 leal 命令是从 ebx 中减去 1 并将其存储到 eax 中,尽管正确吗?
是的,没错。
@lurker 我重新查看了它并再次尝试了解决方案。我认为它实际上只是将 x 到 1 的值相加。
【参考方案1】:
我会这样注释:
bar: // bar()
pushl %ebp // function prologue
movl %esp, %ebp //
pushl %ebx //
subl $20, %esp //
movl 8($ebp), %ebx // %ebx = x
movl $1, %eax // %eax = 1
cmpl $1, %ebx // if (x > 1)
jle .L3 //
leal -1(%ebx), %eax // %eax = x - 1
movl %eax, (%esp) // put (x - 1) on stack
call bar // %eax = bar(x - 1)
addl %ebx, %eax // %eax += x
.L3 //
addl $20, %esp // function epilogue
popl %ebx //
popl %ebp //
ret // return %eax
//
所以 C 看起来与您发布的内容相当:
int bar (int x)
if (x > 1)
return bar(x - 1) + x;
return 1;
出于历史兴趣:我使用 clang -m32 -S
编译了您的原始(不正确)C 代码,在手动“优化”以消除存储/加载对之后,我得到了类似于您的汇编代码的东西,但很清楚您那一刻错了。从那以后你就修好了。
【讨论】:
我会将push %ebp / mov %esp, %ebp
上的cmets 简化为// stack frame boilerplate
。 “所谓的堆栈”甚至不完全准确,因为它是在推送之后完成的。此外,“展开”意味着(无论如何对我来说)跟随堆栈帧的链接列表将调用链备份到某个父函数的堆栈帧。我会说“将堆栈指针恢复到我们保存寄存器的位置”之类的。
@PeterCordes:很公平——我现在用“prologue”和“epilogue”替换了那些cmets,我认为这很标准。
是的,我喜欢它。它不是函数逻辑的一部分,只是为该 ABI 实现它的一部分(带有一些保留调用的寄存器和通常的堆栈帧约定)。在跟踪实际逻辑以查看函数的作用时,不需要关注什么。【参考方案2】:
int bar(int x)
if (x<= 1)
return 1;
else
return x+bar(x-1);
按升序将 x 与 1 相加
【讨论】:
以上是关于从汇编到 C 代码的主要内容,如果未能解决你的问题,请参考以下文章