- 编译单元
每一个cpp文件就是一个编译单元。
ps:每个编译单元之间是相互独立并且互相不可知。 - 目标文件
由编译所生成的文件,以机器码的形式包含了编译单元里所有的代码和数据,还有未解决符号表,导出符号表等。目标文件是以二进制的形式存在的。 - 编译器
将程序中的个各类变成.obj文件 - 连接器
将.obj文件变成可执行的exe文件 - 连接器工作原理
一个函数或变量的声明,实际上就是在向C编译器承诺:(这个函数或变量已经在程序的别处定义了),而连接器的工作就是兑现这个承诺。连接器会根据目标文件中提供的"未解决符号表"了解哪些的地址没有提供好,通过"导出符号表"提供具体的地址。
ps:好啦,到这里我们就已经知道,一个目标文件不仅要提供数据和二进制代码外,还至少要提供两个表:“未解决符号表”,“导出符号表”。来告诉连接器自己需要什么和自己能提供什么。你以为这就完事了? No,No,No。每个编译单元的地址都是从0x0000开始,那么最终多个目标文件连接时就会导致地址重复。所以连接器在连接时就会对每个目标文件的地址进行调整。举个栗子:假如B.obj的0x0000被定义到可执行文件的0x00001000上,而A.obj的0x0000被定义到可执行文件的0x00002000上,那么实现上对连接器来说,A.obj的导出符号地址都会加上0x00002000,B.obj的导出符号地址都会加上0x00001000。这样就可以保证地址不会重复。我们修改了.obj的导出符号地址,那么就需要目标文件再提供一个表,叫地址重定向表。 - 连接器的工作顺序
当连接器进行连接时,会先确定目标文件在可执行文件里的位置,然后访问目标文件的地址重定向表,对记录的地址进行重定向。然后遍历未解决符号表,在导出符号表里查找匹配的符号,并填写相应的实现地址。最后把所有的目标文件内容写在各自的位置上。然后进行一些操作,就生成了可执行文件。
静态库,当程序编译时,静态库会被连接到目标代码中,程序运行时不再需要该静态库。
动态库,当程序运行时才会被载入,因此在程序运行时还有要动态库存在。