<some symbol>@GOTPCREL(%rip)
是什么意思?
我遇到过这一行
mov var@GOTPCREL(%rip), %rax
并且对奇怪的语法有点困惑。
有人可以推荐我应该阅读以理解这一点的相关文档吗? 谢谢!
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 相对偏移量。
call printf@plt
之类的操作来通过PLT条目显式调用函数。不幸的是,我没有在 GNU
as
手册中找到 @gotpcrel 的记录。https://sourceware.org/binutils/docs/as/。