链接程序和库指南

生成输出文件

在完成输入文件处理和符号解析并且没有出现致命错误后,链接编辑器将生成输出文件。链接编辑器首先生成完成输出文件必需的其他节。这些节包括所有输入文件中的符号表,这些符号表包含局部符号定义以及已解析的全局符号和弱符号信息。

此外,还包括运行时链接程序需要的任何输出重定位和动态信息节。确定所有输出节信息后,将计算输出文件总大小。然后,相应地创建输出文件映像。

创建动态可执行文件或共享库时,通常会生成两个符号表。.dynsym 表及其关联的字符串表 .dynstr 包含寄存器符号、全局符号、弱符号和节符号。这些节成为在运行时作为进程映像一部分映射的 text 段的一部分。 请参见 mmap(2)。使用此映射,运行时链接程序可以读取这些节,以便执行任何必需的重定位。

.symtab 表及其关联的字符串表 .strtab 包含在输入文件处理过程中收集的所有符号。这些节不能作为进程映像的一部分进行映射。使用链接编辑器的 -s 选项或在链接编辑后使用 strip(1) 甚至可以从映像中删除这些节。

生成符号表期间,将创建保留符号。这些符号对于链接进程有特殊意义。不能在代码中定义这些符号。

_etext

文本段后面的第一个位置。

_edata

已初始化数据后面的第一个位置。

_end

所有数据后面的第一个位置。

_DYNAMIC

.dynamic 动态信息节的地址。

_END_

_end 相同。此符号具有局部范围,它与 _START_ 一起提供一种确定目标文件地址范围的方法。

_GLOBAL_OFFSET_TABLE_

对链接编辑器提供的地址表(即 .got 节)的位置无关的引用。此表由与位置无关的数据引用构造而成,这些数据引用出现在使用 -K pic 选项编译的目标文件中。 请参见与位置无关的代码

_PROCEDURE_LINKAGE_TABLE_

对链接编辑器提供了地址表(即 .plt 节)的与位置无关的引用。此表由与位置无关的函数引用构造而成,这些数据引用出现在使用 -K pic 选项编译的目标文件中。 请参见与位置无关的代码

_START_

文本段中的第一个位置。此符号具有局部范围,它与 _END_ 一起提供一种确定目标文件地址范围的方法。

生成可执行文件时,链接编辑器将查找其他符号,以定义可执行文件的入口点。如果使用链接编辑器的 -e 选项指定了一个符号,则将使用该符号。否则,链接编辑器将查找保留符号名称 _start,然后查找 main。如果这些符号都不存在,则将使用文本段的第一个地址。

标识硬件和软件功能

通常在编译时记录可重定位目标文件的硬件和软件功能。链接编辑器合并所有输入可重定位目标文件的功能来创建输出文件的最终功能节。 请参见硬件和软件功能节

此外,还可以在链接编辑器创建输出文件时定义功能。使用 mapfile 和链接编辑器的 -M 选项标识这些功能。使用 mapfile 定义的功能可以扩充或覆盖输入可重定位目标文件提供的功能。

以下各小节说明如何使用 mapfile 定义功能。

标识硬件功能

目标文件的硬件功能标识目标文件正常执行要满足的平台硬件要求。例如,要求可能是,标识需要在某些 x86 体系结构上可用的 MMXSSE 功能的代码。

可以使用以下 mapfile 语法标识硬件功能要求:


hwcap_1 = TOKEN | Vval [ OVERRIDE ];

使用一个或多个标记限定 hwcap_1 声明,这些标记是硬件功能的符号表示。此外,通过在值前面加上 V 作为前缀可以提供表示多个功能中的某个功能的数值。对于 SPARC 平台,硬件功能定义为 sys/auxv_SPARC.h 中的 AV_ 值。对于 x86 平台,硬件功能定义为 sys/auxv_386.h 中的 AV_ 值。

以下 x86 示例说明如何将 MMXSSE 声明为目标文件 foo.so.1 需要的硬件功能。


$ egrep "MMX|SSE" /usr/include/sys/auxv_386.h

#define AV_386_MMX    0x0040

#define AV_386_SSE    0x0800

$ cat mapfile

hwcap_1 = SSE MMX;

$ cc -o foo.so.1 -G -K pic -Mmapfile foo.c -lc

$ elfdump -H foo.so.1



