Oracle® Solaris 11.2 链接程序和库指南

退出打印视图

更新时间: 2014 年 7 月
 
 

与位置无关的代码

动态可执行文件中的代码通常是位置相关的,并且与内存中的某个固定地址相关联。相反,共享目标文件可装入不同进程中的不同地址。位置无关代码不与特定地址关联。这种无关性允许在每个使用此类代码的进程中的不同地址有效地执行代码。建议在创建共享目标文件时使用与位置无关的代码。

使用 –K pic 选项,编译器可以生成与位置无关的代码。

如果共享目标文件根据位置相关代码生成,则在运行时可能需要修改文本段。通过此修改,可以为已装入目标文件的位置指定可重定位引用。本段的重定位需要将此段重映射为可写段。这种修改需要预留交换空间,并且会形成此进程的文本段专用副本。此文本段不再供多个进程共享。通常,位置相关代码比相应的与位置无关的代码需要更多的运行时重定位。总体而言,处理文本重定位的开销可能会严重降低性能。

根据与位置无关的代码生成共享目标文件时,会通过共享目标文件数据段中的数据间接生成可重定位引用。文本段中的代码不需要进行任何修改。所有重定位更新都会应用于数据段中的相应项。有关特定间接技术的更多详细信息,请参见全局偏移表(特定于处理器)过程链接表(特定于处理器)

如果存在文本重定位,运行时链接程序便会尝试处理这些重定位。但是,某些重定位无法在运行时实现。

x64 位置相关代码序列可生成的代码只能装入内存的低 32 位。任何地址的高 32 位必须全部为零。由于共享目标文件通常装入内存高位,因此需要地址的高 32 位。这样,x64 共享目标文件中位置相关代码便无法满足重定位要求。在共享目标文件中使用此类代码会导致出现运行时重定位错误。

$ prog
ld.so.1: prog: fatal: relocation error: R_AMD64_32: file \
    libfoo.so.1: symbol (unknown): value 0xfffffd7fff0cd457 does not fit

与位置无关的代码可以装入内存中的任何区域,从而可以满足 x64 共享目标文件的要求。

这种情况不同于用于 64 位 SPARCV9 代码的缺省 ABS64 模式。这种位置相关代码通常兼容整个 64 位地址范围。因此,位置相关代码序列可以存在于 SPARCV9 共享目标文件中。针对 64 位 SPARCV9 代码使用 ABS32 模式或 ABS44 模式仍会导致无法在运行时解析的重定位。但是,这两种模式都需要运行时链接程序对文本段进行重定位。

无论运行时链接程序功能如何,也无论重定位要求的差异如何,共享目标文件都应该使用与位置无关的代码生成。

可以根据文本段确定需要重定位的共享目标文件。以下示例使用 elfdump(1) 确定是否存在 TEXTREL 项动态项。

$ cc -o libfoo.so.1 -G -R. foo.c
$ elfdump -d libfoo.so.1 | grep TEXTREL
    [9]  TEXTREL       0

注 - TEXTREL 项的值无关紧要。共享目标文件中存在此项表示存在文本重定位。

要防止创建包含文本重定位的共享目标文件,可使用链接编辑器的 –z text 标志。此标志会导致链接编辑器生成指示将位置相关代码源用作输入的诊断。以下示例显示位置相关代码如何导致无法生成共享目标文件。

$ cc -o libfoo.so.1 -z text -G -R. foo.c
Text relocation remains                       referenced
  against symbol                  offset      in file
foo                                 0x0         foo.o
bar                                 0x8         foo.o
ld: fatal: relocations remain against allocatable but \
non-writable sections

因为通过 foo.o 文件生成了位置相关代码,因此将根据文本段生成两个重定位。如有可能,这些诊断会指明执行重定位所需的任何符号引用。在这种情况下,将根据符号 foobar 进行重定位。

如果包括手写汇编程序代码,但不包括相应的位置无关原型,则在共享目标文件中也会出现文本重定位。


注 - 可能需要使用一些简单的源文件进行实验,以确定启用位置无关性的编码序列。请使用编译器功能来生成中间汇编程序输出。