使用栈内存替代.bss段后汇编函数返回触发Bus Error问题排查
先看看你提供的代码片段:
C代码
#include<stdio.h> extern double func(double d); int main(){ double d_1 = 1.22; double d_2 = func(d_1); printf("%lf\n", d_2); return 0; }
汇编代码(片段)
section .text global func func: enter 0,0 sub r...
结合x86-64平台的调用约定和栈操作规则,出现Bus Error大概率是栈操作出了问题,下面是几个最可能的原因:
违反栈对齐要求
x86-64的System V ABI明确规定,在执行call指令后,栈指针rsp必须保持16字节对齐。当你执行enter 0,0时,会把基址指针rbp压入栈(占8字节),这会让rsp的对齐状态从16字节变成8字节偏移——也就是不符合对齐要求了。如果后续的sub rsp, ...没有把栈重新调整回16字节对齐(比如要存一个double的话,得sub rsp, 16而不是8),后续访问栈内存或者执行其他操作时就会触发内存访问错误,也就是你遇到的Bus Error。栈空间分配不足导致越界
要是你sub rsp时分配的栈空间比实际需要的小,后续往栈里写数据时就会越界,覆盖栈帧里的关键数据(比如返回地址、rbp的旧值)。等函数执行ret指令时,它会去读取被覆盖的返回地址,这个地址几乎肯定是无效的,直接就会引发Bus Error。栈帧没有正确恢复
你用了enter 0,0来创建栈帧,那函数结束时必须正确恢复栈帧才行——要么用leave指令(这是enter的逆操作),要么手动执行mov rsp, rbp; pop rbp。如果没做这一步,rsp的位置就不对,ret指令找不到正确的返回地址,自然会触发Bus Error。返回地址被意外篡改
哪怕你分配的栈空间足够,要是在操作栈时不小心改写了栈上的返回地址(比如偏移计算错误),ret指令执行时就会跳转到一个非法内存地址,这也会直接导致Bus Error。
内容的提问来源于stack exchange,提问作者Rotem Barak

