1

在阅读《计算机系统:程序员的视角》第 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?

希望得到您的答复,非常感谢。

4

1 回答 1

0

该值无关紧要,它会在重定位过程中被覆盖。显然,对于 i386,编译器默认指向重定位条目本身,而对于 x86-64,它指向下一条指令。无论如何,这只是一个虚拟值。

于 2011-12-03T13:50:42.690 回答