你的位置:首页 > 操作系统

[操作系统]linux下共享库的注意点之


在编译共享库必须加上-fpic。这是为什么呢?

首先看一个简单的例子:

#include <stdio.h>int fun1(){    printf("fun1\n");}

先不加-fpic的情况下生成库,反汇编查看fun1的机器码

0000044c <fun1>: 44c:  55           push  %ebp 44d:  89 e5          mov  %esp,%ebp 44f:  83 ec 18        sub  $0x18,%esp 452:  c7 04 24 b2 04 00 00  movl  $0x4b2,(%esp) 459:  e8 fc ff ff ff     call  45a <fun1+0xe> 45e:  c9           leave  45f:  c3           ret 

可以看出调用printf的位置是那个唯一的一个call,并不是跳转到plt表,有关plt表的内容可以查看我前面的博文。也就是说在该库被加载时需要修改代码段来达到重定位的效果。那么每一个加载这个共享库的程序都要有这个库的一份拷贝,这样实际上就没有达到共享库的效果。

看下运行时的机器码

  0xb771d44c <+0>:   55   push  %ebp  0xb771d44d <+1>:   89 e5  mov  %esp,%ebp  0xb771d44f <+3>:   83 ec 18    sub  $0x18,%esp  0xb771d452 <+6>:   c7 04 24 b2 d4 71 b7  movl  $0xb771d4b2,(%esp)  0xb771d459 <+13>:  e8 42 b2 ea ff call  0xb75c86a0 <puts>  0xb771d45e <+18>:  c9   leave   0xb771d45f <+19>:  c3   ret 

显然代码段被修改了。

再看一下再加了-fpic的情况下生成的库,反汇编看下fun1的机器码

0000045c <fun1>: 45c:  55           push  %ebp 45d:  89 e5          mov  %esp,%ebp 45f:  53           push  %ebx 460:  83 ec 14        sub  $0x14,%esp 463:  e8 ef ff ff ff     call  457 <__i686.get_pc_thunk.bx> 468:  81 c3 8c 1b 00 00    add  $0x1b8c,%ebx 46e:  8d 83 ee e4 ff ff    lea  -0x1b12(%ebx),%eax 474:  89 04 24        mov  %eax,(%esp) 477:  e8 04 ff ff ff     call  380 <puts@plt> 47c:  83 c4 14        add  $0x14,%esp 47f:  5b           pop  %ebx 480:  5d           pop  %ebp 481:  c3           ret   482:  90           nop 483:  90           nop 484:  90           nop 485:  90           nop 486:  90           nop 487:  90           nop 488:  90           nop

看过很多汇编代码的人知道printf有时候是puts,所以这段机器码中printf就对应第二个call,也就是跳转到plt表中去查找puts符号,那么这样就达到了共享库的效果,此时每一个需要该库的程序只是有一个plt表的拷贝,而代码段所有应用程序是共享的。

再看下运行时机器码

  0xb773045c <+0>:   55   push  %ebp  0xb773045d <+1>:   89 e5  mov  %esp,%ebp  0xb773045f <+3>:   53   push  %ebx  0xb7730460 <+4>:   83 ec 14    sub  $0x14,%esp  0xb7730463 <+7>:   e8 ef ff ff ff call  0xb7730457 <__i686.get_pc_thunk.bx>  0xb7730468 <+12>:  81 c3 8c 1b 00 00    add  $0x1b8c,%ebx  0xb773046e <+18>:  8d 83 ee e4 ff ff    lea  -0x1b12(%ebx),%eax  0xb7730474 <+24>:  89 04 24    mov  %eax,(%esp)  0xb7730477 <+27>:  e8 04 ff ff ff call  0xb7730380 <puts@plt>  0xb773047c <+32>:  83 c4 14    add  $0x14,%esp  0xb773047f <+35>:  5b   pop  %ebx  0xb7730480 <+36>:  5d   pop  %ebp  0xb7730481 <+37>:  c3   ret 

显然是一致的。

所以,在编译共享库时是必须加上-fpic的选项的,否则共享库剩下的仅仅是硬盘上的空间,而没有剩下内存。