1

I have a very strange behavior of gcc that I cannot understand well, maybe somebody can explain it a bit to me (it must be simple but I failed to find precise documentation about it on the Web).

I try to compile a very simple 'Hello World' program in amd64 assembly with gcc. For that, I try to not rely on the libc nor the gcc libraries. Just to show that I do not need to go through __libc_start_main() at first.

Here is my code (which should be okay):

.data # Data section
msg:
        .ascii "Hello World!\n"
        len = . - msg

.text # Text section
.globl _start

_start:
# Write the string to stdout
        movq    $len, %rdx
        movq    $msg, %rsi
        movq    $1, %rdi
        movq    $1, %rax
        syscall
# and exit
        movq    $0, %rdi
        movq    $60, %rax
        syscall

Then, I try to compile it with gcc:

#> gcc -m64 -Wall -Wextra -m64 -nostdlib -o hello_syscall hello_syscall.s
/usr/bin/ld: /tmp/ccDQWRW2.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

Then, adding -fPIC does not help at all. But, when I compile it with -static it works:

#> gcc -m64 -Wall -Wextra -m64 -nostdlib -static -o hello_syscall hello_syscall.s
#> ./hello_syscall
Hello World!

So, I wonder why this behavior and if I can get rid of the -static option or not (well, I would be happy if I just know why it is needed here!).

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
perror
  • 7,071
  • 16
  • 58
  • 85
  • 1
    If you had used `movabs` instead of `movq`, your PIE would have linked with a 64-bit absolute relocation. But you don't want that, use `-static`. (I usually use `ld` directly when making a static executable, with a wrapper script that runs NASM and then `ld`. But with a .S, yeah it's easier to use `gcc` to assemble + link) – Peter Cordes Jan 10 '18 at 20:10
  • @PeterCordes: Indeed, it explain a lot. But, I did not found the question on a first search. Thanks for pointing it! I am also quite surprised that changing `movq` by `movabs` make it compile without any problem (but, I also understand why now). – perror Jan 11 '18 at 09:13
  • Yeah, finding the duplicate required knowing the answer to this question. Hopefully this question will be a useful signpost for people coming at it from the direction you did. (Upvoted for this reason.) – Peter Cordes Jan 11 '18 at 19:14
  • 1
    I was surprised, too, that Linux/ELF supported 64-bit absolute relocations. I thought PIC code had to actually be PIC, without load-time fixups. But that's not the case after all. In GAS syntax, `movabs` gives you the `mov $imm64, %r64` encoding, while `movq` always means `mov $sign-extended-imm32, %r64` (and thus could only be relocated within the low 32 bits of virtual address space). If you want to write PIC code, use RIP-relative LEA, like `lea msg(%rip), %rsi`. But `mov $msg, %esi` is even better in a position-dependent executable. Static addresses are in the low 2GiB so this works – Peter Cordes Jan 11 '18 at 19:18

0 Answers0