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

NASM 64位汇编调用printf出现R_X86_64_32S错误及段错误求助

x86_64 Ubuntu下NASM汇编调用printf问题修复方案

现有代码存在的核心问题

  • 传参顺序不符合x86_64 System V调用约定:64位Linux下C函数前6个参数依次通过rdi、rsi、rdx、rcx、r8、r9传递,printf的第一个参数是格式字符串地址,第二个才是要打印的数值,你直接把计算得到的和放到rdi作为第一个参数,printf会把这个数值当成内存地址去访问,直接触发段错误。
  • 静态字符串寻址不符合PIE要求:PIE(位置无关可执行文件)要求代码引用静态数据时使用RIP相对寻址,直接写message会生成32位重定位,链接时就会报你遇到的R_X86_64_32S错误。
  • 可变参数函数调用未设置rax值:printf是可变参数函数,调用前需要将rax设置为传递的浮点参数个数,本次调用没有浮点参数,所以rax要设为0。
  • 字符串位置不规范:message定义在.text代码段,虽然只读属性不影响运行,但规范上应该放在.rodata只读数据段。
  • 无用栈调整破坏栈平衡:修改后的代码没有压栈操作,末尾的add rsp,8完全多余,会破坏栈结构。
  • 被调用者保存寄存器未恢复:你使用了rbx寄存器,x86_64调用约定要求rbx属于被调用者需要保存恢复的寄存器,直接修改会导致上层调用者执行异常。
  • 栈对齐不符合要求:调用C函数前,栈必须满足16字节对齐,call指令会压入8字节返回地址,进入函数后需要额外调整栈保证对齐。

修复后的完整代码

section .rodata
message db "Sum = %08X", 10, 0

section .text
    global main
    extern printf

main:
    ; 压入rbp占8字节,完成16字节栈对齐
    push rbp
    ; 改用调用者保存寄存器rcx存储临时值,避免额外的寄存器保存恢复逻辑
    mov rax, 5
    mov rcx, 55
    add rax, rcx

    ; 第一个参数传入格式字符串地址,用RIP相对寻址适配PIE规则
    lea rdi, [rel message]
    ; 第二个参数传入要打印的求和结果
    mov rsi, rax
    ; 无浮点参数,可变参数标记rax置0
    xor rax, rax
    call printf WRT ..plt

    ; 恢复栈,设置程序返回值为0
    pop rbp
    xor rax, rax
    ret

编译运行命令

# 汇编生成64位目标文件
nasm -f elf64 new1.asm -o new1.o
# 链接生成PIE可执行文件
gcc -fpie -m64 -o new1 new1.o
# 运行程序
./new1

运行后将正常输出:Sum = 0000003C


内容的提问来源于stack exchange,提问作者Hello-World

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 07:57:03