在阅读《计算机系统:程序员的视角》第 7.7.1 节重定位条目这本书时:本节的简要内容是链接器如何在不同的目标文件中重定位引用。
编译和 objdump 示例源代码时:
void swap();
int buf[2] = {1, 2};
int main()
{
swap();
return 0;
}
然后gcc -Wall -c -o main.o main.c,然后objdump -S -r main.o > main.asm;并将看到交换的重定位条目:
6: e8 fc ff ff ff call 7 <main+0x7> swap();
7: R_386_PC32 swap relocation entry
所以当ld链接main.o和swap.o时,ld会使用swap(offset=7, type=R_386_PC32)的重定位入口r来确定链接地址:
refaddr = ADDR(section .text) + r.offset
*refptr = (unsigned)(ADDR(r.symbol + *refptr - refptr)
而调用指令的操作数(fc ff ff ff)-4非常适合386指令集。
但是当我在 X86_64 Linux 中重复此操作时,我发现调用的代码是:
9: e8 00 00 00 00 callq e <main+0xe>
a: R_X86_64_PC32 swap relocation entry
那么我的问题是为什么386中call(e8)的操作数是-4((fc ff ff ff),而X86_64 main.o中的操作数是00 00 00 00?是不是因为指令集不同(call vs .callq),还是只是 GNU ld 使用不同的算法来重定位 R_X86_64_PC32?
希望得到您的答复,非常感谢。