【发布时间】:2011-08-20 11:04:52
【问题描述】:
我正在调查共享库的重定位,但遇到了一些奇怪的事情。考虑这段代码:
int myglob;
int ml_util_func(int p)
{
return p + 2;
}
int ml_func2(int a, int b)
{
int c = ml_util_func(a);
return c + b + myglob;
}
我将它编译为与gcc -shared 共享的非PIC 库。我在 x86 上运行的 32 位 Ubuntu 上执行此操作。
生成的.so 有一个重定位条目,用于在ml_func2 中调用ml_util_func。这是objdump -dR -Mintel 在ml_func2 上的输出:
0000050d <ml_func2>:
50d: 55 push ebp
50e: 89 e5 mov ebp,esp
510: 83 ec 14 sub esp,0x14
513: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]
516: 89 04 24 mov DWORD PTR [esp],eax
519: e8 fc ff ff ff call 51a <ml_func2+0xd>
51a: R_386_PC32 ml_util_func
51e: 89 45 fc mov DWORD PTR [ebp-0x4],eax
521: 8b 45 0c mov eax,DWORD PTR [ebp+0xc]
524: 8b 55 fc mov edx,DWORD PTR [ebp-0x4]
527: 01 c2 add edx,eax
529: a1 00 00 00 00 mov eax,ds:0x0
52a: R_386_32 myglob
52e: 8d 04 02 lea eax,[edx+eax*1]
531: c9 leave
532: c3 ret
533: 90 nop
注意call 指令中的R_386_PC32 重定位。
现在,我的问题是为什么需要搬迁? e8 在 x86 上是“调用相对...”,并且由于 ml_util_func 是在同一个对象中定义的,所以链接器肯定可以计算它与调用之间的相对偏移量,而不会将其留给动态加载器吗?
有趣的是,如果ml_util_func 被声明为static,重定位就会消失,链接器会正确计算并插入偏移量。 ml_util_func 也被导出,导致链接器懒惰的原因是什么?
P.S.:我故意使用非 PIC 代码,以了解加载时重定位。
【问题讨论】:
-
为什么要编译
.so而不使用-fPIC?? -
@osgx:因为,正如我的问题在第一句话中所说的那样——我对加载时重定位特别感兴趣。我现在添加了一个 P.S.澄清
-
你能用另一个库(LD_PRELOAD)重载一个库中的全局符号吗?
-
Eli,还有一个
attribute((visibility("type")))type is one of hidden,internal,protected,default可以精细控制任意符号的绑定顺序。
标签: linux assembly linker elf relocation