1

I'm trying to use the printf function in nasm. My program is set up like this:


section .text
global main
extern printf
main:
  endbr64
  push rbp
  
  mov rdi, [array + 1 * 4]
  mov rsi, specifer
  mov rax, 0
  call printf

  pop rbp
  mov rax, 0
  ret
section .data
  array db 1,2,3,4,5,6,7,8,9,1
  arrlen equ $ - array
  specifer db '%d',0xa,0
  speclen equ $ - specifer

I am running these commands to compile:

nasm -f elf64 arrays.asm
gcc arrays.o

But when I do, I get this error:

arrays.asm:6: warning: label alone on a line without a colon might be in error [-w+orphan-labels]
/usr/bin/ld: arrays.o: relocation R_X86_64_32S against `.data' can not be used when making a PIE object; recompile with -fPIE
collect2: error: ld returned 1 exit status

I tried recompiling with -fPIE but I got the literal same exact error. What am I doing wrong?

Here are the versions of the tools I am using:

NASM: 2.14.02
GCC: 9.4.0
ld: 2.34

My goal at this point is just to get it to compile. I have tried using LD instead of GCC, but I just kept getting a segfault.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • "getting a segfault" with `ld`? Presumably you didn't link CRT startup code, so your `main` was actually the ELF entry point, but you tried to `ret` from it. [Nasm segmentation fault on RET in \_start](https://stackoverflow.com/q/19760002). If you single-step your program with GDB, you can see RIP after `ret` pops `argc` into it. – Peter Cordes Aug 30 '22 at 17:16

1 Answers1

4

Update your version of NASM or get rid of the endbr64 instruction to fix the first error. Your version of NASM is too old to support it. As you do not seem to enable control flow enforcement anyway, it's not really important to have that instruction in your code anyway.

/usr/bin/ld: arrays.o: relocation R_X86_64_32S against `.data' can not be used when making a PIE object; recompile with -fPIE

The error message is misleading; you don't have a compilation step in your code. Usually the compiler generates assembly code. If you did not instruct the compiler to obey the PIE (position independent executable) rules but then try to link a PIE binary, the linker gives you this hint. However, when you write in assembly, you are the compiler and you need to obey these rules yourself.

There are two solutions: either link with -no-pie to disable generation of a PIE binary, or fix your code to conform to PIE rules. The second fix is done by not referencing the absolute address of any symbol from code. The offending instruction is mov rsi, specifer which loads the (absolute) address of specifer into rsi. Replace it with lea rsi, [rel specifer] to instead use rip-relative addressing to conform to the rules. You'll also have to add a rel keyword to mov rdi, [array + 1 * 4] to make it use the same rip-relative addressing mode.

You can use the default rel directive to always use such an addressing mode if possible.

Relevant canonical questions/answers:

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
fuz
  • 88,405
  • 25
  • 200
  • 352
  • 2
    The canonical Q&A for the absolute addressing part is [32-bit absolute addresses no longer allowed in x86-64 Linux?](https://stackoverflow.com/q/43367427) . (This isn't a duplicate because of the `endbr` part of the question). [How to load address of function or label into register](https://stackoverflow.com/q/57212012) is a canonical answer for `lea rsi, [rel specifier]`. Also, `mov rdi, [array + 1 * 4]` is a problem without `default rel`. (And would have to be reworked if used with a register offset, but for now it can still use a RIP+rel32 addressing mode.) – Peter Cordes Aug 30 '22 at 17:13