计算机系统篇之链接:静态链接(上)
Posted csstormq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算机系统篇之链接:静态链接(上)相关的知识,希望对你有一定的参考价值。
计算机系统篇之链接(3):静态链接(上)
Author:stormQ
Saturday, 21. December 2019 11:58AM
引入静态库的动机
引入静态库是为了更好地解决“编译器开发者如何将标准库函数提供给调用者使用”的问题。
解决该问题的不同方式及比较如下所示:
解决方式 | 优点 | 缺点 |
---|---|---|
方式1:编译器识别程序中对标准库函数的调用并直接生成相应的代码 |
|
|
方式2:将所有的标准库函数实现放到同一个可重定位目标文件中(即 .o 文件) |
|
|
方式3:将每个标准库函数实现放到一个独立的可重定位目标文件中,即一个可重定位目标文件中只存放一个库函数的实现 |
|
|
方式4:静态库 |
|
|
如何生成静态库
静态库的文件格式被称为存档(archive),以.a
为后缀。archive 是一组连接起来的可重定位目标文件的集合,有一个头部用于描述每个成员可重定位目标文件的大小和位置。
生成静态库的命令:
$ ar rs <target static library> <object file 1> <object file n>
# $ ar rs libtest.a sum.o test.o
注:操作码r
表示将指定的可重定位目标文件插入到静态库中,如果没有静态库则创建。修饰码s
表示将索引(ar
为可重定位目标文件的每个符号创建一个索引)添加到归档文件中,或者更新它(如果它已经存在)。建立索引的目的:可以加速到库的链接,并允许库中的函数相互调用,而不考虑它们在归档文件中的位置。
1)查看静态库中有哪些可重定位目标文件
# 查看静态库中所有的可重定位目标文件
$ ar t /usr/aarch64-linux-gnu/lib/libc.a
# 查看静态库中指定的可重定位目标文件
$ ar t /usr/aarch64-linux-gnu/lib/libc.a printf.o scanf.o
注:操作码t
只显示可重定位目标文件的名称。如果要显示其他信息,比如:可重定位目标文件的大小、文件权限等,需要添加修饰码v
,即$ ar tv /usr/aarch64-linux-gnu/lib/libc.a
。
2)从静态库中提取可重定位目标文件(即将指定的可重定位目标文件从静态库中拷贝到磁盘上)
# 从静态库中提取所有的可重定位目标文件
$ ar x /usr/aarch64-linux-gnu/lib/libc.a
# 从静态库中提取指定的可重定位目标文件
$ ar x /usr/aarch64-linux-gnu/lib/libc.a printf.o scanf.o
3)从静态库中删除指定的可重定位目标文件
$ ar d /usr/aarch64-linux-gnu/lib/libc.a printf.o scanf.o
4)查看ar
为可重定位目标文件中的符号创建的索引
$ nm --print-armap libtest.a
Archive index:
_Z3sumii in sum.o
_Z4funcv in test.o
sum.o:
0000000000000000 T _Z3sumii
test.o:
U g_val_1
U g_val_2
0000000000000000 T _Z4funcv
如何使用静态库
1)查看源文件的源码
$ cat sum.cpp
int sum(int a, int b)
return a + b;
$ cat test.cpp
extern int g_val_1;
extern int g_val_2;
void func()
g_val_1 *= 2;
g_val_2 *= 2;
$ cat main.cpp
#include <stdio.h>
int g_val_1;
int g_val_2 = 3;
void func();
int main()
printf("original value: g_val_1=%d, g_val_2=%d\\n", g_val_1, g_val_2);
func();
printf("now value: g_val_1=%d, g_val_2=%d\\n", g_val_1, g_val_2);
return 0;
2)生成可重定位目标文件
$ g++ -c test.cpp sum.cpp
注:生成可重定位目标文件分别为test.o
和sum.o
。
3)生成静态库
$ ar rs libtest.a test.o sum.o
4)使用静态库
方式1:
# main 可以直接加载到内存并运行,在加载时无需更进一步的链接
$ g++ -o main main.cpp --static ./libtest.a
方式2:
# main_2 可以直接加载到内存并运行,在加载时无需更进一步的链接
$ g++ -o main_2 main.cpp --static -L. -ltest
方式3:
# main_3 在加载时需要更进一步的链接
$ g++ -o main_3 main.cpp ./libtest.a
-
注:
-
--static
选项指示编译器驱动程序,链接器应该构建一个完全链接的可执行目标文件,它可以直接加载到内存并运行,在加载时无需更进一步的链接。-
-ltest
是libtest.a
的缩写。-
-L.
指示链接器在当前目录下查找libtest.a
。
5)运行可执行目标文件
$ ./main
original value: g_val_1=0, g_val_2=3
now value: g_val_1=0, g_val_2=6
$ ./main_2
original value: g_val_1=0, g_val_2=3
now value: g_val_1=0, g_val_2=6
$ ./main_3
original value: g_val_1=0, g_val_2=3
now value: g_val_1=0, g_val_2=6
如果你觉得本文对你有所帮助,欢迎关注公众号,支持一下!
以上是关于计算机系统篇之链接:静态链接(上)的主要内容,如果未能解决你的问题,请参考以下文章