控制转移场景下栈字节分配的逻辑疑问
x86-64栈指针%rsp与call指令的字节分配逻辑
首先要明确两个核心事实:
- x86-64是64位架构,所有内存地址都是8字节宽度,不存在3字节地址的说法——你可能混淆了指令的机器码长度和地址本身的长度。
- x86-64的系统ABI(应用二进制接口)强制要求栈必须保持16字节对齐,这是硬件和编译器共同遵守的规则,不是看单个数据需要多少空间。
拆解你的疑问:
call指令的硬件行为
call指令执行时,会自动完成两个操作:- 把当前指令的下一条指令地址(64位,8字节)压入栈
- 跳转到目标函数入口
压栈过程是硬件自动处理的:先将%rsp的值减8(因为要存8字节的地址),再把返回地址写入新的%rsp指向的内存位置。不存在“手动分配2字节”的情况,你看到的注释地址差是十六进制计算:0x7fffffffe820 - 0x7fffffffe818 = 8(十六进制0x8),这就是8字节的空间,不是2字节。
关于栈对齐的要求
当main函数调用top时,call指令压入8字节返回地址后,%rsp的地址是0x7fffffffe818(是8的倍数,但未达到16字节对齐)。top函数开头的sub $0x5,%rdi是操作rdi寄存器,和栈无关;当top调用leaf时,call指令再次压入8字节返回地址,%rsp变成0x7fffffffe810——这个地址是16的倍数(0x810=16×2064),符合ABI的栈对齐要求。关于注释里的地址显示
注释里写的返回地址0x4004e是简写,实际是64位地址0x00000000004004e,高位的零被省略了,本质还是8字节的地址,所以必须用8字节栈空间存储。%rsp的指向规则
%rsp始终指向栈顶的下一个可写入位置(栈向低地址方向增长),任何压栈操作(包括call)都会自动调整%rsp,且必须遵循8字节的地址粒度——x86-64不支持非8字节对齐的栈操作,硬件本身就不允许,这是架构设计的要求。
内容的提问来源于stack exchange,提问作者GabrielBRAA
相关产品推荐
相关产品推荐

