`var@GOTPCREL(%rip)` 是什么意思?

Cur*_*ner 9 assembly x86-64 dynamic-linking att got

这是什么<some symbol>@GOTPCREL(%rip)意思?

我遇到过这一行mov var@GOTPCREL(%rip), %rax,并对奇怪的语法感到有点困惑。

有人可以推荐我应该阅读以理解这一点的相关文档吗?谢谢!

Pet*_*des 9

foo@GOTPCREL(%rip)是符号 的 GOT 条目foo,使用 RIP 相对寻址模式访问。

GOT 条目由动态链接器填充(支持符号插入),并保存符号的绝对地址foo,因此mov foo@GOTPCREL(%rip), %rax 加载&foo到 RAX 中https://en.wikipedia.org/wiki/Global_Offset_Table。通常,这后面跟着mov (%rax), %eax或类似于实际获取全局变量的值int foo;,例如在共享库中,我们对符号的定义可能不是主可执行文件正在使用的符号。(请参阅 Thiago Macieira 的博客:Sorry state of Dynamic Libraries on Linux from 2012;它早于gcc -fno-plt,也早于PIE 可执行文件,但共享库访问全局变量的情况并没有改善。)

通常,您只会在共享库中foo@GOTPCREL(%rip)使用全局变量地址,而不是可执行文件(甚至不是 PIE 可执行文件)。编译器假设主可执行文件的全局变量不会被符号插入“遮蔽”。(在共享库中,您可以为符号提供“隐藏”ELF 可见性,以便编译器可以直接访问它们,知道它们不会参与符号插入。)

对于int foo,只是mov foo(%rip), %eax加载它或lea foo(%rip), %rdi获取它的地址,而不通过 GOT。


但是对于函数调用,如果您想要一个指向像 之类的库函数的指针sin,您当然可以通过从 加载指针来获取 libm 本身的最终地址sin@GOTPCREL,而不是仅仅使用指向其 PLT 存根的指针mov $sin, %edi(并让链接器重写 sin到 sin@plt(当在您静态链接的任何内容中找不到该符号时,仅在共享库中找到该符号)。GCC 选择使用哪个取决于您的编译方式。(PIE 与传统的位置相关,和/或-fno-plt不。) 函数指针局部变量的意外值

或者像gcc -fno-plt模式一样,调用库函数以call *sin@gotpcrel(%rip)通过其 GOT 条目使用间接调用,基本上内联几乎与 PLT 存根相同的内容,并强制早期绑定而不是惰性绑定(在启动时解析 GOT 条目,而不是在第一次调用时解析)。 )

NASM 等效项是call [rel printf wrt ..got].


请注意,使用从此处到label/symbol 的foo(%rip) 相对偏移量foo,而不是像您可能猜测的那样将其绝对地址添加到该指令的末尾,或者像这样123(%rip)做的那样。但 GOTPCREL 的 PCREL 部分显然是指从此处开始到 GOT 条目的 PC 相对偏移量。


与 @gotpcrel 类似,您可以执行诸如call printf@plt通过 PLT 条目显式调用函数之类的操作。不幸的是,我没有在 GNUas手册中找到 @gotpcrel 的记录。 https://sourceware.org/binutils/docs/as/


归档时间:

查看次数:

3397 次

最近记录:

4 年 前