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

问题描述 投票:0回答:1

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

我遇到过这一行

mov var@GOTPCREL(%rip), %rax
并且对奇怪的语法有点困惑。

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

assembly x86-64 dynamic-linking att got
1个回答
9
投票

foo@GOTPCREL(%rip)
是符号 foo
全局偏移表 (GOT)
条目,通过 RIP 相对寻址模式访问。

GOT 项由动态链接器填充(支持符号插入),保存符号

foo
的绝对地址,因此
mov foo@GOTPCREL(%rip), %rax
&foo
加载到RAX
中。通常,后面跟着
mov (%rax), %eax
或类似的内容,以实际获取像
int foo;
这样的全局变量的值,在共享库中,我们对符号的定义可能不是主可执行文件正在使用的符号。 (参见 Thiago Macieira 的博客:2012 年以来 Linux 上动态库的状况,抱歉;它早于
gcc -fno-plt
,也早于 PIE 可执行文件,但共享库访问全局变量的情况并没有改善。)

通常您只会将

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

对于int foo

,只需
mov foo(%rip), %eax
加载它或
lea foo(%rip), %rdi
获取其地址,而无需通过GOT。


但是对于函数调用,如果您想要一个指向像

sin

这样的库函数的指针,您当然可以通过从
sin@GOTPCREL
加载指针来获取libm本身的最终地址,而不是仅仅使用指向其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]


请注意,

foo(%rip)

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


与@gotpcrel类似,您可以执行诸如

call printf@plt

之类的操作来通过PLT条目显式调用函数。不幸的是,我没有在 GNU 
as
 手册中找到 @gotpcrel 的记录。 
https://sourceware.org/binutils/docs/as/

© www.soinside.com 2019 - 2024. All rights reserved.