欢迎来到天天文库
浏览记录
ID:57863327
大小:13.68 KB
页数:6页
时间:2020-09-02
《C++编译器与连接器的工作原理.docx》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、C++编译器与链接器工作原理1.几个概念1)编译:把源文件中的源代码翻译成机器语言,保存到目标文件中。如果编译通过,就会把CPP转换成OBJ文件。2)编译单元:根据C++标准,每一个CPP文件就是一个编译单元。每个编译单元之间是相互独立并且互相不可知。3)目标文件:编译所生成的文件,以机器码的形式包含了编译单元里所有的代码和数据。还有一些其他信息,如未解决符号表,导出符号表和地址重定向表等。目标文件是以二进制的形式存在的。根据C++标准,一个编译单元(TranslationUnit)是指一个.cpp
2、文件以及这所include的所有.h文件,.h文件里面的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,后者拥有PE(PortableExecutable,即Windows可执行文件)文件格式,并且本身包含的就是二进制代码,但是不一定能执行,因为并不能保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方式编译完毕后,再由链接器进行链接成为一个.exe或.dll文件。2.分析编译的过程源文件:A.cppintn=1;voidFunA(){
3、++n;}目标文件:A.obj偏移量内容长度0x0000n40x0004FunA??注意:这只是说明,与实际目标文件的布局可能不一样,??表示长度未知,目标文件的各个数据可能不是连续的,也不一定是从0x0000开始。FunA函数的内容可能如下:0x0004incDWORDPTR[0x0000]0x00??ret这时++n已经被翻译成incDWORDPTR[0x0000],也就是说把本单元0x0000位置的一个DWORD(4字节)加1。源文件:B.cppexternintn;voidFunB(){++
4、n;}目标文件:B.obj偏移量内容长度0x0000FunB??这里为什么没有n的空间呢,因为n被声明为extern,这个extern关键字就是告诉编译器n已经在别的编译单元里定义了,在这个单元里就不要定义了。由于编译单元之间是互不相关的,所以编译器就不知道n究竟在哪里,所以在函数FunB就没有办法生成n的地址,那么函数FunB中就是这样的:0x0000incDWORDPTR[????]0x00??ret那怎么办呢?这个工作就只能由链接器来完成了。为了能让链接器知道哪些地方的地址没有填好(也就是??
5、??),那么目标文件中就要有一个表来告诉链接器,这个表就是“未解决符号表”,也就是unresolvedsymboltable。同样,提供n的目标文件也要提供一个“导出符号表”也就是exprotsymboltable,来告诉链接器自己可以提供哪些地址。到这里我们就已经知道,一个目标文件不仅要提供数据和二进制代码外,还至少要提供两个表:未解决符号表和导出符号表,来告诉链接器自己需要什么和自己能提供些什么。那么这两个表是怎么建立对应关系的呢?这里就有一个新的概念:符号。在C/C++中,每一个变量及函数都会
6、有自己的符号,如变量n的符号就是n,函数的符号会更加复杂,假设FunA的符号就是_FunA(根据编译器不同而不同)。A.obj的导出符号表符号地址n0x0000_FunA0x0004A.obj的未解决符号表为空(因为它没有引用别的编译单元里的东西)B.obj的导出符号表符号地址_FunB0x0000B.obj的未解决符号表符号地址n0x0001这个表告诉链接器,在本编译单元0x0001位置有一个地址,该地址不明,但符号是n。在链接的时候,链接在B.obj中发现了未解决符号,就会在所有的编译单元中的导
7、出符号表去查找与这个未解决符号相匹配的符号名,如果找到,就把这个符号的地址填到B.obj的未解决符号的地址处。如果没有找到,就会报链接错误。在此例中,在A.obj中会找到符号n,就会把n的地址填到B.obj的0x0001处。但是,这里还会有一个问题,如果是这样的话,B.obj的函数FunB的内容就会变成incDWORDPTR[0x000](因为n在A.obj中的地址是0x0000),由于每个编译单元的地址都是从0x0000开始,那么最终多个目标文件链接时就会导致地址重复。所以链接器在链接时就会对每个
8、目标文件的地址进行调整。在这个例子中,假如B.obj的0x0000被定位到可执行文件的0x00001000上,而A.obj的0x0000被定位到可执行文件的0x00002000上,那么实现上对链接器来说,A.obj的导出符号地地址都会加上0x00002000,B.obj所有的符号地址也会加上0x00001000。这样就可以保证地址不会重复。既然n的地址会加上0x00002000,那么FunA中的incDWORDPTR[0x0000]就是错误的,所以目标文件还要提供一个
此文档下载收益归作者所有