7

This is an issue that didn't used to ever occur. I'm pretty convinced it's probably an issue with my package repos (I recently reinstalled my Arch system and this has only just started happening).

I wrote a small hello world in x86_64:

.data
str:    .asciz  "Test"

.text
.globl main
main:
    sub $8, %rsp
    mov $str, %rdi
    call puts
    add $8, %rsp
    ret

and then I attempt to assembly and link using GCC - like I have done many times in the past - with, simply:

gcc test.s -o test

and then this error is outputted:

/usr/bin/ld: /tmp/ccAKVV4D.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

This error has never occured for me ever. I've tried to fix the issue by googling the same error message but it comes up with things that are so specific whereas I'd consider this a general issue. I've tried reinstalling base-devel and the entire GCC toolchain. I dunno what else I can do (please don't suggest using nasm, that's heresy).

I'd like to think I'm missing something obvious but I've used GCC for my assembly needs for a long time.

oldjohn1994
  • 359
  • 4
  • 12
  • I'm sort of sure this is duplicate, but I'm going to search for it later, so just short summary what's going on. The Debian did some time ago switch to PIC/PIE binaries in 64b mode (just like OS X does for some time already, and now other distros follow), thus the defaults for toolchain were modified, and the `gcc` in your case is trying to link your object as PIC, but it will encounter absolute address in `mov $str, %rdi`. So you either should rewrite your code to be `rip` relative everywhere, or there's probably some way to set up gcc linking to enforce old non-PIC linking of executable. – Ped7g Sep 08 '17 at 20:03
  • Thanks for the insight @Ped7g I'll look into it – oldjohn1994 Sep 08 '17 at 20:06
  • 7
    Your probably using a newer/different version of Arch Linux that has GCC build 64-bit code as relocatable by default. The best way to deal with this is to modify your code to use RIP (instruction pointer relative) addressing. CHange your `mov` to `lea str(%rip), %rdi` and when calling the _C_ library use `call puts@plt` instead of `call puts`. – Michael Petch Sep 08 '17 at 20:10
  • compile with `no-pie` flag. That is `gcc -no-pie test.s -o test`. That must work since it will not produce a shared object but an executable file. I tried it on my local machine & it worked but still do not know why. @oldjohn1994 – Karim Manaouil Sep 08 '17 at 20:14
  • @MichaelPetch Thanks, I just just about to ask how I'd use libc functions in relative code. Cheers for that. – oldjohn1994 Sep 08 '17 at 20:25
  • @Karim Manaouil - interesting, I suppose I'm just on some weird in-between build where everything is just a inbetween-stages. That no-pie worked for me too but I think I'll just write rip-relative from now on. – oldjohn1994 Sep 08 '17 at 20:25
  • The solution i gave you is just the non-PIC linking of executable @Ped7g talked about. So combining what Ped7g said & the option i gave you, we can write an answer. – Karim Manaouil Sep 08 '17 at 20:30
  • If you are going to write new code from scratch, you can write it in PIC way and be more fancy. Just be aware what does PIC mean, and how it works, so you will avoid some absolute addressing stuff by accident or weird code.. can't right now think of anything obvious breaking PIC rules, but I doubt it's as simple as just to use `%rip` everywhere. Writing old absolute code is probably tiny bit easier, certainly I wouldn't want to port any longer legacy source, then no-pie sounds like better way. But for new code, try the PIC way... (I would prefer somebody to search for dupe instead of new A) – Ped7g Sep 08 '17 at 20:33
  • @Ped7g : this one is related (although for a different assembler). https://stackoverflow.com/questions/41845065/x86-64-bits-assembly-linux-hello-world-linking-issue – Michael Petch Sep 08 '17 at 20:39

1 Answers1

14

The way to get around this error is to generate a no-pie (Non Position Independent executable) executable :

gcc -no-pie test.s -o test

The reason for this behaviour is as explained by @Ped7g :

Debian switched to PIC/PIE binaries in 64-bits mode & GCC in your case is trying to link your object as PIC, but it will encounter absolute address in mov $str, %rdi.

Karim Manaouil
  • 1,177
  • 10
  • 24
  • 2
    He's using Arch in this case but same applies to Debian. the address of the string isn't the only issue. The calls to the _C_ library have to be modified as well. – Michael Petch Sep 08 '17 at 20:35
  • 1
    @MichaelPetch: `-no-pie` fixes everything, and transforms `call puts` into `call puts@plt` for you. You only need to modify the `call` instructions if you want it to work in a PIE. Specifically, `call *puts@GOTPCREL(%rip)` if building with `gcc -fno-plt` (non-lazy dynamic linking to avoid a writeable + executable PLT, and avoid extra indirection), or `call puts@PLT` for the default way. (Or `call puts@plt` works, too. The compiler emits upper-case PLT when compiling C.) – Peter Cordes Sep 08 '17 at 21:28
  • Related: [32-bit absolute addresses no longer allowed in x86-64 Linux?](https://stackoverflow.com/questions/43367427/32-bit-absolute-addresses-no-longer-allowed-in-x86-64-linux) has the same answer. BTW, `movabs $str, %rdi` *would* work in a PIE executable; text relocations are allowed, just not *32-bit* sign or zero-extended relocations. But don't do that, use a RIP-relative LEA for PIC, or `mov $str, %edi` for position-dependent. – Peter Cordes Mar 19 '18 at 02:34