过早重置堆栈指针?令人困惑的汇编代码

Posted

技术标签:

【中文标题】过早重置堆栈指针?令人困惑的汇编代码【英文标题】:Prematurely resetting the stack pointer? Confusing assembly code 【发布时间】:2021-11-08 04:53:32 【问题描述】:

我试图理解一点组装的意义。

pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%edx
movl 12(%ebp),%eax
movl %ebp,%esp
movl (%edx),%edx
addl %edx,(%eax)
movl %edx,%eax
popl %ebp
ret

为什么在函数的其余部分之前将 sp 重置为基指针?为什么 %edx 中的值被移回自身?

【问题讨论】:

【参考方案1】:

一个更短的版本是:

mov 4(%esp), %eax
mov 8(%esp), %edx
mov (%edx), %edx
add  %edx, (%eax)
ret

或者,一个粗略的 C 等价物:

void add(int *from, int *to) 
  *to += *from;

编译器可能会使用 %ebp go 确保可调试的堆栈帧;并且从 %ebp 恢复 %esp 什么都不做——它们是相同的值。

【讨论】:

感谢您的快速回复,是的,预期的功能应该是基本的。我还是不太明白这是在做什么:movl (%edx), %edx %edx 包含一个指针 (from),以便取消引用指针以获取其位置的值。使用 -S 编译“C”版本以查看编译器生成的内容;然后使用 -O4 之类的选项,看看它可以减少到什么。【参考方案2】:

为什么在函数的其余部分之前将 sp 重置为基指针?

在 GNU 汇编器语法中,movl %esp,%ebp 表示将 esp 移动到 ebp。 (GNU asm 语法与 Intel asm 语法的两个或多个 args 的顺序总是相反)。

这会创建堆栈帧:局部变量和参数可以相对于%ebp 引用,如movl 8(%ebp),%edx

popl %ebp恢复原来的%ebp,由pushl %ebp保存。


为什么 %edx 中的值被移回自身?

在 GNU 汇编器语法中,(%edx)%edx 中指针的间接寻址;请注意,它又是源操作数。

【讨论】:

VLA 是 C99 中的新功能。当然,C11 仍然有它们,但我们通常说 C99 VLA。 @PeterCordes,实际上删除了该部分。这个函数中的%esp完全没有变化。 对,当然不是通过 push/pop,所以 movl %ebp,%esp 只是一个错过的优化(因为可能没有启用优化),-fno-omit-frame-pointer 没有必要。

以上是关于过早重置堆栈指针?令人困惑的汇编代码的主要内容,如果未能解决你的问题,请参考以下文章

Reactstrap Form 重置输入值 MERN 堆栈

Android Activity 测试示例具有令人困惑的 OnPause 期望

中断for循环后如何重置指针

在 ACE 编辑器中重置撤消堆栈

任务杀手没有重置堆栈

百度小程序重置了AppSecret,页面就失效了,要在那个里面怎么修改呢?