美文网首页
共享库so机制(函数)

共享库so机制(函数)

作者: Teech | 来源:发表于2019-05-21 14:17 被阅读0次

    上一篇谈到了共享库中引用全局变量的处理,在来谈谈对引用函数的处理。

    $ cat test.c
    int foo(void);
    
    int function(void) {
        return foo();
    }
    $ gcc -shared -fPIC -o libtest.so test.c
    
    $ objdump --disassemble libtest.so
    [...]
    00000000000005bc <function>:
     5bc:        55         push   %rbp
     5bd:        48 89 e5               mov    %rsp,%rbp
     5c0:        e8 0b ff ff ff         callq  4d0 <foo@plt>
     5c5:        5d                     pop    %rbp
    
    $ objdump --disassemble-all libtest.so
    00000000000004d0 <foo@plt>:
     4d0:   ff 25 82 03 20 00       jmpq   *0x200382(%rip)        # 200858 <_GLOBAL_OFFSET_TABLE_+0x18>
     4d6:   68 00 00 00 00          pushq  $0x0
     4db:   e9 e0 ff ff ff          jmpq   4c0 <_init+0x18>
    
    $ readelf --relocs libtest.so
    Relocation section '.rela.plt' at offset 0x478 contains 2 entries:
      Offset          Info           Type           Sym. Value    Sym. Name + Addend
    000000200858  000400000007 R_X86_64_JUMP_SLO 0000000000000000 foo + 0
    

    可以看到 callq 4d0 foo@plt,跳转到了4d0: ff 25 82 03 20 00 jmpq *0x200382(%rip),可以得出跳转到0x200858 这个位置存储的地址上的内容,看注释这个属于GOT表的地址。继续查看反汇编数据

    $ objdump --disassemble-all libtest.so
    
    Disassembly of section .got.plt:
    
    0000000000200840 <.got.plt>:
      200840:       98                      cwtl
      200841:       06                      (bad)
      200842:       20 00                   and    %al,(%rax)
            ...
      200858:       d6                      (bad)
      200859:       04 00                   add    $0x0,%al
      20085b:       00 00                   add    %al,(%rax)
      20085d:       00 00                   add    %al,(%rax)
      20085f:       00 e6                   add    %ah,%dh
      200861:       04 00                   add    $0x0,%al
      200863:       00 00                   add    %al,(%rax)
      200865:       00 00                   add    %al,(%rax)
            ...
    

    可以看到0x200858 这个地址处存储的数据为0x04d6,这个刚好为plt条目里的下一条指令地址,所以这里等价于直接执行plt条目里的下一条指令,这里压栈一个数据0x0,然后跳转到4c0 。这里等价于调用动态链接器。然后动态链接器根据栈的条目确定foo函数的运行时的位置,把这个地址重写回0x200858(got表中的条目),最后把控制传递给foo。
    当下次在调用foo时,可以直接从got表中的位置取到foo的地址,直接将控制转移给foo。
    上述就是“延迟绑定”的意思,避免了像libc.so这样的共享库里有几百上千个函数,一个程序只会用到很少一部分,避免动态链接器加载时进行上千个函数的重定位。第一次调用函数开销比较大,后面只需要花费一条指令和一个间接引用内存。

    相关文章

      网友评论

          本文标题:共享库so机制(函数)

          本文链接:https://www.haomeiwen.com/subject/uqfjzqtx.html