linux gcc链接可执行文件缺少stat64的静态定义

时间:2013-05-10 20:28:07

标签: linux linker glibc stat

linux stat64调用应该最终调用xstat64,并生成一个静态版本的stat64,它会随着调用一起传递一个版本。

我们看到一种情况,其中一个C链接(gcc)版本的代码调用stat64,当链接到旧版本的(C ++链接)共享库(libdb2.so.1,使用stat64但是isn')应该提供它),并没有结束这个stat64调用的“正确”静态版本。 C ++链接的应用程序符合我们的期望:

00000000004007c8 <__xstat64@plt>:
  4007c8:  jmpq   *1051250(%rip)        # 501240 <_GLOBAL_OFFSET_TABLE_+0x20>
  4007ce:  pushq  $0x1
  4007d3:  jmpq   4007a8 <_init+0x18>

0000000000400ac0 <stat64>:
  400ac0:  push   %rbp
  400ac1:  mov    %rsp,%rbp
  400ac4:  sub    $0x10,%rsp
  400ac8:  mov    %rdi,0xfffffffffffffff8(%rbp)
  400acc:  mov    %rsi,0xfffffffffffffff0(%rbp)
  400ad0:  mov    0xfffffffffffffff0(%rbp),%rdx
  400ad4:  mov    0xfffffffffffffff8(%rbp),%rsi
  400ad8:  mov    $0x1,%edi
  400add:  callq  4007c8 <__xstat64@plt>
  400ae2:  leaveq
  400ae3:  retq

而gcc链接代码(也链接到我们的libdb2共享库)最终会得到对stat64的全局引用,而不是它所假设的“静态”版本:

0000000000400618 <stat64@plt>:
  400618:   jmpq   *1050146(%rip)        # 500c40 <_GLOBAL_OFFSET_TABLE_+0x20>
  40061e:   pushq  $0x1
  400623:   jmpq   4005f8 <_init+0x18>

相同的代码,当与gcc链接时,如果没有链接到我们的libdb2库,最终会得到预期的“静态”stat64函数:

0000000000400550 <__xstat64@plt>:
  400550:   jmpq   *1050170(%rip)        # 500b90 <_GLOBAL_OFFSET_TABLE_+0x20>
  400556:   pushq  $0x1
  40055b:   jmpq   400530 <_init+0x18>

00000000004007b0 <stat64>:
  4007b0:   mov    %rsi,%rdx
  4007b3:   mov    %rdi,%rsi
  4007b6:   mov    $0x1,%edi
  4007bb:   jmpq   400550 <__xstat64@plt>

编辑:从链接器映射(-Wl, - print-map)获得的更多信息

当gcc链接的exe没有链接到我们的(libdb2)共享库时,我们看到它从libc_nonshared.a获取它的stat64:

/usr/lib64/libc_nonshared.a(stat64.oS)
                              /home/hotellnx94/peeterj/tmp/cc2f7ETx.o (stat64)
...

.plt            0x0000000000400530       0x70
 *(.plt)
 .plt           0x0000000000400530       0x70 /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crt1.o
                0x0000000000400540                __libc_start_main@@GLIBC_2.2.5
                0x0000000000400550                __xstat64@@GLIBC_2.2.5
                0x0000000000400560                printf@@GLIBC_2.2.5
                0x0000000000400570                memset@@GLIBC_2.2.5
                0x0000000000400580                strerror@@GLIBC_2.2.5
                0x0000000000400590                __errno_location@@GLIBC_2.2.5

 .text          0x00000000004007b0       0x10 /usr/lib64/libc_nonshared.a(stat64.oS)
                0x00000000004007b0                stat64

然而,一旦我们链接到我们的共享库(libdb2),符号就从crt1.o而不是lib_nonshared.a中获取:

.plt            0x00000000004005f8       0x70
 *(.plt)
 .plt           0x00000000004005f8       0x70 /usr/lib64/gcc/x86_64-suse-linux/4.1.2/../../../../lib64/crt1.o
                0x0000000000400608                __libc_start_main@@GLIBC_2.2.5
                0x0000000000400618                stat64
                0x0000000000400628                printf@@GLIBC_2.2.5
                0x0000000000400638                memset@@GLIBC_2.2.5
                0x0000000000400648                strerror@@GLIBC_2.2.5
                0x0000000000400658                __errno_location@@GLIBC_2.2.5

我们可以做什么(或者我们在新版本的库中没有看到这样做),这会导致一旦消费者链接到我们的库,就不会再共享lib_nonshared.a了?

1 个答案:

答案 0 :(得分:1)

事实证明,这是由于已修复的intel编译器错误。当我们开始使用具有修复程序的编译器版本时,我们因为新版本的intel编译器(生成有问题的共享库)而暴露于二进制兼容性问题,所以正确地没有导出这个stat64符号。