




免费预览已结束,剩余1页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C+编译器与链接器工作原理1. 几个概念1)编译:把源文件中的源代码翻译成机器语言,保存到目标文件中。如果编译通过,就会把CPP转换成OBJ文件。2)编译单元:根据C+标准,每一个CPP文件就是一个编译单元。每个编译单元之间是相互独立并且互相不可知。3)目标文件:编译所生成的文件,以机器码的形式包含了编译单元里所有的代码和数据。 还有一些其他信息,如未解决符号表,导出符号表和地址重定向表等。目标文件是以二进制的形式存在的。根据C+标准,一个编译单元(Translation Unit)是指一个.cpp文件以及这所include的所有.h文件,.h文件里面的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,后者拥有PE(Portable Executable,即Windows可执行文件)文件格式,并且本身包含的就是二进制代码,但是不一定能执行,因为并不能保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方式编译完毕后,再由链接器进行链接成为一个.exe或.dll文件。2. 分析编译的过程源文件:A.cppint n = 1;void FunA() +n;目标文件:A.obj偏移量 内容 长度0x0000 n 40x0004 FunA ?注意:这只是说明,与实际目标文件的布局可能不一样,?表示长度未知,目标文件的各个数据可能不是连续的,也不一定是从0x0000开始。FunA函数的内容可能如下:0x0004 inc DWORD PTR0x00000x00? ret这时+n已经被翻译成inc DWORD PTR0x0000,也就是说把本单元0x0000位置的一个DWORD(4字节)加1。源文件:B.cppextern int n;void FunB() +n;目标文件:B.obj偏移量 内容 长度0x0000 FunB ?这里为什么没有n的空间呢,因为n被声明为extern,这个extern关键字就是告诉编译器n已经在别的编译单元里定义了,在这个单元里就不要定义了。由于编译单元之间是互不相关的,所以编译器就不知道n究竟在哪里,所以在函数FunB就没有办法生成n的地址,那么函数FunB中就是这样的:0x0000 inc DWORD PTR?0x00? ret那怎么办呢?这个工作就只能由链接器来完成了。为了能让链接器知道哪些地方的地址没有填好(也就是?),那么目标文件中就要有一个表来告诉链接器,这个表就是“未解决符号表”,也就是unresolved symbol table。同样,提供n的目标文件也要提供一个“导出符号表”也就是exprot symbol table,来告诉链接器自己可以提供哪些地址。 到这里我们就已经知道,一个目标文件不仅要提供数据和二进制代码外,还至少要提供两个表:未解决符号表和导出符号表,来告诉链接器自己需要什么和自己能提供些什么。那么这两个表是怎么建立对应关系的呢?这里就有一个新的概念:符号。在C/C+中,每一个变量及函数都会有自己的符号,如变量n的符号就是n,函数的符号会更加复杂,假设FunA的符号就是_FunA(根据编译器不同而不同)。A.obj的导出符号表符号 地址n 0x0000_FunA 0x0004A.obj的未解决符号表为空(因为它没有引用别的编译单元里的东西)B.obj的导出符号表符号 地址_FunB 0x0000B.obj的未解决符号表符号 地址n 0x0001这个表告诉链接器,在本编译单元0x0001位置有一个地址,该地址不明,但符号是n。在链接的时候,链接在B.obj中发现了未解决符号,就会在所有的编译单元中的导出符号表去查找与这个未解决符号相匹配的符号名,如果找到,就把这个符号的地址填到B.obj的未解决符号的地址处。如果没有找到,就会报链接错误。在此例中,在A.obj中会找到符号n,就会把n的地址填到B.obj的0x0001处。 但是,这里还会有一个问题,如果是这样的话,B.obj的函数FunB的内容就会变成inc DWORD PTR0x000(因为n在A.obj中的地址是0x0000),由于每个编译单元的地址都是从0x0000开始,那么最终多个目标文件链接时就会导致地址重复。所以链接器在链接时就会对每个目标文件的地址进行调整。在这个例子中,假如B.obj的0x0000被定位到可执行文件的0x00001000上,而A.obj的0x0000被定位到可执行文件的0x00002000上,那么实现上对链接器来说,A.obj的导出符号地地址都会加上0x00002000,B.obj所有的符号地址也会加上0x00001000。这样就可以保证地址不会重复。 既然n的地址会加上0x00002000,那么FunA中的inc DWORD PTR0x0000就是错误的,所以目标文件还要提供一个表,叫地址重定向表,address redirect table。3. 总结一下:目标文件至少要提供三个表:未解决符号表,导出符号表和地址重定向表。(1)未解决符号表:列出了本单元里有引用但是不在本单元定义的符号及其出现的地址。(2)导出符号表:提供了本编译单元具有定义,并且可以提供给其他编译单元使用的符号及其在本单元中的地址。(3)地址重定向表:提供了本编译单元所有对自身地址的引用记录。 链接器的工作顺序:当链接器进行链接的时候,首先决定各个目标文件在最终可执行文件里的位置。然后访问所有目标文件的地址重定义表,对其中记录的地址进行重定向(加上一个偏移量,即该编译单元在可执行文件上的起始地址)。然后遍历所有目标文件的未解决符号表,并且在所有的导出符号表里查找匹配的符号,并在未解决符号表中所记录的位置上填写实现地址。最后把所有的目标文件的内容写在各自的位置上,再作一些另的工作,就生成一个可执行文件。说明:实现链接的时候会更加复杂,一般实现的目标文件都会把数据,代码分成好向个区,重定向按区进行,但原理都是一样的。明白了编译器与链接器的工作原理后,对于一些链接错误就容易解决了。4. 下面再看一看C/C+中提供的一些特性extern:这就是告诉编译器,这个变量或函数在别的编译单元里定义了,也就是要把这个符号放到未解决符号表里面去(外部链接)。static:如果该关键字位于全局函数或者变量的声明前面,表明该编译单元不导出这个函数或变量,因些这个符号不能在别的编译单元中使用(内部链接)。如果是static局部变量,则该变量的存储方式和全局变量一样,但是仍然不导出符号。 默认链接属性:对于函数和变量,默认链接是外部链接,对于const变量,默认内部链接。外部链接的利弊:外部链接的符号在整个程序范围内都是可以使用的,这就要求其他编译单元不能导出相同的符号(不然就会报duplicated external symbols)。内部链接的利弊:内部链接的符号不能在别的编译单元中使用。但不同的编译单元可以拥有同样的名称的符号。为什么头文件里一般只可以有声明不能有定义:头文件可以被多个编译单元包含,如果头文件里面有定义的话,那么每个包含这头文件的编译单元都会对同一个符号进行定义,如果该符号为外部链接,则会导致dupli
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 体外诊断创新技术-洞察及研究
- mri技术实习个人工作总结
- 二零二五年度创新土地流转合同
- 2025版汽车融资租赁合同范本(含维修保养)
- 2025版酒店安保与客房保洁服务全面合作协议
- 二零二五年度KTV装修工程款项支付与结算合同
- 2025版绿色建筑别墅自建房施工合同规范文本
- 二零二五年度LED灯珠LED照明行业战略合作购销合同
- 2025版彩钢瓦施工材料采购与质量控制协议
- 二零二五年度LED灯珠节能环保购销合作协议
- 基坑围护质量监理评估报告
- (三四级)农业经理人复习阿备考题库及答案(含理论和实操)
- (完整版)英语26个字母测试题
- 境外安全管理培训(海外)课件
- 塔吊基础沉降观测记录
- 教师职业道德(高职)PPT完整全套教学课件
- GB/T 12325-2008电能质量供电电压偏差
- CB/T 702-1992船用柴油机铸铁气缸套技术条件
- 埃美柯阀门检验报告汇总-391黄铜调节阀
- 函数的奇偶性 省赛一等奖 公开课教学设计
- YYT 1182-2020 核酸扩增检测用试剂(盒)
评论
0/150
提交评论