首页 > 解决方案 > 在 64 位模式下编译 NASM 代码时出现重定位错误

问题描述

我编写了一个简单的汇编代码,我试图在 64 位模式下编译。这是代码:

extern printf

section .rodata
readinfo db `%d\n`, 0

section .text
global main
main:
mov rbp, rsp ; for correct debugging

mov rax, 5
push rax
push readinfo
call printf
add rsp, 8

xor rax, rax
mov rsp, rbp
ret

以下是我给 nasm 和 gcc 的说明(正如我在其他帖子中所读到的,gcc 会自动将目标文件与默认的 c 库链接):

nasm -f elf64 -o test.o test.asm -D UNIX
gcc -o test test.o

但是,我收到以下重定位错误:

/usr/bin/x86_64-linux-gnu-ld: test.o: relocation R_X86_64_32S 对 `.rodata' 不能在制作 PIE 对象时使用;使用 -fPIC 重新编译

/usr/bin/x86_64-linux-gnu-ld:最终链接失败:输出中不可表示的部分

collect2:错误:ld 返回 1 个退出状态

当我使用“-no-pic”选项编译以禁用与位置无关的代码时,它编译时没有错误,但执行后我得到一个没有输出的段错误。当我以 32 位重新编译代码(用 32 位替换 64 位寄存器)时,我没有收到任何错误。命令是:

nasm -f elf32 -o test.o test.asm -D UNIX
gcc -o test test.o -m32

我的问题是:为什么我不能在 64 位模式下用 PIC 编译代码?

PS:这不是Can't link a shared library from an x​​86-64 object from an assembly because of PIC的重复,因为错误是不同的,并且在该帖子中找到的解决方案与我的问题无关。我已经编辑了要指定的错误输出。

标签: linuxgccassemblynasmx86-64

解决方案


错误是我使用了错误的调用约定。在架构 x86_64 中,前两个参数分别在 rdi 和 rsi 中传递,而不使用堆栈。另外,我需要在通话中添加“wrt ..plt”。以下代码有效:

extern printf

section .rodata
readinfo db `%d\n`, 0

section .text
global main
main:
mov rbp, rsp ; for correct debugging

mov rsi, 5
mov rdi, readinfo
xor rax, rax
call printf wrt ..plt

xor rax, rax
mov rsp, rbp
ret

nasm 和 gcc 的命令没有改变。


推荐阅读