You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

x64汇编调用printf触发段错误,请求排查原因

问题分析与修正

你的代码出现段错误的核心原因是误用了32位x86的cdecl调用约定,而x86-64 Linux平台遵循的是System V AMD64调用约定,两者在参数传递、栈要求上差异很大。具体问题和修正方案如下:

错误点拆解

  • 参数传递方式错误:System V AMD64约定中,前6个整数/指针参数通过寄存器传递,而非压栈。printf的第一个参数(格式字符串)需放入rdi,第二个参数(%d对应的整数)需放入rsi。
  • 栈对齐违规:调用函数前,栈指针rsp必须是16字节的整数倍。进入main时,由于call指令已压入8字节的返回地址,rsp处于16n-8的状态,未满足对齐要求,直接调用printf会触发异常。
  • 非规范寄存器使用:rbx是System V AMD64中的非易失性寄存器,调用外部函数前需保存,调用后恢复(虽然这不是段错误的直接原因,但属于编写规范)。

修正后的代码

版本1(规范保存非易失性寄存器)

section .data
    fmt: db "%d", 10, 0
section .text
    extern printf
    global main
main:
    push rbx        ; 保存非易失性寄存器rbx
    mov rbx, 25
    mov rdi, fmt    ; 第一个参数:格式字符串传入rdi
    mov rsi, rbx    ; 第二个参数:要打印的数值传入rsi
    call printf     ; 此时rsp因push rbx后变为16字节对齐,符合要求
    pop rbx         ; 恢复rbx寄存器
    mov rax, 0      ; 退出码0
    ret

版本2(简化版,不使用非易失性寄存器)

section .data
    fmt: db "%d", 10, 0
section .text
    extern printf
    global main
main:
    sub rsp, 8      ; 调整栈指针至16字节对齐(进入main时rsp=16n-8,减8后为16n)
    mov rsi, 25     ; 第二个参数传入rsi
    mov rdi, fmt    ; 第一个参数传入rdi
    call printf
    add rsp, 8      ; 恢复栈指针
    mov rax, 0
    ret

编译验证

仍使用你原有的编译链接命令即可正常运行:

nasm -f elf64 main.s && gcc -o main main.o

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 08:05:34