我希望能够%rbp在内联asm中使用基指针寄存器().这样的玩具示例是这样的:
void Foo(int &x)
{
asm volatile ("pushq %%rbp;" // 'prologue'
"movq %%rsp, %%rbp;" // 'prologue'
"subq $12, %%rsp;" // make room
"movl $5, -12(%%rbp);" // some asm instruction
"movq %%rbp, %%rsp;" // 'epilogue'
"popq %%rbp;" // 'epilogue'
: : : );
x = 5;
}
int main()
{
int x;
Foo(x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我希望,因为我使用通常的序幕/结尾函数调用方法来推送和弹出旧的%rbp,这样就可以了.但是,当我尝试在内x联asm之后访问时,它会出现故障.
GCC生成的汇编代码(略微剥离)是:
_Foo:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
# INLINEASM
pushq %rbp; // prologue
movq %rsp, …Run Code Online (Sandbox Code Playgroud) 考虑以下功能:
extern void test1(void);
extern void test2(void) {
test1();
}
Run Code Online (Sandbox Code Playgroud)
这是gcc -fpic在amd64 Linux上生成的代码:
test2:
jmp test1
Run Code Online (Sandbox Code Playgroud)
当我编译时-fpic,gcc显式调用PLT来启用符号插入:
test2:
jmp test1@PLT
Run Code Online (Sandbox Code Playgroud)
然而,这对于与位置无关的代码并不是严格需要的,如果我不想支持,可能会被遗漏.如有必要,链接器仍然会将跳转目标重写为PLT符号.
如何在不更改源代码且不使编译代码不适合共享库的情况下,使函数调用直接转到其目标而不是通过PLT显式转换?
类Unix系统中的共享对象(*.so)由于符号插入而效率低下:.so内部对全局变量的每次访问都需要GOT查找,而.so内部从一个函数到另一个函数的每次调用都需要一个PLT抬头.因此,我很高兴看到gcc版本5.1添加了选项-fno-semantic-interposition.但是,当我尝试在没有使用PLT的情况下创建一个函数调用另一个函数的.so时,我收到错误消息:
在创建共享对象时,不能使用符号`functionname'重定位R_X86_64_PC32; 用-fPIC重新编译
我期望选项-fno-semantic-interposition可以消除此错误消息,但事实并非如此.-mcmodel = large也无济于事.对函数的引用确实与位置无关,错误消息实际确认了这一点(R_X86_64_PC32表示在64位模式下与PC相关的32位重定位).-fPIC实际上并不意味着与位置无关,正如名称所暗示的那样,它实际上意味着使用GOT和PLT.
我无法使用,__attribute__((visibility ("hidden")))因为被调用的函数和调用者是在单独的文件中编译的(调用者在C++中,称为函数在汇编中).
我试图制作一个汇编列表来查看-fno-semantic-interposition选项的作用.我发现当一个函数在同一个文件中调用另一个函数时,它会引用一个本地别名,但在另一个文件中调用一个函数时它仍然使用PLT.
(g ++版本是5.2.1 Ubuntu,64位模式).
有没有办法让链接器在没有GOT/PLT查找的情况下接受.so内的交叉引用?
在写这个问题之前,我想强调一下,我自己做了几周的研究,阅读了数十篇文章,但这个问题仍然没有解决,而且我得到的解释根本没有意义(也许是因为我是链接世界的新手) )。所以我希望有人能提供简单但非常详细的答案。
我知道 GOT(全局偏移表)可以帮助我们解析动态链接中从另一个引用的全局符号。另外我读到:“每个共享库都有自己的 GOT”
但这是有问题的,如果两个程序使用同一个共享库怎么办?两者对于全局变量都有相同的值,但事实不应该如此。
至于我的主要问题:如果我不想使用惰性绑定,那么为什么我们需要 PLT,为什么不直接使用普通的 GOT 来处理变量呢?