什么是库:
预先编译好的二进制文件
静态库(static library)就是将相关的目标模块打包形成的单独的文件。使用ar命令。
静态库的优点在于:
- 程序员不需要显式的指定所有需要链接的目标模块,因为指定是一个耗时且容易出错的过程;
- 链接时,连接程序只从静态库中拷贝被程序引用的目标模块,这样就减小了可执行文件在磁盘和内存中的大小。
gcc -c max.c
ar crv libaaa.a add.o max.o
动态库(dynamic library)是一种特殊的目标模块,它可以在运行时被加载到任意的内存地址,或者是与任意的程序进行链接。
动态库的优点在于:
- 更新动态库,无需重新链接;对于大系统,重新链接是一个非常耗时的过程;
- 运行中可供多个程序使用,内存中只需要有一份,节省内存
-shared: 指定生成动态链接库。
-static: 指定生成静态链接库。
-fPIC: 表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,概念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。
-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),
则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意
位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
不加fPIC编译出来的so,是要再加载时根据加载到的位置再次重定位的.(因为它里面的代码并不是位置无关代码)
如果被多个应用程序共同使用,那么它们必须每个程序维护一份so的代码副本了.(因为so被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)
我们总是用fPIC来生成so,也从来不用fPIC来生成a.
fPIC与动态链接可以说基本没有关系,libc.so一样可以不用fPIC编译,只是这样的so必须要在加载到用户程序的地址空间时重定向所有表目.
-L.: 表示要连接的库在当前目录中。
-l: 指定链接时需要的动态库。编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib ,后面加上 .so 来确定库的名称
链接器将函数的代码从其所在地(目标文件或静态链接库中)拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
为创建可执行文件,链接器必须要完成的主要任务:
- 符号解析:把目标文件中符号的定义和引用联系起来;
- 重定位:把符号定义和内存地址对应起来,然后修改所有对符号的引用。
在此种方式下,函数的定义在动态链接库或共享对象的目标文件中。在编译的链接阶段,动态链接库只提供符号表和其他少量信息用于保证所有符号引用都有定义,保证编译顺利通过。动态链接器(ld-linux.so)链接程序在运行过程中根据记录的共享对象的符号定义来动态加载共享库,然后完成重定位。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。