段声明可在输出文件中创建新段,或者更改现有段的属性值。现有段可以是指先前定义的段,也可以是随后即将介绍的四个内置段之一。
段声明的语法如下:
segment_name = {segment_attribute_value}*;
对于每个 segment_name,都可以按任意顺序指定任何数量的 segment_attribute_values,但每个值都要由空格进行分隔。每个段属性只能有一个属性值。下表列出了段属性及其有效值。
表 9–1 Mapfile 段属性
属性 |
值 |
---|---|
segment_type |
LOAD | NOTE | STACK |
segment_flags |
? [E] [N] [O] [R] [W] [X] |
virtual_address |
Vnumber |
physical_address |
Pnumber |
length |
Lnumber |
rounding |
Rnumber |
alignment |
Anumber |
有四个内置段,其缺省属性值如下所示:
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 或 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。允许具有多个此类型的段定义。
可以使用 ?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() 之前。由于结果不可靠,因此建议不要使用第二种格式。