函数尾声中的LEA/POP指令作用是什么?基于《Hacking: The Art of Exploitation》汇编示例
结论
你的猜想完全正确,这段地址80491b8之后的代码是main函数的尾声部分,核心作用就是设置返回值、恢复调用前的寄存器和栈状态,最终返回上层调用者。
80491b8后代码逐行解析
80491b8: b8 00 00 00 00 mov eax,0x0
x86 32位C语言调用约定规定,整型返回值默认存放在EAX寄存器中。C标准明确要求如果main函数没有写显式的return语句,末尾会隐式返回0,这行就是实现这个规则。80491bd: 8d 65 f8 lea esp,[ebp-0x8]
对应函数序言里的压栈操作:你在序言中先后push ebx、push ecx,因此当前栈帧布局为ebp指向旧ebp值,ebp-0x4存旧ebx,ebp-0x8存旧ecx。这里直接把栈指针ESP指向旧ecx的存储位置,为后续批量恢复寄存器做准备,比逐次调整ESP效率更高。80491c0: 59 pop ecx
弹出栈顶的旧ecx值恢复到ecx寄存器,ESP自动+4,此时栈顶指向旧ebx的存储位置。80491c1: 5b pop ebx
弹出栈顶的旧ebx值恢复到ebx寄存器,ESP自动+4,此时栈顶指向旧ebp的存储位置。80491c2: 5d pop ebp
弹出栈顶的旧ebp值恢复到ebp寄存器,还原上层函数的栈基址,ESP自动+4,此时栈顶指向序言最开始保存的返回地址上方位置。80491c3: 8d 61 fc lea esp,[ecx-0x4]
序言最开头做了16字节栈对齐操作and esp,0xfffffff0,修改了原始栈指针,这里用最开始保存在ecx里的原始栈相关值恢复原始ESP,确保返回上层调用者时栈指针完全正确,不会因为对齐操作出现栈偏移错误。80491c6: c3 ret
弹出栈顶的返回地址赋值给EIP寄存器,程序跳回main的调用者(通常是libc的__libc_start_main函数)继续执行。
补充说明(对应你的TODO)
你标注的80491ab: 83 c4 10 add esp,0x10逻辑很明确:调用puts前你执行了sub esp,0xc + push eax,总共让ESP减了16字节(0xc+0x4=0x10),cdecl调用约定要求调用者负责清理参数栈,所以调用完加16字节把栈恢复到调用前状态。
内容的提问来源于stack exchange,提问作者Duderus Smith
相关产品推荐
相关产品推荐

