`var@GOTPCREL(%rip)` 是什么意思?
What does `var@GOTPCREL(%rip)` mean?
<some symbol>@GOTPCREL(%rip)
是什么意思?
我遇到过这一行 mov var@GOTPCREL(%rip), %rax
并且对奇怪的语法感到有点困惑。
有人可以推荐我应该阅读以理解这一点的相关文档吗?
谢谢!
foo@GOTPCREL(%rip)
是符号 foo
的 GOT 条目,使用 RIP 相对寻址模式访问。
GOT表项由动态链接器填充(支持符号插入),保存符号的绝对地址foo
,所以mov foo@GOTPCREL(%rip), %rax
加载&foo
到 RAX。 https://en.wikipedia.org/wiki/Global_Offset_Table. Often this is followed by mov (%rax), %eax
or similar to actually get the value of a global variable like int foo;
, in a shared library where our definition of the symbol may not be the one the main executable is using. (See Thiago Macieira's blog: Sorry state of dynamic libraries on Linux from 2012; it pre-dates gcc -fno-plt
, and also predates PIE executables,但共享库访问全局变量的情况并没有改善。)
通常你只会使用 foo@GOTPCREL(%rip)
作为全局变量地址 , not an executable (not even a PIE executable). Compilers assume that the main executable's global vars won't be "shadowed" by symbol interposition. (In a shared library, you can ,知道它们不会参与符号插入。)
对于int foo
,只需mov foo(%rip), %eax
加载它或lea foo(%rip), %rdi
获取它的地址而不通过GOT。
但是对于函数调用,如果你想要一个指向像sin
这样的库函数的指针,你当然可以通过从sin@GOTPCREL
加载一个指针来获取libm本身的最终地址,而不仅仅是使用 mov $sin, %edi
获取指向其 PLT 存根的指针(并让链接器将 sin 重写为 sin@plt 当在静态链接的任何内容中都找不到该符号时,只有共享库)。 GCC 选择使用哪个取决于您的编译方式。 (PIE vs. 传统位置相关,and/or -fno-plt
或不。)
或者像 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/.
<some symbol>@GOTPCREL(%rip)
是什么意思?
我遇到过这一行 mov var@GOTPCREL(%rip), %rax
并且对奇怪的语法感到有点困惑。
有人可以推荐我应该阅读以理解这一点的相关文档吗? 谢谢!
foo@GOTPCREL(%rip)
是符号 foo
的 GOT 条目,使用 RIP 相对寻址模式访问。
GOT表项由动态链接器填充(支持符号插入),保存符号的绝对地址foo
,所以mov foo@GOTPCREL(%rip), %rax
加载&foo
到 RAX。 https://en.wikipedia.org/wiki/Global_Offset_Table. Often this is followed by mov (%rax), %eax
or similar to actually get the value of a global variable like int foo;
, in a shared library where our definition of the symbol may not be the one the main executable is using. (See Thiago Macieira's blog: Sorry state of dynamic libraries on Linux from 2012; it pre-dates gcc -fno-plt
, and also predates PIE executables,但共享库访问全局变量的情况并没有改善。)
通常你只会使用 foo@GOTPCREL(%rip)
作为全局变量地址
对于int foo
,只需mov foo(%rip), %eax
加载它或lea foo(%rip), %rdi
获取它的地址而不通过GOT。
但是对于函数调用,如果你想要一个指向像sin
这样的库函数的指针,你当然可以通过从sin@GOTPCREL
加载一个指针来获取libm本身的最终地址,而不仅仅是使用 mov $sin, %edi
获取指向其 PLT 存根的指针(并让链接器将 sin 重写为 sin@plt 当在静态链接的任何内容中都找不到该符号时,只有共享库)。 GCC 选择使用哪个取决于您的编译方式。 (PIE vs. 传统位置相关,and/or -fno-plt
或不。)
或者像 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/.