段是输出目标文件的一个连续部分,其中包含节。mapfile 段指令允许指定三种不同的段类型。
LOAD_SEGMENT
可装入段包含在运行时映射到进程地址空间的代码或数据。链接编辑器会为每个可分配段创建一个 PT_LOAD 程序头项,运行时链接程序使用它定位和映射段。
NOTE_SEGMENT
注释段包含注释节。链接编辑器会创建一个引用该段的 PT_NOTE 程序头项。注释段不可分配。
NULL_SEGMENT
空段中的节包含在输出目标文件中,但在运行时不能用于该目标文件。这种节的常见示例包括 .symtab 符号表以及为便于调试器操作而生成的各种节。针对空段不会创建程序头。
段指令用于在输出文件中创建新段,或更改现有段的属性值。现有段是之前定义的段,或者是预定义段中所讨论的内置段。每个新段将添加到目标文件中相同类型的最后一个此类段之后。先添加可装入段,然后是注释段,最后添加空段。与这些段相关联的任何程序头将按照与段本身相同的相对顺序放在程序头数组中。通过为可装入段设置显式地址或者使用 SEGMENT_ORDER 指令可以更改这一缺省放置方式。
如果 segment_name 是一个预先存在的段,则所指定的属性将修改现有段。否则,将创建一个新段并为新段应用指定属性。链接编辑器会为未明确提供的属性填入缺省值。
所有这三个段指令共享一组通用的核心属性。段的声明如下,可用 LOAD_SEGMENT、NOTE_SEGMENT 和 NULL_SEGMENT 其中之一取代 directive。
directive segment_name { ASSIGN_SECTION [assign_name]; ASSIGN_SECTION [assign_name] { FILE_BASENAME = file_basename; FILE_OBJNAME = objname; FILE_PATH = file_path; FLAGS = section_flags; IS_NAME = section_name; TYPE = section_type; }; DISABLE; IS_ORDER = assign_name....; IS_ORDER += assign_name....; OS_ORDER = section_name....; OS_ORDER += section_name....; };
LOAD_SEGMENT 指令接受一组特定于可装入段的附加属性。这些附加属性的语法如下。
LOAD_SEGMENT segment_name { ALIGN = value; FLAGS = segment_flags; FLAGS += segment_flags; FLAGS -= segment_flags; MAX_SIZE = value; NOHDR; PADDR = value; ROUND = value; SIZE_SYMBOL = symbol_name....; SIZE_SYMBOL += symbol_name....; VADDR = value; };
其中的任何段指令都可指定为空指令。当空段指令创建新段时,将为所有段属性设置缺省值。空段的声明如下。
LOAD_SEGMENT segment_name; NOTE_SEGMENT segment_name; NULL_SEGMENT segment_name;
下面将说明一个或多个段指令所接受的所有属性。
ALIGN 属性用于指定可装入段的对齐方式。所指定的值设置在对应于该段的程序头的 p_align 字段中。段对齐用于计算段开头的虚拟地址。
指定的对齐方式必须是 0 或 2 的幂。缺省情况下,链接编辑器将段的对齐方式设置为内置缺省值。此缺省值随 CPU 的不同而不同,甚至也可能随软件修订版的不同而不同。
ALIGN 属性与 PADDR 和 VADDR 属性相关,且必须与它们兼容。
ASSIGN_SECTION 指定一个节属性组合,例如节名称、类型和标志,它们共同确定将某个节分配给某个给定段。每个此类属性集合称为一个入口条件。当节属性与入口条件的那些属性精确匹配时,该节即匹配。未指定任何属性的 ASSIGN_SECTION 将匹配与条件进行比较的任何节。
针对某个给定段允许使用多个 ASSIGN_SECTION 属性。每个 ASSIGN_SECTION 属性都独立于其他属性。如果某节与其中任何一个与段关联的 ASSIGN_SECTION 定义相匹配,则将该节指定给该段。除非段具有至少一个 ASSIGN_SECTION 属性,否则链接编辑器不会将节指定给段。
链接编辑器使用一个内部入口条件列表将节指定给段。在 mapfile 中遇到的每个 ASSIGN_SECTION 声明都按照所遇到的顺序放在此列表中。预定义段中所讨论的内置段的入口条件将紧接最后一个 mapfile 定义的项放在此列表中。
可以为入口条件指定一个可选名称 (assign_name)。该名称可与 IS_ORDER 属性一起使用,以指定输入节在输出节中的放置顺序。
为放置输入节,链接编辑器从入口条件列表的开头开始,将节的属性依次与每个入口条件进行比较。节将指定给与节属性精确匹配的第一个入口条件所关联的段。如果没有匹配项,该节将放置在文件的最后,所有不可分配节通常都是如此。
ASSIGN_SECTION 接受以下各项。
这些属性允许基于其所来自的文件的路径 (FILE_PATH)、基名 (FILE_BASENAME) 或目标文件名称 (FILE_OBJNAME) 选择节。
文件路径使用标准 Unix 斜杠分隔约定来指定。最后的路径段是路径的基名,也可以简单地称为文件名。对于归档文件,可以使用归档成员的名称对基名进行扩充,即采用 archive_name(component_name) 的形式。例如,/lib/libfoo.a(bar.o) 指定在名为 /lib/libfoo.a 的归档文件中找到的目标文件 bar.o。
FILE_BASENAME 和 FILE_OBJNAME 在应用于非归档文件时是等效的,它们将文件的给定名称根基名进行比较。在应用至归档文件时,FILE_BASENAME 将检查归档文件名称的基名,而 FILE_OBJNAME 将检查包含在归档文件中的目标文件的名称。
每个 ASSIGN_SECTION 会维护所有 FILE_BASENAME、FILE_PATH 和 FILE_OBJNAME 值的一个列表。如果其中任何一个定义与某个输入文件相匹配,则文件匹配。
输入节名称。
指定 ELF section_type,它可以是 <sys/elf.h> 中定义的任何 SHT_ 常量,且不带 SHT_ 前缀。例如,PROGBITS、SYMTAB 或 NOBITS。
FLAGS 属性使用 section_flags 将节属性指定为Table 8–7 中所给定的一个或多个值的空格分隔列表,这些值与 <sys/elf.h> 中定义的 SHF_ 值相对应。如果某个标志前面带有叹号 (!),则不能显式存在该属性。在下面的示例中,节定义为可分配但不可写入。
ALLOC !WRITE
未明确出现在 section_flags 列表中的标志将予以忽略。在上面的示例中,将节与指定标志进行匹配时,将只检查 ALLOC 和 WRITE 的值。其他节标志可以具有任意值。
|
DISABLE 属性会导致链接编辑器忽略段。不会将任何节指定给禁用的段。当由以下段指令引用时,将自动重新启用段。因此,空引用即足以重新启用禁用的段。
segment segment_name;
FLAGS 属性将段权限指定为Table 8–3 中所示权限的空格分隔列表。缺省情况下,用户定义的段将获得 READ、WRITE 和 EXECUTE 权限。预定义段中所描述的预定义段的缺省标志由链接编辑器提供,在某些情况下可能与平台相关。
该属性允许采用三种形式。
FLAGS = segment_flags....; FLAGS += segment_flags....; FLAGS -= segment_flags....;
简单的 "=" 赋值运算符将当前标志替换为新集合,"+=" 形式将新标志添加到现有集合中,而 "-=" 形式将指定标志从现有集合中删除。
链接编辑器通常按照遇到输出节的顺序将其放入段中。类似地,构成输出节的输入节也按照遇到它们的顺序进行放置。IS_ORDER 属性可用于改变输入节的这种缺省放置方式。IS_ORDER 指定入口条件名称 (assign_name) 的空格分隔列表。通过其中一个入口条件匹配的节将放置在输出节的开头,并按 IS_ORDER 指定的顺序排序。通过未在 IS_ORDER 列表中的入口条件匹配的节将按照遇到它们的顺序放置在已排序节之后。
使用 "=" 形式的赋值时,将放弃给定段的 IS_ORDER 的先前值并替换为新列表。"+=" 形式的 IS_ORDER 将新列表串联到现有列表的最后。
IS_ORDER 属性与编译器的 –xF 选项一起使用时会更有用。使用 –xF 选项编译文件时,将该文件中的每个函数都放置在与 text 节具有相同属性的单独节中。这些节称为 .text%function_name。
例如,使用 –xF 选项编译包含 main()、foo() 和 bar() 这三个函数的文件时,会生成一个可重定位的目标文件,并会将三个函数的文本放置在名为 .text%main、.text%foo 和 .text%bar 的节中。当链接编辑器将这些节放入输出中时,将删除 % 和 % 之后的任何内容。因此,这三个函数都将放在 .text 输出节中。IS_ORDER 属性可用于强制将它们以相对于彼此的特定顺序放在 .text 输出节中。
请考虑以下用户定义的 mapfile。
$mapfile_version 2 LOAD_SEGMENT text { ASSIGN_SECTION text_bar { IS_NAME = .text%bar }; ASSIGN_SECTION text_main { IS_NAME = .text%main }; ASSIGN_SECTION text_foo { IS_NAME = .text%foo }; IS_ORDER = text_foo text_bar text_main; };
不管这三个函数在源代码中的顺序或者链接编辑器遇到它们的顺序如何,它们在输出目标文件文本段中的顺序都将是 foo()、bar() 和 main()。
缺省情况下,链接编辑器允许段增大到段内容所需要的大小。MAX_SIZE 属性可用于指定段的最大大小。如果设置了 MAX_SIZE,链接编辑器会在段增长超出指定大小时生成错误。
如果设置了 NOHDR 属性的段成为输出目标文件中的第一个可装入段,则 ELF 头和程序头将不会包含在该段中。
NOHDR 属性与顶级 HDR_NOALLOC 指令的区别在于 HDR_NOALLOC 是一个基于段的值,仅当段成为第一个可装入段时才有效。该功能主要用于为早期的 mapfile 提供功能奇偶校验。有关更多详细信息,请参见Appendix B, System V 发行版 4(版本 1)mapfile。
建议优先使用 HDR_NOALLOC 指令,而不是段 NOHDR 属性。
链接编辑器通常按照遇到输出节的顺序将其放入段中。OS_ORDER 属性可用于改变输出节的这种缺省放置方式。OS_ORDER 指定输出节名称 (section_name) 的空格分隔列表。列出的节放在段的开头,并按照 OS_ORDER 指定的顺序排序。未在 OS_ORDER 中列出的节将按照遇到它们的顺序放在已排序节之后。
使用 "=" 形式的赋值时,将放弃给定段的 OS_ORDER 的先前值并替换为新列表。"+=" 形式的 OS_ORDER 将新列表串联到现有列表的最后。
PADDR 属性用于为段指定一个显式物理地址。指定的值必须是 0 或 2 的幂。所指定的值设置在对应于该段的程序头的 p_addr 字段中。缺省情况下,链接编辑器将段的物理地址设置为 0,因为此字段对于用户模式目标文件没有意义,它主要用于非用户级目标文件,如操作系统内核。
ROUND 属性用于指定段的大小应向上舍入为给定值。指定的舍入值必须是 0 或 2 的幂。缺省情况下,链接编辑器将段的舍入系数设置为 1,即不对段大小向上舍入。
SIZE_SYMBOL 属性定义要由链接编辑器创建的节大小符号名称的空格分隔列表。大小符号是全局绝对符号,以字节为单位表示段的大小。可以在目标文件中引用这些符号。为访问代码中的符号,应确保 symbol_name 是该语言中的合法标识符。建议采用 C 编程语言的符号命名规则,因为这种符号可能能够由任何其他语言访问。
可以使用 "=" 形式的赋值建立初始值,并且针对每个链接编辑器会话只能使用一次。"+=" 形式的 SIZE_SYMBOL 将新列表串联到现有列表的最后,并可根据需要使用任意次。
VADDR 属性用于为段指定一个显式虚拟地址。所指定的值设置在对应于该段的程序头的 p_vaddr 字段中。缺省情况下,链接编辑器会在创建输出文件时将虚拟地址指定给段。