现在的位置: 首页 > 综合 > 正文

动态库运行时符号解析

2018年06月09日 ⁄ 综合 ⁄ 共 1573字 ⁄ 字号 评论关闭

现在有如下代码:

main.c:

#include<stdio.h>
void print() {
    printf("print in main.c \n");
}

int main() {
    func();
    return 0;
}

temp.c:

#include<stdio.h>
void print() {
    printf("print in temp.c \n");
}

void func() {
    print();
}

将temp.c编译成动态库:gcc -fPIC -shared -o libtemp.so temp.c
然后构建可运行程序:gcc -o main main.c libtemp.so

运行之后发现输出:

printf("print in main.c \n");

这是因为:

如果一个全局符号在多个库中进行了定义,那么多该符号的引用会被绑定到扫描库时找到的第一个定义,其中扫描顺序是按照这些库在静态链接命令行中列出时从左到右的顺序。

我们可以通过readelf  -r libtemp.so 查看动态relocation section的内容:

Relocation section '.rela.plt' at offset 0x480 contains 3 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000201018  000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts + 0
000000201020  000800000007 R_X86_64_JUMP_SLO 00000000000005ec print + 0
000000201028  000500000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_finalize + 0

这说明print并没有绑定到当前库中的print符号上。那么,如果要想库中的全局符号绑定到该符号在库中的定义上,方法如下:

gcc -fPIC -shared -Wl,Bsymbolic -o libtemp.so temp.c

加上Bsymbolic之后,再次采取readelf  -r 查看动态库:

Relocation section '.rela.plt' at offset 0x480 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000201018  000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts + 0
000000201020  000500000007 R_X86_64_JUMP_SLO 0000000000000000 __cxa_finalize + 0

这个时候说明print已经不采用动态解析了,因为已经绑定到当前库中的定义上了。为了确实这一点,objdump -d libtemp.so输出如下:

00000000000005cc <print>:
 5cc:   55                      push   %rbp
 5cd:   48 89 e5                mov    %rsp,%rbp
 5d0:   48 8d 3d 5f 00 00 00    lea    0x5f(%rip),%rdi        # 636 <_fini+0xe>
 5d7:   e8 04 ff ff ff          callq  4e0 <puts@plt>
 5dc:   c9                      leaveq 
 5dd:   c3                      retq   

00000000000005de <func>:
 5de:   55                      push   %rbp
 5df:   48 89 e5                mov    %rsp,%rbp
 5e2:   b8 00 00 00 00          mov    $0x0,%eax
 5e7:   e8 e0 ff ff ff          <span style="color:#FF0000;">callq  5cc <print></span>
 5ec:   c9                      leaveq 
 5ed:   c3                      retq   
 5ee:   66 90                   xchg   %ax,%ax

最后,如果一个库中的函数不对外公开,只是内部使用,那么最好是在函数的定义前面加上static。

抱歉!评论已关闭.