为何程序.fini段会出现sub $0x8,%rsp与add $0x8,%rsp指令?
.fini段中
sub $0x8,%rsp与add $0x8,%rsp操作的意义解析 问题背景
我反汇编的所有非库程序末尾都包含如下.fini段代码:
Disassembly of section .fini: 0000000000002f58 <.fini>: 2f58: f3 0f 1e fa endbr64 2f5c: 48 83 ec 08 sub $0x8,%rsp 2f60: 48 83 c4 08 add $0x8,%rsp 2f64: c3 ret
作为底层技术新手,我无法理解对%rsp先减0x8再加0x8的意义。我原以为这是类似Rust中saturating_sub的饱和减法,但实际并非如此,特此请教。
解答
这两个操作和饱和减法完全无关,核心是满足x86-64架构的栈对齐要求:
x86-64的System V ABI(类Unix系统通用的函数调用规范)明确要求:在执行函数调用(call指令)后,栈指针%rsp必须保持16字节对齐的状态。而ret指令执行时会从栈上弹出8字节的返回地址,相当于隐含执行了一次add $8,%rsp。
具体到这段.fini代码的执行逻辑:
- 当程序通过
call指令进入.fini段时,%rsp指向的是压入栈的返回地址,此时%rsp是8字节偏移的状态——也就是未满足16字节对齐。 sub $0x8,%rsp:将栈指针减8,把%rsp调整到16字节对齐的位置,确保后续代码(哪怕这段里没有显式函数调用)完全符合ABI规范,避免出现对齐错误导致的程序崩溃。add $0x8,%rsp:将栈指针加回8,恢复到进入.fini时的状态,这样执行ret指令弹出返回地址后,%rsp能回到正确的位置,不破坏程序整体的栈结构。
简单来说,这是编译器生成的通用代码模板,目的是保证栈始终符合架构的对齐规则,哪怕当前函数没有实际的栈操作,也要维持规范要求的栈状态。
内容的提问来源于stack exchange,提问作者TadoTheMiner
相关产品推荐
相关产品推荐

