0

I have this simple piece of code which should print hi, and it works fine.

hi.s

    section .text

hi:
    db "hi", 0

    global sayHi
    align 16
sayHi:
    lea rax, [rel hi]
    ret

start.c

extern int puts();
extern const char *sayHi();

void start() {
    puts(sayHi());
}

However, when I change lea rax, [rel hi] to lea rax, [hi], I get an error message from ld, relocation truncated to fit: IMAGE_REL_AMD64_ADDR32.

I checked at what address the program is being loaded, and the debugger prints this. This is when using [rel hi]. I'm not sure whether the address is physical or virtual, but it's sure it goes over 32 bits, so obviously any static data won't fit in a 32-bit absolute displacement.

Entry point: 0x140001000
0x0000000140001000 - 0x0000000140001060 is .text
0x0000000140002000 - 0x0000000140002030 is .rdata

I wrote this C code to see how the compiler loads static data.

volatile char a[10];

void f(int i) {
    a[i];
}

gcc for Windows emits this.

f:
    lea rax, a[rip]
    movsx   rcx, ecx
    movzx   eax, BYTE PTR [rax+rcx]
    ret

I also checked MSVC from godbolt.

f:
        movsxd  rax, ecx
        lea     rcx, OFFSET FLAT:a
        movzx   eax, BYTE PTR [rax+rcx]
        ret     0

Apart from MSVC not using relative addressing where it obviously should, both compilers think static data can always be loaded over 32-bit addresses, so it's not possible to put it in a 32-bit absolute displacement.

In Linux, this was not the case because the linker had no problem handling hand-written assembly code using 32-bit displacement, and also the compilers chose to do that instead of an additional lea. The same code compiled by a Linux gcc is this.

f:
        movsx   rdi, edi
        movzx   eax, BYTE PTR a[rdi]
        ret
xiver77
  • 1,299
  • 1
  • 1
  • 11
  • 1
    For the Linux part (using `[disp32 + reg]` when targeting non-PIE / non-PIC code), see [32-bit absolute addresses no longer allowed in x86-64 Linux?](https://stackoverflow.com/q/43367427), and also [Mach-O 64-bit format does not support 32-bit absolute addresses. NASM Accessing Array](https://stackoverflow.com/q/47300844) re: why you need a separate LEA if static addresses don't fit in 32-bit. (e.g. Windows large address aware = yes). All addresses are virtual, of course. – Peter Cordes Feb 10 '22 at 04:01

0 Answers0