微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决`var@GOTPCREL(%rip)` 是什么意思?

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

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

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

解决方法

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

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

通常,您只会将 foo@GOTPCREL(%rip) 用于全局变量地址 in a shared library,而不是可执行文件(甚至不是 PIE 可执行文件)。编译器假定主可执行文件的全局变量不会被符号插入“遮蔽”。 (在共享库中,您可以give symbols "hidden" ELF visibility so compilers will access them directly,知道它们不会参与符号插入。)

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


但是对于函数调用,如果你想要一个指向像sin这样的库函数的指针,你当然可以通过从sin@GOTPCREL加载一个指针来获得libm本身的最终地址,而不是仅仅取一个使用 mov $sin,%edi 指向其 PLT 存根的指针(并在您静态链接的任何内容中找不到符号时,让链接器将 sin 重写为 sin@plt,只有共享库)。 GCC 选择使用哪个取决于您的编译方式。 (PIE 与传统的位置相关,和/或 -fno-plt 与否。)Unexpected value of a function pointer local variable

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

NASM 等价物是 call [rel printf wrt ..got]


请注意 foo(%rip) uses the relative offset from here to the foo label/symbol,不要像您可能猜到的那样将其绝对地址添加到该指令的末尾,或者像 123(%rip) 那样。但该 GOTPCREL 的 PCREL 部分显然是指从这里到 GOT 条目的 PC 相对偏移量。


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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。