What's the difference between R_386_PC32 and R_X86_64_PC32 in link(GNU ld) relocation process

StackOverflow https://stackoverflow.com/questions/8367587

  •  27-10-2019
  •  | 
  •  

Question

When reading the book Computer System: A Programmer's Perspective Section 7.7.1 Relocation Entries: the brief content of this section is how a linker relocate reference in a different object file.

When compile and objdump the example source code:

void swap();
int buf[2] = {1, 2};
int main()
{
  swap();
  return 0;
}

Then gcc -Wall -c -o main.o main.c, and objdump -S -r main.o > main.asm; and will see the relocation entry for swap:

6: e8 fc ff ff ff    call 7 <main+0x7> swap();
                     7: R_386_PC32 swap relocation entry

So when ld link the main.o and swap.o, the ld will use the relocation entry r of swap(offset=7, type=R_386_PC32) to determine the link address:

refaddr = ADDR(section .text) + r.offset
*refptr = (unsigned)(ADDR(r.symbol + *refptr - refptr)

And the operand of call instruction (fc ff ff ff) -4 is perfectly suiting for 386 instruction set.

But when I repeat this in a X86_64 Linux, I found the code for the call is:

9: e8 00 00 00 00 callq e <main+0xe>
                  a: R_X86_64_PC32 swap relocation entry

Then My question is why the operand of call(e8) in 386 is -4((fc ff ff ff), but the operand in X86_64 main.o is 00 00 00 00? Is it because of the different instruction set(call vs. callq), or just the GNU ld use different algorithm to relocation R_X86_64_PC32?

Hope for you answer, Many thanks.

Was it helpful?

Solution

The value doesn't matter, it will be overwritten during the relocation process. Apparently, for i386 the compiler defaults to pointing to the relocation entry itself, while for x86-64 it points to the next instruction. It's just a dummy value anyway.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top