【问题标题】:relocation entries in a shared lib共享库中的重定位条目
【发布时间】: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 -Mintelml_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


【解决方案1】:

找不到原因,但这是 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.

【讨论】:

  • 有趣,还有这个页面:technovelty.org/code/c/bsymbolic.html 解释了 Bsymbolic。我会研究这个,谢谢指点
  • 我认为 Bsymbolic 只是一个相关的标志,这里真正的交易是符号的搜索顺序 - 首先在可执行文件中,然后是共享库,以及使用此搜索顺序覆盖全局符号的能力。 LD_PRELOAD 是另一种方式。
【解决方案2】:

请注意,对象不一定是完整链接的块。有一些方法可以将符号放在单独的部分中,这些部分可以放在最终的 .exe 中,具体取决于它是否被代码引用。 (搜索 -gc-sections 链接器选项,以及相关的节生成 gcc 选项)

当没有使用任何部分时,可能根本就没有对此进行微优化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-15
    • 2021-05-23
    • 2014-05-06
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 2011-01-12
    相关资源
    最近更新 更多