0

Having this:

.text
str:
    .string "string"
    .globl main
main:
    mov $0, %eax
    mov $str, %rdi #cannot use $str
    call printf
    call exit

compiler gives err:

relocation R_X86_64_32S against `.text' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: final link failed: nonrepresentable section on output

I have read somewhere, the mov $str, %rdi translates to movabsq $str, %rdi, since the size of first operand $str, is address and is greater then 32bits and needs to be passed "full" (absolute value). But that would only work on x32 architecture as told me someone here Why does not XORing %eax causes segfault?. So now the only way to use address of that string and pass it to the printf is use lea str(%rip), %rdi. But that is one more instruction added, instead of use immediate. So why cannot I use immediate?

autistic456
  • 183
  • 1
  • 10
  • That is not the case. If you don't use `movabs` explicitly, GAS assumes you want to use a 32-bit sign-extended immediate (`movq`), which would make sense for an address if linking into a non-PIE executable. Also, `lea` is an *alternative* to `movabs $str, %rdi`, not an extra instruction. – Peter Cordes Jun 05 '20 at 10:49
  • If you had an *assemble-time* constant like `0x123456789abc`, then the size of the number would be visible to the *assembler* (not just at link time), and it would pick `movabs` to be able to encode the immediate operand. **Addresses are link-time constants, not assemble-time.** – Peter Cordes Jun 05 '20 at 10:53
  • Then why GAS *assume* 32-bit length of first operand, when address it obviously 64 (on x64 machine). When I use `mov $str, %rdi`, then the left part 32bits are zeroed? – autistic456 Jun 05 '20 at 10:53
  • @PeterCordes despite being address link-time constant, there could be a exception on immediate addresses, since it is clear/obvious the address will always be 64 bit length because of the architecture – autistic456 Jun 05 '20 at 10:55
  • Static addresses fit in 32 bits in the traditional default code model on x86-64 GNU/Linux. That's why `gcc -fno-pie` code-gen will put addresses in registers with 5-byte `mov $str, %edi`, implicitly zero-extending to 64-bit. That's also why x86-64 ELF object files have a `32` and `32S` zero/sign-extended relocation type for the linker to fill in absolute addresses as 32-bit values. GCC (compiling C to asm, not assembling hand-written source) will only use RIP-relative with `-fPIE` or `-fPIC`. My answer on the linked duplicate explains this and more. – Peter Cordes Jun 05 '20 at 10:56
  • Maybe this question isn't a duplicate after all. This question is more about why a 32-bit immediate is the default, not just how to do it the normal way. If you want me to repost that explanation from comments as an answer, I can reopen this and do so. – Peter Cordes Jun 05 '20 at 11:02
  • @PeterCordes, yes I would like to know the background of 32-bit immediate as well (as it could gives me more insight) and since you know a lot about x86, I would like to get an answer from you – autistic456 Jun 05 '20 at 11:05
  • I searched again; I think [Difference between movq and movabsq in x86-64](https://stackoverflow.com/q/40315803) is a reasonable duplicate; it goes into some detail about when 32-bit immedates work for addresses. (Which is one reason GAS picks a 32-bit immediate when targeting x86-64 Linux ELF, unless you specify otherwise explicitly.) – Peter Cordes Jun 05 '20 at 11:13
  • 1
    [What does this GCC error "... relocation truncated to fit..." mean?](https://stackoverflow.com/a/47168086) talks about the reasons for code models other than "small" and "small-pic", which would justify using 64-bit absolute addresses sometimes. e.g. for the "medium" model, only for large arrays; everything else can use normal rel32 or absolute 32-bit addressing. I also added some more links to the list of duplicates; I think understanding those is your best bet for this to make sense; it won't make sense on its own if you keep thinking that addresses are always 64-bit. – Peter Cordes Jun 05 '20 at 11:16
  • @PeterCordes from here `https://stackoverflow.com/questions/54745872/how-do-rip-relative-variable-references-like-rip-a-in-x86-64-gas-intel-sy`, I do not undestand the conept `a(%rip) means to calculate a rel32` -> **using a disp32 addressing mode**. Could you give and example in gas syntax (not there)? And what mean disp32? "Displacement by 32 bits?" What does it mean (did get it from that link). In `mov str(%rip),%rdi`, if `%rip` content is `0xffff`, and str absolute address is `0x1234`, then the displacement is `0xffff-0x1234`? – autistic456 Jun 05 '20 at 11:29
  • 1
    As we already discussed that just means a 32 bit signed offset added to `%rip`. The displacement is reversed ... it's `symbol - rip` so adding `rip` back gives you the symbol's address. As also said, `rip` already points past the instruction so `rip = address_of_insn + length_of_insn`. – Jester Jun 05 '20 at 11:32
  • [Referencing the contents of a memory location. (x86 addressing modes)](https://stackoverflow.com/a/34058400) explains some about x86-64 addressing modes, and how they can either be a subset of `[base + idx*scale * displacement]` (where displacement is 1 or 4 bytes), or RIP-relative (PC + rel32). Intel's manuals explain in detail what addressing methods are possible. – Peter Cordes Jun 05 '20 at 11:32

0 Answers0