过早重置堆栈指针?令人困惑的汇编代码
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
没有必要。以上是关于过早重置堆栈指针?令人困惑的汇编代码的主要内容,如果未能解决你的问题,请参考以下文章