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

Linux 64位环境下NASM编写printf程序出现段错误问题排查

问题分析与解决方案

你的这段NASM汇编代码在64位Linux下运行出现段错误,核心原因是违反了x86-64 System V AMD64调用约定,还有几个关键细节错误,我来逐一拆解:

1. 参数传递方式错误(最核心问题)

在64位Linux的System V ABI规范中,C标准库函数(比如printf)的前6个参数是通过寄存器传递的,而非32位环境里的栈传参:

  • 第一个参数(格式字符串地址)要存入 rdi 寄存器
  • 第二个参数(%d对应的整数)要存入 rsi 寄存器
    你直接把参数push到栈上,printf会去寄存器里找参数,自然读不到正确值,甚至会访问非法内存触发段错误。

2. 栈未满足16字节对齐要求

x86-64架构要求调用函数前,栈指针rsp必须是16字节对齐的。当main被gcc启动代码调用时,call指令已经压入了8字节的返回地址,此时rsp的偏移是8字节(即rsp % 16 == 8),调用printf前必须调整栈到16字节对齐,否则会触发未定义行为。

3. 格式字符串缺少null终止符

C语言的字符串必须以0字节结尾,你的mymsg只定义了'Hello World %d!', 0xa,没有追加0,printf会一直读取内存直到遇到0,这会导致越界访问,也是段错误的潜在诱因。

4. 64位系统调用方式错误

你用的int 80h是32位Linux的系统调用入口,在64位程序中应该使用syscall指令:

  • sys_exit的系统调用号是60(不是32位的1)
  • 退出码要存入rdi寄存器(不是32位的rbx)

修正后的代码

section .text
extern printf
global main

main:
    ; 调整栈到16字节对齐:进入main时rsp是%16=8,sub 8后变为%16=0
    sub rsp, 8

    ; 准备printf的参数:符合x86-64调用约定
    mov rsi, 10          ; 第二个参数:%d对应的值
    lea rdi, [mymsg]     ; 第一个参数:格式字符串地址
    call printf

    ; 恢复栈
    add rsp, 8

    ; 64位系统调用:sys_exit(0)
    mov rax, 60
    mov rdi, 0
    syscall

section .data
mymsg db 'Hello World %d!', 0xa, 0  ; 加上0作为字符串终止符

编译运行验证

用你原来的编译命令即可正常运行:

nasm -f elf64 printf.asm
gcc printf.o -o printf
./printf

运行后会输出:Hello World 10!


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:28:56