链接的接口--符号
链接的接口--符号
在链接中,我们将函数和变量统称为符号,每个文件都有一个相应的符号表,这个符号表记录了目标文件中的所有符号。每个符号对应了一个符号值,对于函数和变量名,符号值就是他们对应的地址。符号可能是定义在本目标文件的全局符号,在本目标文件引用的全局符号等。
符号表--》结构体数组
符号表也像段表等一样也是文件中的一个段。符号表中的一项的内容如下:
- 符号名:也是一个下标,指示该字符串在字符串表中的位置。
- 符号类型的大小:指示该符号类型的大小,比如一个double 8个字节。
- 符号类型绑定信息:4个字节,低四位表示符号类型,高位表示符号绑定信息(是否是局部符号,全局符号,强弱符号)。
- 符号所在段:如果符号在该文件中,那么该值就指示该段在段表中的下标。
当我们使用ld链接器来产生可执行文件时,它会定义一些特殊的符号。
符号修饰和函数签名
为了解决符号冲突的问题,即名称重复,在c语言中,所有的符号经过编译后,在前面加上“-”。
c++引入符号修饰或符号改编(Name Mangling),将符号按规则进行一些变化,不同编译器厂商的符号修饰方法不同。
extern "C" 关键字:C++为了与C兼容,在符号的管理上,C++有一个用来声明或者定义一个C的符号的extern "C"用法。
c++ 编译器会将extern "C"关键字中的内容当作C语言代码处理,C++的符号修饰就不会起作用。
强符号弱符号
对于c和c++来说,编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号。
针对强弱符号的概念,链接器就会按如下规则处理:
- 不允许强符号多次定义
- 如果一个符号在某个目标文件中是强符号,在其他文件中都是弱符号,那么选择强符号
- 如果一个符号在所有目标文件中都是弱符号,那么选择其中占用空间最大的那个
(static 仅本文件使用的全局 ,extern 具有外部链接性,全局变量通过链接属于整个工程。函数具有全局性)
强引用和弱引用
目前我们所看到的对外部目标文件的符号引用在目标文件被最终链接成可执行文件时,它们必须要被正确决议,如果没有找到该符号的定义,链接器就会报符号未定义错误,这种被称为强引用( Strong Reference)。与之相对应还有一种弱引用(WeakReference),在处理弱引用时,如果该符号有定义,则链接器将该符号的引用决议;如果该符号来被定义,则链接器对于该引用不报错。链接器处理强引用和弱引用的过程几乎--样,只是对于未定义的弱引用,链接器不认为它是一个错误。一般对于未定义的弱引用,链接器默认其为0,或者是一个特殊的值,以便于程序代码能够识别。这种弱符号和弱引用对于库来说十分有用,比如库中定义的弱符号可以被用户定义的强符号所覆盖,从而使得程序可以使用自定义版本的库函数,或者程序可以对某些扩展功能模块的引用定义为弱引用,当我们将扩展模块与程序链接在一起时,功能模块就可以正常使用,如果我们去掉了某些功能模块,那么程序也可以正常链接,只是缺少了相应的功能,这使得程序的功能更加容易裁剪和组合。
COMMON 块
由于弱符号机制允许同一个符号的定义存在于多个文件中,所以可能会导致的一个问题是:如果一个弱符号定义在多个目标文件中,而它们的类型又不同,怎么办?目前的链接器本身并不支持符号的类型,即变量类型对于链接器来说是透明的,它只知道符号的名字,并不知道类型是否一致。直到链接器最后才会决定了弱符号的类型,以及分配空间大小,才能放入bss段。
这也解释了为什么不把未初始化的全局变量也当作未初始化的局部静态变量在.bss 段中分配空间,因为在编译的时候全局变量的所占大小是未知的。在链接之后,未初始化的全局变量最终还是放在.bss段里的。
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号