可执行目标文件
image.png可执行目标文件还包括了程序的入口点,即第一条指令的地址。
各个段会被映射到连续的内存区域,段头部表描述了这种映射关系。
加载可执行目标文件
将程序复制到内存并运行的过程叫加载。
image.png
堆是从低地址向高地址分配空间,而栈是从高地址向低地址分配空间。
从地址2^48开始,是为内核中的代码和数据保留的(操作系统驻留在内存的部分)。
动态链接共享库
静态库是在链接的时候合并到可执行目标文件里面,这样有一些缺点:
- 每次更新了目标文件都需要重新链接
- 多个程序都需要使用标准库函数,都需要进行链接并载入内存,是对内存空间的浪费
共享库就是为了解决这部分问题而产生的。共享库可以在运行或加载时,加载到任意的内存地址,并和一个内存中的程序链接起来。这个过程称为动态链接,由动态链接器来执行。
共享库也叫共享目标,Linux中通常用.so后缀表示,Windows被称为DLL。
编译共享目标文件:
gcc -shared -fpic -o libvector.so addvec.c multvec.c
这样生成的libvector.so就是共享目标文件,再将文件链接到其他程序中:
gcc -o prog main.c ./libvector.so
这样prog程序在运行的时候就会和libvector.so链接。在创建可执行文件时,静态执行一些链接,在程序加载时,动态完成链接过程。链接器没有复制so文件的代码和数据节,只复制了一些重定位和符号表信息,使得在运行时可以对libvector.so中的代码和数据的引用。
从应用程序中加载和链接共享库
上面那种方式要在编译时指定共享库,而另外一种方式是在应用程序中,通过接口直接加载和链接共享库,在编译时无需指定。
步骤:
//加载共享库
handle = dlopen("filename",flag);
//链接共享库
func = dlsym(handle,"func_name");
func();
//关闭共享库
dlclose(handle);
//产生的错误
dlerror();
image.png
库打桩机制
类似于设计模式中的代理模式,允许截获对共享库函数的调用,取而代之执行自己的代码。打桩可以发生在编译时、链接时或当程序被加载和执行的运行时。即定义一个完全一样的函数接口,在实现的时候通过调用真正的函数完成功能,同时可以记录调用的参数与结果等。
网友评论