链接程序和库指南

Mapfile 结构和语法

可以将以下基本类型的指令输入 mapfile

每个指令可以跨越多行,并且可以包含任意数量的空格(包括换行符),但空格后面要跟随一个分号。

通常,段声明后面跟有映射指令。您可以声明段,然后定义节成为段的一部分所依据的标准。如果未先声明要映射到的段(内置段除外),便输入映射指令或大小符号声明,则会为该段赋予缺省属性。此类段为隐式声明的段。

大小符号声明和文件控制指令可以出现在 mapfile 中的任何位置。

以下各节将针对每种指令类型进行介绍。对于所有语法讨论,以下约定都适用:

段声明

段声明可在输出文件中创建新段,或者更改现有段的属性值。现有段可以是指先前定义的段,也可以是随后即将介绍的四个内置段之一。

段声明的语法如下:

        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

有四个内置段,其缺省属性值如下所示:

缺省情况下,禁用 bss 段。任何类型为 SHT_NOBITS(此类型为节的唯一输入)的节都是在 data 段中捕获的。有关 SHT_NOBITS 节的完整说明,请参见表 7–5。最简单的 bss 声明:

        bss =;

便足以创建 bss 段。任何 SHT_NOBITS 节都是由此段(而不是 data 段)捕获的。此段采用最简单的形式,并且使用与应用于任何其他段相同的缺省值对齐。还可以声明其他既可创建段又可为指定属性赋值的段属性。

链接编辑器的行为方式就好像在读入 mapfile 之前已经声明了这些段。请参见Mapfile 缺省选项

输入段声明时,请注意以下事项:


注 –

如果指定了 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 标志与缺省文本段进行关联。

如果源文件中函数定义的顺序为 mainfoobar,则最终的可执行文件所包含的函数顺序为 foobarmain

对于具有相同名称的静态函数,还必须使用文件名。?O 标志强制按 mapfile 中的要求对节进行排序。例如,如果静态函数 bar() 位于文件 a.ob.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 文件。下表列出了节属性及其有效值。

表 9–2 节属性

节属性 

值 

section_name

任何有效的节名 

section_type

$PROGBITS

$SYMTAB

$STRTAB

$REL

$RELA

$NOTE

$NOBITS

section_flags

? [[!]A] [[!]W] [[!]X]

输入映射指令时,请注意以下几点:

段内节的排序

使用以下表示法可以指定段中放置节的顺序:

        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 中包含的版本定义名称。