只是扩展:
ELF文件(Executable and Linkable Format):可执行和可连接格式文件。
ELF可重定位目标文件的格式:
ELF可执行文件的格式:
静态库:(.a)
所有的编译系统都提供一种机制,将所有相关的目标文件打包成为一个单独的文件,成为静态库,它可以用作连接器的输入。(一般由.o文件构成,即.o文件的打包)
程序在编译链接的时候把库的代码复制到可执行文件中,程序运行时将不再需要静态库。
如何打包?
ar -rc lib库名.a(库文件名) xxx.oex: ar -rc libmymath.a add.o sub.o
静态库默认搜索路径:
1./lib/usr/lib
2.-L指定库的路径 ex: gcc main.c -L . -lmymath
当静态库被调用时,用到哪个函数,调用哪个函数(.o文件)。
缺点:
1.静态库和所有软件一样需要定期的维护和更新。如果我们想要使用一个库的最新版本,就必须以某种方式了解到该库的更新情况,
然后显式的将我们的程序与更新的库重新连接,这在大型程序的开发过程中是不能被容忍的。
2.几乎每个程序都使用了库的标准IO函数,如scanf,printf, 在运行时,这些函数的代码会被复制到每个运行进程的文本段中,这样会造成存储器系统资源的极大浪费。
动态(共享)库:(.so)
(ELF文件, 即可执行程序)共享库是一个目标模块,在运行时,可以加载到任意的存储器地址,并和一个在存储器中的程序连接起来。
动态库在运行的时候才去链接动态库的代码,多少程序共享使用库的代码。一个与动态库连接的可执行文件仅仅包含他们用到的函数入口地址一个表,
而不是外部函数所在目标文件的整个机器码在可执行文件开始运行之前,外部函数的机器码由操作系统从磁盘上的该动态库文件中复制到内存中。
这个过程成为动态链接。动态库可以在多个程序之间共享,所以动态链接是的可执行文件更小,节省了磁盘空间。
动态连接器通过下列三步重定位完成链接任务:
1.重定位libc.so的文本和数据到某个存储器段。
2.重定位libmymath.so的文本和数据到另一个存储器段。
3.重定位a.out中所有对libc.so和libmymath.so定义的符号和引用。
最后,动态链接器将传递给应用程序。
如何生成动态库?
gcc -fPIC -shared -o lib库名.soxxx.c ex:gcc -fPIC -shared -o libmymath.so add.c sub.c
-fPIC:指示编译器生成与位置无关的代码。
-shared:指示连接器创建一个共享的目标文件。
动态库的链接:
gcc main.c -L . -lmymath
ldd查看静态库链接情况
ldd a.out
动态库的使用:
1.vim /etc/ld.so.conf.d/XX.conf-- 把动态库的路径加进去 vim /etc/ld.so.conf.d/mymath.conf .
2.ldconfig链接动态库
利用文件打开动态库:动态库的运行时加载: -ldlex: gcc main.c -ldl
void *dlopen(const char *filename, int flag);//动态库名,什么时候将动态库加载到内存(RTLD_LAZY(什么时候用,什么时候加载))
//返回值 代表动态库的句柄
void *dlsym(void *handle,//dlopen的返回值
const char *symbol);//函数的符号名(函数名) 返回函数的地址---函数指针来接收
int dlclose(void *handle);//关闭dlopen打开的文件
#include <stdio.h>
#include <dlfcn.h>
#include "add.h"
#include "sub.h"
typedef int FUNC(int ,int);
int main()
{
void *dp = dlopen("libmath.so", RTLD_LAZY);
FUNC *paf, *psf;
paf = (FUNC*)dlsym(dp, "add");
psf = (FUNC*)dlsym(dp, "sub");
printf("10 + 20 = %d\n", paf(10,20));
printf("10 - 20 = %d\n", psf(10,20));
dlclose(dp);
return 0;
}
动态链接库的优点:
1.动态链接库在内存中多个进程之间可以共享,节省计算机内存和磁盘空间。
2.程序的升级和更新变得容易。理论上只需要将旧的目标文件覆盖掉,而无需将程序再重新连接一遍。
3.使开发过程各个模块变得独立,耦合度小。
4.程序在运行时可以动态的选择加载的各种程序模块,这个优点被用来制作插件。
缺点:
当程序依赖的某个模块更新后,由于新模块与旧模块之间的接口不兼容,导致了原有的程序无法运行。这个问题又称“DLL Hell”.