在64位模式下编译NASM代码时发生重定位错误

时间:2018-07-18 16:52:59

标签: linux gcc assembly nasm x86-64

我编写了一个简单的汇编代码,试图在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:将R_X86_64_32S重定位为   制作PIE对象时不能使用`.rodata'。重新编译   -fPIC

     

/ usr / bin / x86_64-linux-gnu-ld:最终链接失败:无法表示   输出部分

     

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

当我使用'-no-pic'选项进行编译以禁用与位置无关的代码时,它编译时没有错误,但是执行后,我遇到了没有输出的段错误。 当我重新编译32位代码(将64位寄存器替换为32位)时,没有任何错误。这些命令是:

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 x86-64 object from assembly because of PIC的重复项,因为错误有所不同,并且该帖子中找到的解决方案与我的问题无关。我已编辑错误输出以指定。

1 个答案:

答案 0 :(得分:2)

错误是我使用了错误的调用约定。在体系结构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的命令未更改。