linux下共享库的注意点之-fpic

在编译共享库必须加上-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 <[email protected]>
 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 <[email protected]>
   0xb773047c <+32>:    83 c4 14        add    $0x14,%esp
   0xb773047f <+35>:    5b      pop    %ebx
   0xb7730480 <+36>:    5d      pop    %ebp
   0xb7730481 <+37>:    c3      ret 

显然是一致的。

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

时间: 2024-12-09 17:51:36

linux下共享库的注意点之-fpic的相关文章

【原创】Linux下共享库嵌套依赖问题

问题场景: 动态库 librabbitmq_r.so 内部依赖动态库 libevent_core.so 和 libevent_pthreads.so : 可执行程序 sa 依赖动态库 librabbitmq_r.so ; 在链接生成 sa 的时候希望只指定 librabbitmq_r.so 而不指定 libevent_core.so 和 libevent_pthreads.so . 错误信息: ... g++ ../source/authorisecfg.o ../source/bmcinst.

Linux下共享库嵌套依赖问题 (转载)

转自:http://my.oschina.net/moooofly/blog/506466 问题场景: 动态库 librabbitmq_r.so 内部依赖动态库 libevent_core.so 和 libevent_pthreads.so : 可执行程序 sa 依赖动态库 librabbitmq_r.so ; 在链接生成 sa 的时候希望只指定 librabbitmq_r.so 而不指定 libevent_core.so 和 libevent_pthreads.so . 错误信息: ... g

【Linux笔记】细说linux系统下共享库的命名规范和使用方法

1. Shared Library的优势 共享库,又称动态库或so文件,顾名思义,它可以在可执行文件启动时加载或进程运行期被调用.使用共享库有很多好处,例如(包含但不限于下面提到的场景): 1) 减少了依赖共享库的模块的大小,因为它们不必把共享库提供的功能的实现代码静态编译到自己的模块代码中. 2) 在同一台机器上运行的多个进程会在内存中共享同一份动态库,操作系统采用的这种内存布局方式可以极大地节省机器内存资源. 3) 若很多模块依赖了以共享库形式提供的同一个底层库,则底层库升级时,只需升级该s

Linux下的库操作工具-nm、ar、ldd、ldconfig和ld.so

Linux下的库操作工具-nm.ar.ldd.ldconfig和ld.so 1.nm [options] file 列出file中的所有符号 [option] -c 将符号转化为用户级的名字 -s 当用于.a文件即静态库时,输出把符号名映射到定义该符号的模块或成员名的索引 -u 显示在file外定义的符号或没有定义的符号 -l 显示每个符号的行号,或为定义符号的重定义项 2.ar {dmpqrtx} [member] archive file 用于操作高度结构化的存档文件(.a) [option

Linux下静态库与动态库

一.基本概念 1.1.什么是库        在 windows 平台和 linux 平台下都大量存在着库. 本质上来说库是一种可执行的二进制代码(但不可以独立执行),可以被操作系统载入内存执行. 由于 windows 和 linux 的平台不同(主要是编译器.汇编器和连接器 的不同),因此二者库的二进制是不兼容的. 本文仅限于介绍 linux 下的库. 1.2. 库的种类 linux下的库有两种:静态库和共享库(动态库). 二者的不同点在于代码被载入的时刻不同: 静态库的代码在编译过程中已经被

linux下静态库和动态库一些东西

http://www.cnblogs.com/changefuture/archive/2011/12/22/2297460.html Linux  动态链接库和静态库示例 文件预览 文件目录树如下,如你所见,非常简单. libtest/ |-- lt.c |-- lt.h `-- test.c 代码 #lt.c /* lt.c * */ #include <stdio.h> void myprint(void) { printf("Linux library test!\n&quo

Linux下静态库和动态库的制作与使用

p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; font-size: 10.5pt; font-family: "Times New Roman", serif } h2 { margin-top: 14.0pt; margin-right: 0cm; margin-bottom: 14.0pt; margin-left: 28.8pt;

谈谈Linux下动态库查找路径的问题 ldconfig LD_LIBRARY_PATH PKG_CONFIG_PATH

谈谈Linux下动态库查找路径的问题 ldconfig LD_LIBRARY_PATH  PKG_CONFIG_PATH 转载自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=23069658&id=4028681 学习到了一个阶段之后,就需要不断的总结.沉淀.清零,然后才能继续“上路”.回想起自己当年刚接触Linux时,不管是用源码包编译程序,还是程序运行时出现的和动态库的各种恩恩怨怨,心里那真叫一个难受.那时候脑袋里曾经

linux下的库链接

linux下的编译一般都是需要一些头文件或者库文件的支持,头文件或者库文件一般的默认路径是在/usr/include/ 和/usr/lib/下的,但是当你需要的文件没有在默认的路径下,该怎么办尼,这里提供了几种链接到的方法: 1.$ gcc foo.c -I /home/liuru/include -o foo                                               链接到/home/liuru/include 下的头文件,使用-I选项 2.$ gcc foo