转自https://www.cnblogs.com/king-lps/p/7757919.html
1.obj文件,.o
也就是用户自己写的用于连接的文件,是特殊的二进制文件。根据里面不只有程序指令,还有一些相关信息,告诉连接器如何根据多个.o文件及链接库文件.a及.so进行修改从而形成最后的可执行二进制文件。
2.静态链接库文件,.a
静态链接库文件本质上为.o的打包,连接器会将其复制(应该是用到了那个库函数就copy哪个)到可执行二进制文件中。与.o文件不同的是,.a一定要放在引用它的.o文件后面,函数定义才能被找到,而.o并不会这样。
特点:
l 静态库对函数库的链接是放在编译时期完成的。
l 程序在运行时与函数库再无瓜葛,移植方便。
l 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
问题:
另一个问题是静态库对程序的更新、部署和发布页会带来麻烦。如果静态库liba.lib更新了,所以使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新)。
3.动态链接库文件,.so(没看太懂)
相对于静态链接(static link)拷贝原有的程序代码进可执行文件,动态链接不那样做,link editor把一些信息写进可执行文件而已。
例如,需要的程序库名、函数名等,最后执行的时候,必须呼叫dynamic linker來做program intepreter(程序直译器?),dynamic linker会根据需要的函数库名称,把想要的函数名字创造一个可执行的image放到内存,所以执行有动态链接的执行文件,最后通常都是由OS的exec系列的system call与dynamic linker如ld.so联合完成。(一个显示调用的系统调用和动态链接库配合运行实现动态链接库函数的调用)
dynamic linker通常会做如下工作:
(1)把可执行文件的内容加载到process image
(2)把shared obj需要的东西加载到process image
(3)完成relocation(再布置)
本来这些obj文件里面的虚拟地址应该和文件的地址有相对应的偏移(offset),而文件首地址通常是0x08040800,这是绝对虚拟地址,但它只适合可执行文件,例如Linux extuable file通常是:
file offset virtual address
----------- ----------------
0x0 0x08048000
0x100 0x08048100
shared obj函数库里的程序代码必须为位置无关代码Position
Independent Code (PIC),也就是说它的地址可能会随不同process而有不同,例如,一个程序只用了libc.so、
ld-linux.so,通常这时候lib.so是从0x40017000开始的,但如果另一个程序多用一个libm.so,那么libc.so从
0x40034000开始两个的printf参照(reference),就会有不同的地址,所以这种动态函数库的内部资料就要说明这些codePIC。
动态库特点总结:
l 动态库把对一些库函数的链接载入推迟到程序运行的时期。
l 可以实现进程之间的资源共享。(因此动态库也称为共享库,不重复载入)
l 将一些程序升级变得简单。
l 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。
Window与Linux执行文件格式不同,在创建动态库的时候有一些差异。
l 在Windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数做出初始化的入口,通常在导出函数的声明时需要有_declspec(dllexport)关键字。
l Linux下gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要函数做特别的声明,编写比较方便。
与创建静态库不同的是,不需要打包工具(ar、lib.exe),直接使用编译器即可创建动态库。