首页 / 操作系统 / Linux / Linux下共享库的注意点之-fpic
在Linux下编译共享库必须加上-fpic。这是为什么呢?首先看一个简单的例子:#include <stdio.h>int fun1(){printf("fun1
");}先不加-fpic的情况下生成库,反汇编查看fun1的机器码0000044c <fun1>: 44c: 55push %ebp 44d: 89 e5 mov%esp,%ebp 44f: 83 ec 18sub$0x18,%esp 452: c7 04 24 b2 04 00 00movl $0x4b2,(%esp) 459: e8 fc ff ff ffcall 45a <fun1+0xe> 45e: c9leave 45f: c3ret可以看出调用printf的位置是那个唯一的一个call,并不是跳转到plt表,有关plt表的内容可以查看我前面的博文。也就是说在该库被加载时需要修改代码段来达到重定位的效果。那么每一个加载这个共享库的程序都要有这个库的一份拷贝,这样实际上就没有达到共享库的效果。看下运行时的机器码 0xb771d44c <+0>: 55push %ebp 0xb771d44d <+1>: 89 e5 mov%esp,%ebp 0xb771d44f <+3>: 83 ec 18sub$0x18,%esp 0xb771d452 <+6>: c7 04 24 b2 d4 71 b7movl $0xb771d4b2,(%esp) 0xb771d459 <+13>:e8 42 b2 ea ffcall 0xb75c86a0 <puts> 0xb771d45e <+18>:c9leave 0xb771d45f <+19>:c3ret 显然代码段被修改了。再看一下再加了-fpic的情况下生成的库,反汇编看下fun1的机器码0000045c <fun1>: 45c: 55push %ebp 45d: 89 e5 mov%esp,%ebp 45f: 53push %ebx 460: 83 ec 14sub$0x14,%esp 463: e8 ef ff ff ffcall 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 24mov%eax,(%esp) 477: e8 04 ff ff ffcall 380 <puts@plt> 47c: 83 c4 14add$0x14,%esp 47f: 5bpop%ebx 480: 5dpop%ebp 481: c3ret 482: 90nop 483: 90nop 484: 90nop 485: 90nop 486: 90nop 487: 90nop 488: 90nop看过很多汇编代码的人知道printf有时候是puts,所以这段机器码中printf就对应第二个call,也就是跳转到plt表中去查找puts符号,那么这样就达到了共享库的效果,此时每一个需要该库的程序只是有一个plt表的拷贝,而代码段所有应用程序是共享的。再看下运行时机器码 0xb773045c <+0>: 55push %ebp 0xb773045d <+1>: 89 e5 mov%esp,%ebp 0xb773045f <+3>: 53push %ebx 0xb7730460 <+4>: 83 ec 14sub$0x14,%esp 0xb7730463 <+7>: e8 ef ff ff ffcall 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 24mov%eax,(%esp) 0xb7730477 <+27>:e8 04 ff ff ffcall 0xb7730380 <puts@plt> 0xb773047c <+32>:83 c4 14add$0x14,%esp 0xb773047f <+35>:5bpop%ebx 0xb7730480 <+36>:5dpop%ebp 0xb7730481 <+37>:c3ret 显然是一致的。所以,在编译共享库时是必须加上-fpic的选项的,否则共享库剩下的仅仅是硬盘上的空间,而没有剩下内存。本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-07/133412.htm