库是写好的现有的,成熟的,可以复⽤的代码。比如,在平时编写代码时,许多函数都是通用的,如果没有库,人们在编写代码时就需要将这些通用的函数都自己实现一份。将这些通用的函数都编写到一起,这样,就形成了一个库。
在Linux下:
在windows下:
动静态库中,要不要包含main函数??
ar表示将文件进行归档,归档后的文件叫libmyc.a,即一个静态库,这个静态库的库名叫“myc”。-rc表示,如果将.o文件进行打包时,有新增的文件,则直接打包进去即可(c),如果.o文件的内容更新了,直接将更新后的.o文件对包中的对应源文件进行替换即可(r)。简单讲就是:需要替换的就替换,有需要一起打包的新源文件就直接一起打包



-L.表示在当前路径下查找库文件,-lmyc表示要链接的库叫"myc"

如果要链接任何非c/c++标准库,都需要指明-L -l,意思是要指明在哪里查找库,要链接的库叫什么
为了方便对库文件进行管理,可以将需要用到的库文件管理在“lib”目录下


链接完后,就形成了可执行程序:

库也是被安装到系统中的。linux下,库在/usr/lib64路径下,头文件在/usr/include路径下 对于库的安装,就是将库的头文件与库文件拷贝到系统指定目录下,在链接时,只需要“-l+库名”就可以了。
制作动态库与静态库类似,也是将文件打包成库。
-fPIC::产⽣位置⽆关码(positionindependentcode)
-shared:表示形成的是动态库


形成静态库需要使用到ar指令,因为静态库是一个归档文件,而动态库不是
对库进行链接会发现,能生成指定的可执行程序,但是依然会报找不到库的错误

检查可执行程序链接的库,发现,真的是无法找到库

为什么会这样??
静态库为什么没有这个问题?
怎么解决:
因为系统是去指定的路径下找库,所以第一种方法

软链接

OS除了在指定路径下查找动态库,也会在该环境变量下查找:LDLIBRARYPATH
该环境变量通常是空的

将动态库的路径导入到这个环境变量中:


一旦关闭了shell,导入的这个环境变量就没了

更改系统的配置文件
这个路径下用于存放 动态链接器(ld.so) 的额外配置文件,这些文件告诉系统在哪些目录中搜索共享库(.so 文件)。

创建一个我们自己的conf配置文件,并将动态库路径写进去

使用这个指令重新加载配置文件


四种方法总结:
当动静态库同时存在时,可执行程序会链接哪个库呢?

链接任何库之前,库都必须存在。像上面动静态库都存在,想链接静态库就需要使用-static ,但前提条件是静态库必须存在
gcc/g++默认使用动态库 在Linux系统下,默认情况安装的大部分库,默认都是优先安装动态库 库:应用程序== 1:N vs不仅仅形成可执行程序,也能形成静态库
形成可执行程序的过程:预处理、编译、汇编、链接。但其实归根揭底就两步:编译、链接

形成的.o文件全称叫做:可重定向目标文件
进行链接其实就是将所有.o进行链接。
为什么要先编译成.o文件?
我们知道,可执行程序是有自己固定的格式的,会分为多个模块的,比如:数据段,代码段…
动静态库、可执行程序、.o文件也是如此,它们是以一定的格式将内容放入到二进制文件中的,也就是ELF格式



我们自己的可执行程序是有上图这般的格式的
最常见的部分:
文件被编译后,代码则在代码节中,数据则在数据节中。数据节与代码节分别会占用数个section
size计算得出的是程序中几个数据节的大小
ELF形成可执⾏

Section Headers是一个数组。可以把他理解为一个线性数组,当我们要拿其中的某一个section时,就是从这个线性的数组中取出数据。

ELF格式中,有一个data节与bss节。

eadelf -h +要查看的程序

每个ELF区域与文件的偏移量之间存在联系
静态库是如何形成可执行程序的:
对.o文件进行反汇编,我们看到callq的地址是00 00 00 00,这是因为编译器编译.c文件时不知道调用函数的地址是多少,所以先暂时设为0

尽管调用了一个没有声明,没有函数体的函数的函数,但是编译依然没有报错。这就证明了编译器在编译.c文件时,是不认识调用的函数的,不知道函数的真实地址是多少。

那这个地址会在什么时候进行填充修正呢?
printf底层实际上调用的就是puts函数

观察hello.o的符号表

当将这些.o文件进行链接时,实际上就是将文件中的这些未定义的模块去其他模块中找


当链接后,callq 00 00 00 00的地址,全都填充为具体的值了

最终: 两个 .o 的代码段合并到了⼀起,并进⾏了统⼀的编址 。链接的时候,会修改 .o 中没有确定的函数地址,在合并完成之后,进⾏相关 call 地址,完成代码调 ⽤
静态链接就是把库中的.o进⾏合并,和上述过程⼀样
所以链接其实就是将编译之后的所有⽬标⽂件连同⽤到的⼀些静态库运⾏时库组合,拼装成⼀个独⽴ 的可执⾏⽂件。其中就包括我们之前提到的地址修正,当所有模块组合在⼀起之后,链接器会根据我 们的.o⽂件或者静态库中的重定位表找到那些需要被重定位的函数全局变量,从⽽修正它们的地址。这 其实就是静态链接的过程。
所以,链接过程中会涉及到对.o中外部符号进⾏地址重定位
ELF程序如何加载到内存的,ELF如何转换成进程的(逻辑地址,物理地址),虚拟地址空间:
一个可执行程序,如果没有被加载到内存中,该可执行程序有没有地址?
当要查找某个模块时,只需要根据起始地址和偏移量就能查找到。
磁盘上的地址叫做“逻辑地址”。
后面优化成:每个程序只要一个segment,且起始地址为0,每个模块的偏移量都是根据这个一个segment来说的

当代计算机编址:平坦模式编址
这些地址也叫做线性地址
这前讲到线性地址的地方是关于程序的虚拟地址空间部分。
这里关于对磁盘上的可执行程序进行编址,其实就是虚拟地址的统一编址
当文件被编译好之后,函数之间互相调用的地址就是虚拟地址了
