我正在调查共享库的重定位,并遇到了一些奇怪的问题。请考虑以下代码:
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_util_func
中的ml_func2
。以下是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
请注意R_386_PC32
指令上的call
重定位。
现在,我的问题是为什么需要重新安置? e8
在x86上是“call relative ...”,并且由于ml_util_func
在同一个对象中定义,因此链接器肯定可以计算它与调用之间的相对偏移量而不会将其保留为动态装载机?
有趣的是,如果ml_util_func
被声明为static
,则重定位将消失,链接器将正确计算并插入偏移量。什么是ml_util_func
也被导出使链接器变得懒惰呢?
P.S。:我故意使用非PIC代码,以了解加载时重定位。
答案 0 :(得分:4)
无法找到原因,但这是binutils对此的评论:
binutils-2.11.90-20010705-src.tar.gz / bfd / elf32-i386.c:679
/* If we are creating a shared library, and this is a reloc
against a global symbol, or a non PC relative reloc
against a local symbol, then we need to copy the reloc
into the shared library. However, if we are linking with
-Bsymbolic, we do not need to copy a reloc against a
global symbol which is defined in an object we are
我认为,这个重定位是为了允许用户重载库中的任何全局符号而创建的。并且,似乎-Bsymbolic
禁用此功能,并且不会从库本身生成符号的重定位。
http://www.rocketaware.com/man/man1/ld.1.htm
<强> -Bsymbolic 强> 此选项会导致输出中的所有符号引用 在此链接编辑会话中解决。唯一剩下的运行时间 搬迁要求是基地相对重新安置,即 关于加载地址的转换。未能解决 任何符号引用都会导致报告错误。
各种-B模式和限制(C ++)的更长描述在这里:
http://developers.sun.com/sunstudio/documentation/ss12/mr/man1/CC.1.html
-B的结合的
Specifies whether a library binding for linking is
symbolic, dynamic (shared), or static (nonshared).
-Bdynamic is the default. You can use the -B
option several times on a command line.
For more information on the -Bbinding option, see
the ld(1) man page and the Solaris documentation.
-Bdynamic directs the link editor to look for
liblib.so files. Use this option if you want
shared library bindings for linking. If the
liblib.so files are not found, it looks for
liblib.a files.
-Bstatic directs the link editor to look only for
liblib.a files. The .a suffix indicates that the
file is static, that is, nonshared. Use this
option if you want nonshared library bindings for
linking.
-Bsymbolic forces symbols to be resolved within a
shared library if possible, even when a symbol is
already defined elsewhere. For an explanation of
-Bsymbolic, see the ld(1) man page.
This option and its arguments are passed to the
linker, ld. If you compile and link in separate
steps and are using the -Bbinding option, you must
include the option in the link step.
Warning:
Never use -Bsymbolic with programs containing C++
code, use linker scoping instead. See the C++
User's Guide for more information on linker scop-
ing. See also the -xldscope option.
With -Bsymbolic, references in different modules
can bind to different copies of what is supposed
to be one global object.
The exception mechanism relies on comparing
addresses. If you have two copies of something,
their addresses won't compare equal, and the
exception mechanism can fail because the exception
mechanism relies on comparing what are supposed to
be unique addresses.
答案 1 :(得分:0)
请注意,对象不一定是整个链接的块。有一些方法可以将符号放在单独的部分中,这些部分可以放在最终的.exe中,具体取决于它是否被代码引用。 (搜索-gc-sections链接器选项,以及相关节生成gcc选项)
如果没有使用任何部分,可能根本就没有微观优化。