2

I'm trying to make a program with NASM and GCC:

global main
extern puts

section .data
  hi db 'hello', 0

section .text
main:
  push hi
  call puts
  ret

I am building with:

nasm -f elf64 main.asm
gcc main.o -o main
rm main.o

I get:

/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

I have a feeling I'm doing a few things wrong, judging by the presence of weird stack operations in examples like this and this. I can't find any documentation that actually explains this, for some reason, though (In fact, I can hardly find any useful documentation for 64-bit development with NASM in general, which has made everything I've made so far a real pain in the ass to make), and adding in things like that don't have any effect on my error output.

Update:

I've been looking at this and this.

If I change my main to:

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

  ret

It compiles fine, but then gives me a segfault when running instead of actually printing. I also don't understand why I'm pushing and pulling the value of rbp from the stack, and why rax's value matters in this case.

Ethan McTague
  • 2,236
  • 3
  • 21
  • 53
  • 1
    Also see [Access .data section in Position Independent Code (PIC)](https://stackoverflow.com/q/36223182/608639) and [Writing NetBSD/FreeBSD/OpenBSD and Linux/ELF Shared Libraries](https://www.csee.umbc.edu/~chang/cs313.f04/nasmdoc/html/nasmdoc8.html#section-8.2) in the NASM manual. – jww Jan 10 '18 at 14:42
  • Related: [How to load address of function or label into register](https://stackoverflow.com/q/57212012) / [32-bit absolute addresses no longer allowed in x86-64 Linux?](https://stackoverflow.com/q/43367427) – Peter Cordes Sep 21 '21 at 18:19

1 Answers1

5

rbp is a callee-saved register hence you need to preserve it. You are not changing it so you don't have to push/pop it here. However you need to preserve 16 byte stack alignment, and a push is a simple way to do that. You could have used any other register, or even sub rsp, 8.

mov rdi, hi should be lea rdi, [rel hi].

Functions are called through the PLT not the GOT, and not through a pointer. Just do call puts ..wrt plt.

As such, the following should work:

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
Jester
  • 56,577
  • 4
  • 81
  • 125
  • Excellent, it works! Might I ask where you learned this? I've been struggling to find a good guide for 64-bit NASM with libc. – Ethan McTague Jan 10 '18 at 16:45
  • 1
    `call [puts wrt ..got]` is also correct; it's the NASM equivalent of `gcc -fno-plt` code-gen. [Can't call C standard library function on 64-bit Linux from assembly (yasm) code](https://stackoverflow.com/a/52131094) shows both options, inlining the indirect call through the GOT or just calling the PLT stub. (@EthanMcTague) – Peter Cordes Sep 21 '21 at 18:22