-->

What's the difference between R_386_PC32 and R

2019-08-04 10:18发布

问题:

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.

回答1:

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.