提前重置栈指针?令人困惑的汇编代码问题咨询
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
这是一段32位x86平台AT&T语法的汇编代码,遵循cdecl调用约定,对应的C逻辑等价于:
int function(int *src, int *dst) { int val = *src; *dst += val; return val; }
下面针对两个问题逐一解答:
问题1:为什么函数还未执行完就提前将%esp重置为%ebp的值?
- 这段函数建立栈帧后,没有执行
sub $xxx, %esp这类在栈上分配局部变量空间的操作,说明整个函数运行过程中不需要使用栈空间存储临时数据。 - 在执行
movl %ebp,%esp之前,函数已经把两个入参都读取到了%edx和%eax寄存器里,后续所有操作都是基于寄存器和寄存器指向的内存地址完成,不再需要访问栈上的数据。 - 此时提前重置栈指针不会对后续执行逻辑产生任何影响,属于编译器生成代码时的正常优化写法,和最后执行
popl %ebp前再重置栈指针的效果完全一致。
问题2:为什么会出现movl (%edx),%edx这类看似把%edx的值移回自身的操作?
这是对AT&T汇编寻址语法的误解:
- AT&T语法中,寄存器外加括号代表间接寻址,也就是把寄存器里的值当做内存地址,取这个地址里存储的数据。
- 这条指令的实际含义是:把%edx寄存器中存储的地址指向的32位整数,加载到%edx寄存器里,等价于C语言中的
edx = *edx,完全不是把寄存器的值赋值给自身的无效操作。
内容的提问来源于stack exchange,提问作者Dank_Hill
相关产品推荐
相关产品推荐

