【发布时间】:2018-12-26 16:24:45
【问题描述】:
我编写了一个简单的汇编代码,我试图在 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 位重新编译代码(用 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 x86-64 object from assembly because of PIC 的重复,因为错误是不同的,并且在该帖子中找到的解决方案与我的问题无关。我已经编辑了要指定的错误输出。
【问题讨论】:
-
push readinfo与位置无关。你可以做lea rax, [rel readinfo]push rax。但是忘记这一点。在 64 位 Linux 代码中,第一个参数在寄存器中传递。(不在堆栈上)。您还需要将call printf更改为call printf wrt ..plt -
要打印到你想尝试的
xor eax, eaxlea rdi, [rel readinfo]mov esi, 5call printf wrt ..plt。寄存器 AL 必须设置为向量寄存器使用的数量,在这种情况下为 0。所以我使用 XOR EAX,EAX 为零 RAX。第一个整数类参数在 RDI 中,第二个在 RSI -
可以在此处找到 64 位 ABI,讨论调用约定:github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf。注意,
printf是可变参数函数(不是固定数量的参数),可变参数函数也包含在 ABI 中。 -
您可以在此处找到调用约定的摘要:en.wikipedia.org/wiki/…
标签: linux gcc assembly nasm x86-64