制作共享对象时不能使用针对 .data 的重定位 R_X86_64_32S(64 位 NASM + gcc)

Eth*_*gue 3 c linux assembly libc nasm

我正在尝试使用 NASM 和 GCC 制作一个程序:

global main
extern puts

section .data
  hi db 'hello', 0

section .text
main:
  push hi
  call puts
  ret
Run Code Online (Sandbox Code Playgroud)

我正在构建:

nasm -f elf64 main.asm
gcc main.o -o main
rm main.o
Run Code Online (Sandbox Code Playgroud)

我得到:

/usr/bin/ld: main.o: relocation R_X86_64_32S against `.data' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

从像这样的示例中存在奇怪的堆栈操作来判断,我有一种感觉我做错了一些事情。不过,出于某种原因,我找不到任何实际解释这一点的文档(事实上,我几乎找不到任何使用 NASM 进行 64 位开发的有用文档,这使得我迄今为止所做的一切都成为真正的做起来很痛苦),并且添加类似的东西对我的错误输出没有任何影响。

更新:

我一直在看这个这个

如果我将 main 更改为:

  push rbp
  mov rax,0
  mov rdi, hi
  call [puts wrt ..got]
  pop rbp
  mov rax,0

  ret
Run Code Online (Sandbox Code Playgroud)

它编译得很好,但是在运行而不是实际打印时给了我一个段错误。我也不明白为什么我要从rbp堆栈中推入和拉出 的值,以及为什么raxs 的值在这种情况下很重要。

Jes*_*ter 6

rbp是一个被调用者保存的寄存器,因此您需要保留它。您没有更改它,因此不必在此处push/pop它。但是,您需要保留 16 字节堆栈对齐方式,apush是实现此目的的简单方法。您可以使用任何其他寄存器,甚至sub rsp, 8.

mov rdi, hi应该lea rdi, [rel hi]

函数是通过 PLT 而不是 GOT 调用的,也不通过指针调用。做就是了call puts ..wrt plt

因此,以下内容应该有效:

global main
extern puts

section .data
  hi db 'hello', 0

section .text
main:
  push rbp
  lea rdi, [rel hi]
  call puts wrt ..plt
  pop rbp
  ret
Run Code Online (Sandbox Code Playgroud)