Hardware/Software Capabilities Section:  .SUNW_cap

     index  tag               value

       [0]  CA_SUNW_HW_1     0x840  [ SSE  MMX ]

可重定位目标文件可以包含硬件功能值。链接编辑器可以合并多个输入可重定位目标文件中的任何硬件功能值。生成的 CA_SUNW_HW_1 值是对关联的输入值进行按位或运算的结果。缺省情况下,这些值与 mapfile 指定的硬件功能合并。

可以使用 OVERRIDE 关键字在 mapfile 中显式控制输出文件的硬件功能要求。OVERRIDE 关键字和硬件功能值 0 可有效地从要生成的目标文件中删除任何硬件功能要求。


$ elfdump -H foo.o



Hardware/Software Capabilities Section:  .SUNW_cap

     index  tag               value

       [0]  CA_SUNW_HW_1     0x840  [ SSE  MMX ]

$ cat mapfile

hwcap_1 = V0x0 OVERRIDE;

$ cc -o bar.o -r -Mmapfile foo.o

$ elfdump -H bar.o

$ 

运行时链接程序会针对进程可用的硬件功能验证目标文件定义的任何硬件功能要求。如果无法满足任何硬件功能要求,则不会在运行时装入该目标文件。例如,如果进程不能使用 SSE 功能,则 ldd(1) 将指示以下错误。


$ ldd prog

         foo.so.1 =>     ./foo.so.1  - hardware capability unsupported: \

                         0x800 [ SSE ]

         libc.so.1 =>    /lib/libc.so.1

利用不同硬件功能的动态库可以使用过滤器提供灵活的运行时环境。 请参见特定于硬件功能的共享库

标识软件功能

目标文件的软件功能标识对于调试或监视进程可能很重要的软件特征。目前,可识别的唯一软件功能与目标文件使用的帧指针有关。目标文件可以声明已知其帧指针的使用状态。然后,将帧指针声明为正在使用或未使用来限定此状态。

sys/elf.h 中定义的两个标志表示帧指针状态:


#define  SF1_SUNW_FPKNWN    0x001

#define  SF1_SUNW_FPUSED    0x002

可以使用以下 mapfile 语法标识这些软件功能要求:


sfcap_1 = TOKEN | Vval [ OVERRIDE ];

可以使用 FPKNWNFPUSED 标志限定 sfcap_1 声明。或者,可以使用表示这些状态的数值进行限定。

可重定位目标文件可以包含软件功能值。链接编辑器合并多个输入可重定位目标文件中的软件功能值。可按如下方法根据两个输入值计算 CA_SUNW_SF_1 的值。

表 2–1 CA_SUNW_SF_1 标志组合状态表

输入文件 1 

输入文件 2 

 

SF1_SUNW_FPKNWN SF1_SUNW_FPUSED

SF1_SUNW_FPKNWN

<unknown>

SF1_SUNW_FPKNWN SF1_SUNW_FPUSED

SF1_SUNW_FPKNWN SF1_SUNW_FPUSED

SF1_SUNW_FPKNWN

SF1_SUNW_FPKNWN SF1_SUNW_FPUSED

SF1_SUNW_FPKNWN

SF1_SUNW_FPKNWN

SF1_SUNW_FPKNWN

SF1_SUNW_FPKNWN

<unknown>

SF1_SUNW_FPKNWN SF1_SUNW_FPUSED

SF1_SUNW_FPKNWN

<unknown>

此计算方法适用于每个可重定位目标文件值和 mapfile 值。如果不存在 .SUNW_cap 节,或者此节不包含 CA_SUNW_SF_1 值,或者未设置 SF1_SUNW_FPKNWSF1_SUNW_FPUSED 标志,则目标文件的软件功能未知。

缺省情况下,使用相同的状态模型处理 mapfile 指定的任何软件功能。

可以使用 OVERRIDE 关键字在 mapfile 中显式控制输出文件的软件功能要求。OVERRIDE 关键字和软件功能值 0 可有效地从要生成的目标文件中删除任何软件功能要求。


$ elfdump -H foo.o



Hardware/Software Capabilities Section:  .SUNW_cap

     index  tag               value

       [0]  CA_SUNW_SF_1     0x3  [ SF1_SUNW_FPKNWN  SF1_SUNW_FPUSED ]

$ cat mapfile

sfcap_1 = V0x0 OVERRIDE;

$ cc -o bar.o -r -Mmapfile foo.o

$ elfdump -H bar.o

$