ZHCADC4A September 2011 – March 2014
在 Linux 中,外部符号通常具有 STV_DEFAULT 可见性,因此,除非另有声明,否则会受制于占先。这通常会导致对几乎所有对变量(包括在同一模块中定义的变量)的引用都采用基于 GOT 的寻址。换句话说,Linux 模块需要将所有对 extern 变量的引用都视为是导入的,即使它们不是导入的。为避免由此带来的性能损失,可执行文件采用了特殊约定,该约定允许可执行文件进行规避。
可执行文件可以选择将对变量的任何引用视为自带引用(即在可执行文件中定义的引用),从而允许编译器生成高效的 DP 相对寻址。在静态链接时,任何最终要导入的变量都会在可执行文件中获得重复定义。在动态加载时,重复定义会占先库中的原始定义,并且任何初始化值都会从占先定义复制到新定义。
重复定义的大小由源定义的 st_size 字段指定。重复定义的最小对齐方式如下所示:
(直观上,这定义了重复对象至少与原始对象一样对齐,最多为其所需的最大可能对齐。)
创建过程映像时,存储在原始符号中的任何初始值都必须传播到副本。R_C6000_COPY 重定位可用于该目的。连接器使用 R_C6000_COPY 来标记可执行文件中的重复定义。在加载时,动态加载器在库中找到所引用的符号,并将该位置处的数据复制到可执行文件中的重复定义。
这样,可执行文件就不会因动态链接而受影响。相反,影响是由库承担的,库必须假设其所有外部变量都是导入的,因为占先,库无论如何都必须这样做。