x64架构调用函数时RSP未必需16字节对齐?技术求证
x64架构函数调用的RSP对齐误区解析
测试现象回顾
- 针对callme程序的ROP payload中添加
ret指令(意图对齐栈指针):进入system函数时RSP未按16字节对齐,但代码正常执行; - payload中不添加
ret指令:进入system函数时RSP是16字节对齐,却在do_system函数中因movaps指令触发段错误崩溃。
核心结论:x64调用规范仍要求调用者保证RSP对齐
x64 System V调用规范明确规定:调用者在执行call指令前,必须确保RSP是16字节对齐的。因为call指令会将8字节的返回地址压入栈中,所以被调用函数入口处的RSP会是原RSP-8(即8字节偏移的未对齐状态)。正规实现的函数会在入口处通过sub rsp, 8之类的指令恢复16字节对齐,再执行后续操作。
反常现象的原因拆解
加ret后未对齐却正常运行
ret指令会弹出栈上8字节的返回地址到RIP,相当于RSP增加8。此时执行call system前的RSP处于未对齐状态,进入system时RSP虽未对齐,但system函数内部在使用movaps这类要求对齐的指令前,已经主动调整了栈指针(比如额外执行sub rsp, 16),兼容了入口处的未对齐状态,因此代码能正常运行。不加ret时对齐却崩溃
进入system时RSP是16字节对齐的,但system内部调用do_system时,call do_system会将8字节返回地址压栈,导致do_system入口处的RSP变为对齐RSP-8(即未对齐状态)。而do_system的实现中没有额外处理栈对齐,直接使用movaps访问栈上的未对齐内存,触发了段错误。
总结
x64的调用规范并没有失效,只是不同函数的内部实现对栈对齐的处理方式不同:有些函数会兼容入口处的未对齐状态,有些则严格依赖调用者提前做好对齐。你遇到的反常识现象,本质是不同函数栈对齐处理逻辑差异导致的。
内容的提问来源于stack exchange,提问作者talsim
相关产品推荐
相关产品推荐

