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


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

    首先看一个简单的例子:

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

    先不加-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的选项的,否则共享库省下的仅仅是硬盘上的空间,而没有省下内存。

  • 相关阅读:
    Java泛型
    Hibernate JPA实体继承的映射(一) 概述
    Hibernate JPA实体继承的映射(二) @MappedSuperclass
    rownum使用说明
    Javascript 中使用Json的四种途径
    JavaScript中使用JSON,即JS操作JSON总结
    Refresh Tokens: When to Use Them and How They Interact with JWTs
    Nginx 安装与启动
    JSON与js对象序列化
    js对象小结
  • 原文地址:https://www.cnblogs.com/leo0000/p/5691483.html
Copyright © 2020-2023  润新知