• Chap-4 Section 4.3 COMMON块


    4.3 COMMON块
    如果一个弱符号定义在多个目标文件中,而它们的类型又不同,怎么办?目前的链接器
    类型并不支持符号的类型,即变量类型对于链接器而言是透明的,它只知道一个名字,并
    不知道类型是否一致,那么当我们定义的多个符号类型不一致时,链接器该怎么处理呢?
    主要分三种情况:
    1.两个或者两个以上的强符号类型不一致
    2.有一个强符号,其他都是弱符号,出现类型不一致
    3.两个或者两个以上弱符号类型不一致

    对于第一种情况而言,定义多个强符号本身就是违法的,链接器会报符号多重定义错误,
    链接器处理的就是后两种情况。

    事实上,现在的编译器和链接器都支持一种叫COMMON块的机制,该机制最早来源于Fortan,
    早期的Fortan没有动态分配空间的机制,程序员必须事先声明所需要的临时使用空间的大小,
    Fortan把这种临时空间叫COMMON块,当不同的目标文件需要的COMMON块空间大小不一致时,
    以最大的那块为准。

    现在的链接器在处理弱符号的时候,采用的就是与COMMON块一样的机制,我们以实例来说明
    该机制。
    假设有如下两个c文件:
    //weak-s1.c
    int var;
    void f();
    int main() {
    var = 12;
    f();
    }

    //weak-s2.c
    double var;
    void f() {
    var = 321;
    }

    将这两个c文件链接成为最终的目标文件test,我们用readelf -s test读取目标文件的
    符号表,如图4.2.12所示:


    ***图4.2.12***
    从图中可以看出,变量var的最终大小为8个字节,所在段的下标为25,我们再用readelf -S test
    读取目标文件的段表,如图4.2.13所示,下标为25的段正好是.bss段。


    ***图4.2.13***

    在单个目标文件中,比如在weak-s1.o中,为什么不直接把未初始化的全局变量也当作
    未初始化的局部静态变量一样处理,为它在.bss段分配空间,而是将其标记为一个COMMON
    类型的变量?
    通过了解编译器处理多个弱符号的过程,我们可以知道,当编译器将一个编译单元编译成
    目标文件后,如果该编译单元包含了弱符号,那么该弱符号最终所占空间的大小在此时是
    未知的,因为可能在其他编译单元中,该符号所占的空间比本编译单元该符号所占的空间
    大,所以编译器此时无法为该弱符号在.bss段分配空间,因为所需要的空间大小未知,但是
    链接器在链接过程中可以确定弱符号的大小,因为当链接器读取所有输入目标文件后,任何
    一个弱符号的最终大小都可以确定,所以它可以在最终输出文件的.bss段为其分配空间,
    所以总体来看,未初始化的全局变量最终还是被放在.bss段的。
    比如,我们单独对weak-s1.c编译,然后用readelf -S weak-s1.o查看该目标文件的段表,如
    图4.2.14所示:


    ***图4.2.14***
    图中.bss段的大小为0,由此说明编译单元为未把该未初始化的全局变量放在.bss段。

  • 相关阅读:
    jenkins 简单实现php集成上线部署
    关于PHP7
    关于版本迭代的那些事
    confirmit中手机端不能直接给input设置disabled属性
    confirmit中Html Styles有一处bug(或者说是一个坑)
    vsCode快捷键大全
    vscode打不开文件夹或文件夹未响应
    js中排序方法sort() 和 reverse()
    js最简单的编写地点
    js对象转换为json格式时,js对象属性中有值为null和undefined注意事项
  • 原文地址:https://www.cnblogs.com/miaoyong/p/3508082.html
Copyright © 2020-2023  润新知