You need to enable JavaScript to run this app. 为什么自制编译器生成的x86_64汇编代码会触发段错误?
优惠活动
大模型
产品
解决方案
定价
更多

为什么自制编译器生成的x86_64汇编代码会触发段错误?

问题分析
  • 核心错误是违反了x86_64 macOS平台的函数调用栈对齐规则
    macOS遵循System V x86_64调用约定,要求调用任意函数前,栈指针%rsp必须16字节对齐。进入_main函数时,callq _main自动压入8字节返回地址,随后执行pushq %rbp又压入8字节,此时%rsp已经16字节对齐,后续subq $16, %rsp操作后仍保持对齐。但你额外执行了pushq %rdi,这一步会让%rsp再减8,直接破坏了16字节对齐要求,此时调用_strcmp触发系统层面的对齐检查,直接抛出段错误。
  • 次要遗漏点:变参函数printf调用前需要设置%rax值
    System V约定中,调用可变参数函数前,%rax需要存放传入的向量寄存器数量,你这段代码没有用到向量寄存器,需要在调用_printf前执行xorl %eax, %eax将%rax置0,否则也可能引发不可预知的运行错误。
修复方案

方案1:保留压栈逻辑,补充对齐操作

如果要保留你原本压栈保存格式串地址的逻辑,只需要在压栈后补充栈对齐操作即可:

leaq    S0(%rip), %rax
    movq    %rax, %rdi
    pushq   %rdi
    subq    $8, %rsp   # 补充8字节偏移,让%rsp恢复16字节对齐
    leaq    S1(%rip), %rax
    movq    %rax, %rdi
    leaq    S2(%rip), %rax
    movq    %rax, %rsi
    callq   _strcmp
    addq    $8, %rsp   # 调用结束后回补8字节
    popq    %rdi
    movq    %rax, %rsi
    xorl    %eax, %eax # 补充变参函数要求的rax置0
    callq   _printf

方案2:移除不必要的压栈操作,调用printf前重新加载格式串

这也是你测试过可用的方案,相比方案1指令更少、执行效率更高,也不会引入栈对齐风险:

leaq    S1(%rip), %rdi
    leaq    S2(%rip), %rsi
    callq   _strcmp
    leaq    S0(%rip), %rdi
    movq    %rax, %rsi
    xorl    %eax, %eax
    callq   _printf

内容的提问来源于stack exchange,提问作者Dovahkiin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 23:15:02