静态库
可重定位目标文件以一种特定的方式打包成一个单独的文件,并且在链接生成可执行文件时,从这个单独的文件中“拷贝”它自己需要的内容到最终的可执行文件中。这个单独的文件,称为静态库。linux中通常以.a(archive)为后缀
- 生成:
ar rcs + 静态库文件的名字 + 目标文件列表
- 使用:
gcc -c main.c
gcc -static -o main main.o -lm // 如果要链接libxxx.a,使用-lxxx即可)
-lm : 使用用到系统中的静态库libm.a
必须把 -lm放在main.o的后面。
lm放在main.o的前面,发生错误:
main.o: In function `main':
main.c:(.text+0x2a): undefined reference to `exp'
collect2: error: ld returned 1 exit status
必须把 -lm放在main.o的后面的原因
-
放在最后时解析过程如下:
- 链接器从左往右扫描可重定位目标文件和静态库
- 扫描main.o时,发现一个未解析的符号exp,记住这个未解析的符号
- 扫描libm.a,找到了前面未解析的符号,因此提取相关代码
- 最终没有任何未解析的符号,编译链接完成
-
将-lm放到main.o 前面
- 链接器从左往右扫描可重定位目标文件和静态库
- 扫描libm.a,由于前面没有任何未解析的符号,因此不会提取任何代码
- 扫描main.o,发现未解析的符号exp
- 扫描结束,还有一个未解析的符号,因此编译链接报错
objdump -d main
使用反汇编查看 :
_exp函数也在main二进制文件中,函数调用的时候直接调用
动态库
动态库和静态库类似,但是它并不在链接时将需要的二进制代码都“拷贝”到可执行文件中,而是仅仅“拷贝”一些重定位和符号表信息,这些信息可以在程序运行时完成真正的链接过程。linux中通常以.so(shared object)作为后缀。
- 生成
gcc -c -fpic -o main.o
gcc -shared -o main main.so
- 使用:
gcc -o main main.c -lm #默认使用的是动态链接
和静态库一样-lm 必须放到 main.c 后面;
文件大小明显比使用静态库小
动态库链接通过plt和got实现,通过_dl_runtime_resolve_xsave查找动态库中的函数
用到的实例代码:
#include<stdio.h>
#include<math.h>
int main(int argc,char *argv[])
{
printf("hello 编程珠玑\n");
int b = 2;
double a = exp(b);
printf("%lf\n",a);
return 0;
}