LOAD_SEGMENT / NOTE_SEGMENT / NULL_SEGMENT 指令
SIZE_SYMBOL 属性(仅限 LOAD_SEGMENT)
SYMBOL_SCOPE / SYMBOL_VERSION 指令
下面说明链接编辑器用来将节指定给输出段的内部过程。这些信息并不是使用 mapfile 所必需的。这些信息主要提供给对链接编辑器的内部过程感兴趣的读者,以及希望进一步了解链接编辑器如何解释和执行段的 mapfile 指令的读者。
将输入节分配给输出段的过程涉及以下数据结构。
输入节
输入节是从可重定位目标文件输入读入到链接编辑器中的。其中某些由链接编辑器检查和处理,另一些则只是传递至输出而不检查其内容(例如 PROGBITS)。
输出节
输出节是写入到输出目标文件中的节。其中某些由通过输入目标文件传递的节串联而成。另一些(如符号表和重定位节)由链接编辑器自己生成,并且通常会并入从输入目标文件中读取的信息。
当链接编辑器传递输入节以使之成为输出节时,该节通常会保留输入节名称。不过,链接编辑器在某些情况下会修改名称。例如,链接编辑器会转换 name%XXX 形式的输入节名称,在输出节名称中删除 % 字符及其后的任何字符。
段描述符
链接编辑器会维护一个已知段列表。该列表初始时包含预定义段,如预定义段中所述。当使用 LOAD_SEGMENT、NOTE_SEGMENT 或 NULL_SEGMENT mapfile 指令创建新段时,会向此列表中添加新段的附加段描述符。除非通过设置虚拟地址 (LOAD_SEGMENT) 或使用 SEGMENT_ORDER 指令进行显式排序,否则新段将位于列表的末尾(位于相同类型的其他段之后)。
创建输出目标文件时,链接编辑器只会为接收节的段创建程序头。将以无提示方式忽略空段。因此,用户指定的段定义可完全取代预定义的段定义的使用,尽管没有明确的工具用于从链接编辑器列表中删除段定义。
入口条件
为将节放入给定段中所需的一组节属性称为该段的入口条件。给定段可以具有任意数量的入口条件。
链接编辑器会维护一个所有定义的入口条件的内部列表。该列表用于将节放入段中,如下所述。每个 mapfile 按照在 mapfile 中遇到 ASSIGN_SECTION 属性所创建的入口条件的顺序将它们插入到此列表顶部的 LOAD_SEGMENT、NOTE_SEGMENT 或 NULL_SEGMENT mapfile 指令中。预定义段中所讨论的内置段的入口条件放在此列表的最后。因此,mapfile 定义的入口条件将优先于内置规则,而位于命令行最后的 mapfile 将优先于开始处的 mapfile。
对于写入到输出目标文件中的每个节,链接编辑器将执行以下步骤,以便将节放入输出段中。
节的属性将与内部入口条件列表中的每个记录进行比较,从列表的开头开始,依次考虑每个入口条件。当入口条件中的每个属性都精确匹配时,则表示匹配,并且不会禁用与该入口条件相关联的段。搜索将在匹配的第一个入口条件处停止,并且节将定向到关联的段。
如果不与任何入口条件匹配,则将节放置在输出文件的末尾(位于所有其他段之后)。不会为此信息创建任何程序头项。多数非可分配节(例如调试节)都结束于此区域。
当节位于段下时,链接编辑器会检查此段中现有输出节的列表,方式如下:
如果节属性值与现有输出节的属性值完全匹配,则将此节放置在与该输出节关联的节列表的末尾。
如果未找到匹配的输出节,则使用要放置的节的属性创建一个新输出节,并将输入节放在新输出节中。此新输出节位于段内具有相同节类型的任何其他输出节之后,如果没有相同类型的其他输出节,则位于段的末尾。
注 - 如果输入节的用户定义的节类型值介于 SHT_LOUSER 和 SHT_HIUSER 之间,则将其视为 PROGBITS 节。没有在 mapfile 中命名此节类型值的方法,但可以使用入口条件中指定的其他属性值(节标志、节名称)重定向这些节。
链接编辑器提供一组预定义的输出段描述符和入口条件,如预定义段中所述。链接编辑器已经知道这些节,因此创建这些节无需 mapfile 指令。所显示的可用于生成它们的 mapfile 指令仅为提供说明,并作为相对复杂的 mapfile 规范的一个示例。可以使用 Mapfile 段指令修改或扩充这些内置定义。
通常,节到段的分配可在单个段指令中完成。但是,预定义节具有更复杂的要求,即要求按照不同于段在内存中的布局顺序处理这些节的入口条件。为此可以使用两个过程,第一个用于按照所需顺序定义所有段,第二个用于按照实现所需结果的顺序建立入口条件。用户 mapfile 很少需要采用此策略。
# Predefined segments and entrance criteria for the Oracle Solaris # link-editor $mapfile_version 2 # The lrodata and ldata segments only apply to x86-64 objects. # Establish amd64 as a convenient token for conditional input $if _ELF64 && _x86 $add amd64 $endif # Pass 1: Define the segments and their attributes, but # defer the entrance criteria details to the 2nd pass. LOAD_SEGMENT text { FLAGS = READ EXECUTE; }; LOAD_SEGMENT data { FLAGS = READ WRITE EXECUTE; }; LOAD_SEGMENT bss { DISABLE; FLAGS=DATA; }; $if amd64 LOAD_SEGMENT lrodata { FLAGS = READ }; LOAD_SEGMENT ldata { FLAGS = READ WRITE; }; $endif NOTE_SEGMENT note; NULL_SEGMENT extra; # Pass 2: Define ASSIGN_SECTION attributes for the segments defined # above, in the order the link-editor should evaluate them. # All SHT_NOTE sections go to the note segment NOTE_SEGMENT note { ASSIGN_SECTION { TYPE = NOTE; }; }; $if amd64 # Medium/large model x86-64 readonly sections to lrodata LOAD_SEGMENT lrodata { ASSIGN_SECTION { FLAGS = ALLOC AMD64_LARGE; }; }; $endif # text receives all readonly allocable sections LOAD_SEGMENT text { ASSIGN_SECTION { FLAGS = ALLOC !WRITE; }; }; # If bss is enabled, it takes the writable NOBITS sections # that would otherwise end up in ldata or data. LOAD_SEGMENT bss { DISABLE; ASSIGN_SECTION { FLAGS = ALLOC WRITE; TYPE = NOBITS; }; }; $if amd64 # Medium/large model x86-64 writable sections to ldata LOAD_SEGMENT ldata { ASSIGN_SECTION { FLAGS = ALLOC WRITE AMD64_LARGE; }; ASSIGN_SECTION { TYPE = NOBITS; FLAGS = AMD64_LARGE }; }; $endif # Any writable allocable sections not taken above go to data LOAD_SEGMENT data { ASSIGN_SECTION { FLAGS = ALLOC WRITE; }; }; # Any section that makes it to this point ends up at the # end of the object file in the extra segment. This accounts # for the bulk of non-allocable sections. NULL_SEGMENT extra { ASSIGN_SECTION; };