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
相关产品推荐
相关产品推荐

