段声明。
映射指令。
节到段的排序。
大小符号声明。
文件控制指令。
每个指令可以跨越多行,并且可以包含任意数量的空格(包括换行符),但空格后面要跟随一个分号。
通常,段声明后面跟有映射指令。您可以声明段,然后定义节成为该段的一部分所依据的标准。如果在未首先声明要映射到的段(内置段除外)的情况下输入映射指令或大小符号声明,则会为该段赋予缺省属性。此类段为隐式声明的段。
大小符号声明和文件控制指令可以出现在 mapfile 中的任何位置。
以下各节将针对每种指令类型进行介绍。对于所有语法讨论,以下表示法都适用。
所有项都为固定宽度,所有冒号、分号、等号和 at (@) 符号都按原样输入。
所有以斜体表示的项都是可替换的。
{ ... }* 表示“零个或多个”。
{ ... }+ 表示“一个或多个”。
[ ... ] 表示“可选”。
section_names 和 segment_names 遵守与 C 标识符相同的规则,其中将句点 (.) 视为一个字母。例如,.bss 为合法名称。
section_names、segment_names、file_names 和 symbol_names 区分大小写。其他名称不区分大小写。
除编号之前、名称或值的中间位置以外,空格或者换行符可以出现在其他任何位置。
以 # 开始并以换行符结束的注释可以出现在任何允许出现空格的位置。
段声明可在输出文件中创建新段,或更改现有段的属性值。现有段可以是您先前定义的段,也可以是下面即将介绍的四个内置段之一。
段声明的语法如下:
segment_name = {segment_attribute_value}*;
对于每个 segment_name,可以按任意顺序指定任何数量的 segment_attribute_values,但每个值都要由空格进行分隔。每个段属性只能有一个属性值。下表列出了段属性及其有效值。
表 E-1 Mapfile 段属性
|
有四个内置段,其缺省属性值如下所示:
text-LOAD,?RX,未指定 virtual_address、physical_address 或 length,按 CPU 类型将 alignment 值设置为缺省值。
data-LOAD,?RWX,未指定 virtual_address、physical_address 或 length,按 CPU 类型将 alignment 值设置为缺省值。
bss-已禁用,LOAD,?RWX,未指定 virtual_address、physical_address 或 length,按 CPU 类型将 alignment 值设置为缺省值。
note-NOTE。
缺省情况下,禁用 bss 段。任何类型为 SHT_NOBITS(此类型为节的唯一输入)的节都是在 data 段中捕获的。有关 SHT_NOBITS 节的完整说明,请参见表 7-5。最简单的 bss 声明足以创建 bss 段。
bss =;
任何 SHT_NOBITS 节都是由此段(而不是 data 段)捕获的。此段采用最简单的形式,并且使用与应用于任何其他段相同的缺省值对齐。还可以声明其他既可创建段又可为指定属性赋值的段属性。
链接编辑器的行为方式就好像在读入 mapfile 之前已经声明了这些段。请参见Mapfile 缺省选项。
输入段声明时,请注意以下事项:
数字可以是十六进制、十进制或八进制,所遵守的规则与 C 语言中的规则相同。
V、P、L、R 或 A 和数字之间不允许有空格。
segment_type 值可以是 LOAD、NOTE、NULL 或 STACK。如果未指定值,则缺省的段类型为 LOAD。
segment_flags 的值包括 R、W、X 和 O,分别表示可读、可写、可执行以及顺序。问号 (?) 与构成 segment_flags 值的单个标志之间不允许有空格。
LOAD 段的 segment_flags 值缺省为 RWX。
不能为 NOTE 段指定除 segment_type 以外的任何段属性值。
允许有一个值为 STACK 的 segment_type。只能指定从 segment_flags 中选择的段访问要求。
隐式声明的段缺省为:segment_type 值为 LOAD,segment_flags 值为 RWX,缺省的 virtual_address、physical_address 和 alignment 值,并且没有 length 限制。
注 - 链接编辑器基于先前段的属性值计算当前段的地址和长度。
LOAD 段可以具有显式指定的 virtual_address 值或 physical_address 值,以及段的最大 length 值。
如果某个段的 segment_flags 值为 ?,并且后面未跟任何内容,则该值缺省为不可读、不可写并且不可执行。
alignment 值用于计算段开头的虚拟地址。此对齐值仅影响指定了对齐的段。其他段仍采用缺省的对齐,除非更改了它们的 alignment 值。
如果有任何 virtual_address、physical_address 或 length 属性值未设置,链接编辑器将在创建输出文件时计算这些值。
如果没有为段指定 alignment 值,则对齐值将设置为内置的缺省值。此缺省值因 CPU 的不同而异,甚至也可能因软件修订版的不同而异。
如果同时为段指定了 virtual_address 和 alignment 值,则 virtual_address 值优先。
如果为段指定了 virtual_address 值,则程序头中的 alignment 字段将包含缺省的对齐值。
如果为段设置了 rounding 值,则此段的虚拟地址将舍入为下一个符合给定值的地址。该值只影响指定了它的段。如果没有给定值,将不执行任何舍入操作。
注 - 如果指定了 virtual_address 值,段将放置在该虚拟地址处。对于系统内核,此方法可生成正确的结果。对于通过 exec(2) 启动的文件,此方法将生成错误的输出文件,因为段与其页边界的相对偏移量是错误的。
使用 ?E 标志可以创建空段。此空段没有关联的节。此段可为 LOAD 段或 NULL 段。只能为可执行文件指定空 LOAD 段。这些段必须有指定的大小和对齐方式。这些段将导致在进程启动时创建内存保留空间。空的 NULL 段可添加程序头项,后处理实用程序可以使用这些程序头项。这些段不应指定任何附加属性。LOAD 段和 NULL 段允许具有多个定义。
使用 ?N 标志可以控制是否将 ELF 头和任何程序头作为第一个可装入段的一部分包括在内。缺省情况下,ELF 头和程序头包括在第一个段内。这些头中的信息通常由运行时链接程序用在映射的映像中。使用 ?N 选项将导致从第一个段的第一个节开始计算映像的虚拟地址。
使用 ?O 标志可以控制输出文件中各节的顺序。此标志用于与编译器的 -xF 选项一起使用。使用 -xF 选项编译文件时,该文件中的每个函数将放置在与 .text 节具有相同属性的单独节中。这些节称为 .text%function_name。
例如,使用 -xF 选项编译包含 main()、foo() 和 bar() 这三个函数的文件时,会生成一个可重定位的目标文件,并会将三个函数的文本放置在名为 .text%main、.text%foo 和 .text%bar 的节中。由于 -xF 选项强制实行每节一个函数,因此使用 ?O 标志控制各节的顺序实际上是控制函数的顺序。
请考虑以下用户定义的 mapfile。
text = LOAD ?RXO; text: .text%foo; text: .text%bar; text: .text%main;
第一个声明将 ?O 标志与缺省文本段进行关联。
如果源文件中函数定义的顺序为 main、foo 和 bar,则最终的可执行文件所包含的函数顺序为 foo、bar 和 main。
对于具有相同名称的静态函数,还必须使用文件名。?O 标志强制按 mapfile 中的要求对节进行排序。例如,如果静态函数 bar() 存在于 a.o 和 b.o 文件中,并且要将 a.o 文件中的 bar() 函数放置在 b.o 文件中的 bar() 函数之前,则 mapfile 项将显示为:
text: .text%bar: a.o; text: .text%bar: b.o;
虽然此语法允许具有以下项:
text: .text%bar: a.o b.o;
但此项不能保证将 a.o 文件中的 bar() 函数放置在 b.o 中的 bar() 之前。由于结果不可靠,因此建议不要使用第二种格式。
映射指令指示链接编辑器如何将输入节映射到输出段。本质上,就是指定要映射到的段,并指明节为了映射到指定的段而必须具备的属性。节为映射到特定段而必须具备的 section_attribute_values 集合称为此段的入口条件。节必须完全满足段的入口条件,才能置于输出文件的指定段中。
映射指令的语法如下:
segment_name : {section_attribute_value}* [: {file_name}+];
对于 segment_name,可以按任意顺序指定任何数量的 section_attribute_values,其中每个值由空格进行分隔。每个节属性最多允许具有一个节属性值。您还可以通过 file_name 声明指定节必须来自某个特定的 .o 文件。下表列出了节属性及其有效值。
表 E-2 节属性
|
输入映射指令时,请注意以下几点:
最多只能从上面列出的 section_types 中选择一个 section_type。上面列出的 section_types 是内置类型。有关 section_types 的更多信息,请参见节。
section_flags 值包括 A、W 和 X,分别表示可分配、可写和可执行。如果个别标志之前加有一个叹号 (!),则链接编辑器将检查是否未设置此标志。构成 section_flags 值的问号、叹号和各个标志之间不允许有空格。
file_name 可以是任何形式为 *filename 或 archive_name(component_name) 的合法文件名,例如,/lib/libc.a(printf.o)。链接编辑器不会检查文件名的语法。
如果 file_name 的形式为 *filename,链接编辑器将决定命令行中文件的 basename(1)。此基本名称用于与指定的 file name 进行匹配。换言之,mapfile 中的 filename 只需要与命令行中文件名的最后一部分匹配即可。请参见映射示例。
如果在链接编辑过程中使用 -l 选项,并且 -l 选项后的库位于当前目录中,则必须在库的前面添加 ./ 或整个路径名(在 mapfile 中),以便创建匹配。
对于特殊的输出段,可能显示多个指令行。例如,以下指令集是合法的:
S1 : $PROGBITS; S1 : $NOBITS;
为段输入多个映射指令行是为节属性指定多个值的唯一方法。
一个节可以与多个入口条件匹配。在这种情况下,将使用 mapfile 中第一个遇到的具有该入口条件的段。例如,如果 mapfile 显示为:
S1 : $PROGBITS; S2 : $PROGBITS;
则 $PROGBITS 节将映射到 S1 段。
使用以下表示法可以指定节在段中放置的顺序:
segment_name | section_name1; segment_name | section_name2; segment_name | section_name3;
以上述形式命名的节将按照它们在 mapfile 中列出的顺序放置在任何未命名的节之前。
使用大小符号声明,可以定义新的全局绝对符号,以代表指定段的大小(以字节为单位)。可以在目标文件中引用此符号。大小符号声明的语法如下:
segment_name @ symbol_name;
symbol_name 可以是任何合法的 C 标识符。链接编辑器不会检查 symbol_name 的语法。
使用文件控制指令,可以指定共享目标文件中有哪些版本定义在链接编辑期间可用。文件控制定义的语法如下:
shared_object_name - version_name [ version_name ... ];
version_name 是指定 shared_object_name 中包含的版本定义名称。