问题
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.
来源:https://stackoverflow.com/questions/8367587/whats-the-difference-between-r-386-pc32-and-r-x86-64-pc32-in-linkgnu-ld-reloc