我正在研究共享库的迁移,并遇到一些奇怪的问题。考虑下面这段代码:
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
也被导出变得懒惰呢?附言:我故意使用非PIC代码,以了解加载时重定位。
attribute((visibility("type")))
,其中type是hidden、internal、protected、default之一,可以精细控制任何符号的绑定顺序。 - osgx