C++静态库与动态库执行过程深入

静态库与动态库

静态库

  • 基本使用

    静态库是将一组完整的功能,如一个提供了完整运算的计算器,进行封装为一个.a或.lib文件。

    使用时仅需要在使用处include这个静态库的头文件。而后在编译时添加-L与-l选项,如静态库位置在/usr/local, 名称为libmath.a

    Linux静态库命名规范,必须是”lib[your_library_name].a”:lib为前缀,中间是静态库名,扩展名为.a。

    执行命令为:g++ mycode.cpp - L /usr/local -lmath,这回使静态库被链接到最终的可执行文件中

  • 缺陷

    静态库被不同的文件引用时会有多个在内存中的拷贝,可能会造成体积庞大,因此较大的文件应该尽量使用动态库;

    静态库对程序的更新、部署和发布页会带来麻烦。如果静态库更新了,所有使用它的应用程序都需要重新编译、发布给用户

动态库

image-20230920163640213

或者合为一个命令:

g++ -fPIC -shared -o libdynmath.so DynamicMath.cpp

执行过程

一个程序的执行阶段都会有一个叫代码段的内存段,也就是说程序要执行哪个函数要会去代码段里面寻址,查函数地址。

那么代码段里面存的函数地址的值是怎么计算?这就是link阶段做的(其中一件)事:计算函数地址偏移量。

于是:

所谓的“静态库”就是说这个函数地址偏移量在link阶段计算好了,所以函数地址要相对整个代码段的地址在执行阶段是不变的,最终看起来每个进程“独享”函数库地址。(link阶段已经把静态库放到了最终的可执行文件中)

“动态库”就是说这个函数地址具体是多少,则是在执行阶段才计算好。(执行阶段)函数地址相对进程的内存段是会变化的。

这么做当然是有用的:对于一个内存不充足,抑或是平台开发,动态库都方便开发,不用link出庞大的二进制包,代价就是执行阶段运行会慢些。

而在跨平台,你不知道新平台是否有完善的动态库时,静态库这时候就起作用,你link出的二进制包不怕库缺失,代价就是二进制包占空间比较大,但是运行速度快。
摘自https://www.zhihu.com/question/457186986/answer/1863306428

  • 静态库执行过程

    静态库如果是一个函数,那么这个函数的偏移地址是固定的。函数会复制到该进程代码段中固定偏移地址的位置,从而形成一个完整的程序

  • 动态库执行过程

    1. 查找动态库:首先,进程需要知道要调用的函数在哪个动态库中。这个信息在编译阶段就已经确定了。
    2. 加载动态库:在程序运行时,动态链接器会把需要的动态库加载到内存中。
    3. 查找函数地址:当进程第一次调用某个函数时,动态链接器会在动态库中查找这个函数的地址。这个过程叫做延迟绑定。
    4. 使用GOT和PLT:为了实现延迟绑定,进程会使用两个表:全局偏移表 (Global Offset Table, GOT) 和过程链接表 (Procedure Linkage Table, PLT)。这两个表中存储了函数的地址信息。(对于模块外部引用的全局变量和全局函数,用 GOT 表的表项内容作为地址来间接寻址)
    5. 更新GOT:当函数被第一次调用时,动态链接器会把函数(不在代码段中)的真实地址写入GOT。之后的调用就可以直接从GOT中读取地址,而不需要再次查找。
posted @ 2023-09-20 17:26  石中火本火  阅读(113)  评论(0编辑  收藏  举报