nasm x86汇编学习printf时代码无输出?排查递归求和示例异常
程序无输出的根因
程序从未执行到调用printf的代码段,全程因为栈帧操作错误、违反x86-64 System V调用约定直接触发段错误退出,因此没有任何打印输出。
具体错误点
- sum函数参数寻址完全错误
进入sum后,先依次压入rbp、rbx,再将当前rsp赋值给rbp作为栈帧基址,此时[rbp]存储的是刚压入的rbx旧值,根本不是main传入的300参数。后续add rsp,24的操作直接跨越了两个压入的寄存器值、函数返回地址,完全破坏了当前栈帧的边界,后续的寄存器恢复、函数返回操作全都会从无效内存位置取值。 - 栈全程不平衡,违反调用约定
main函数里为调用sum压入的300参数,在sum返回后没有做任何栈清理,rsp偏移了8字节。
递归调用sum的流程中,每一层为传参压入的rbx-1值,在sum返回后都没有执行add rsp,8清理栈空间,每递归一层就多占用8字节无效栈空间,少量递归后就会触发栈溢出。
准备调用printf时,rsp根本没有达到System V要求的16字节对齐标准,printf内部如果使用需要内存对齐的SIMD指令处理格式串,会直接触发访问违例崩溃。 - 函数返回流程混乱,跳转地址完全不可控
走到sum的base分支时,没有匹配的栈平衡操作,直接跳转至end块执行pop rbx、pop rbp,此时rsp位置早已偏移,弹出的都是栈上的随机内存值。后续ret指令会把栈上的随机值当作返回地址跳转,根本回不到main里准备调用printf的代码段。
附带的逻辑问题(不影响崩溃,但结果不对)
- 递归base分支返回值设为1,常规从1到n求和的base逻辑应该是n=0时返回0,否则返回
n + sum(n-1),当前的返回值设置会导致最终计算结果永久偏差。
简单正确流程参考:
基于栈传参的sum函数需要保证,压入的寄存器值、参数的操作和弹出操作完全对称,函数返回时的rsp必须和刚被call指令压入返回地址时的位置完全一致;调用任何库函数前,必须将rsp调整为16字节对齐状态,再传入参数。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

