以下示例为用户定义的 mapfile。示例中左边的编号用于教学演示。实际上只有编号右边的信息会出现在 mapfile 中。
示例 B-1 用户定义的 Mapfile
1. elephant : .data : peanuts.o *popcorn.o; 2. monkey : $PROGBITS ?AX; 3. monkey : .data; 4. monkey = LOAD V0x80000000 L0x4000; 5. donkey : .data; 6. donkey = ?RX A0x1000; 7. text = V0x80008000;
在此示例中处理四个单独的段。隐式声明的 elephant 段(第 1 行)从 peanuts.o 和 popcorn.o 文件中接收所有 .data 节。请注意,*popcorn.o 能够匹配任何可以提供给链接编辑的 popcorn.o 文件。该文件无需位于当前目录中。另一方面,如果将 /var/tmp/peanuts.o 提供给了链接编辑,它将不会与 peanuts.o 相匹配,因为它没有 * 前缀.
隐式声明的 monkey 段(第 2 行)接收既有 $PROGBITS 属性又有可分配且可执行属性 (?AX) 的节,同时还接收所有尚未存在于 elephant 段中且名为 .data(第 3 行)的节。进入 monkey 段的 .data 节无需是 $PROGBITS 节或可分配且可执行的节,因为输入 section_type 和 section_flags 值的行与 section_name 值所在的行不是同一个行。
如第 2 行的 $PROGBITS“与”?AX 所示,同一行中的属性之间存在“与”的关系。如第 2 行的 $PROGBITS ?AX“或”第 3 行的 .data 所示,相同段不同行的属性之间存在“或”的关系。
示例中的 monkey 段在第 2 行中隐式声明为:segment_type 值为 LOAD,segment_flags 值为 RWX,并且未指定 virtual_address、physical_address、length 和 alignment 值(使用缺省值)。在第 4 行中,monkey 的 segment_type 值设置为 LOAD。由于 segment_type 属性值未发生更改,因此不会发出任何警告。virtual_address 值设置为 0x80000000,最大 length 值设置为 0x4000。
第 5 行隐式声明了 donkey 段。入口条件的目的是将所有 .data 节路由到此段。但是实际上,没有任何节进入此段,因为第 3 行中 monkey 的入口条件会捕获所有这些节。在第 6 行中,segment_flags 值设置为 ?RX,alignment 值设置为 0x1000。由于这两个属性值都发生了更改,因此会发出警告。
第 7 行将文本段的 virtual_address 值设置为 0x80008000。
为了进行说明,用户定义的 mapfile 示例设计为会发出警告。如果要更改指令的顺序以避免发出警告,请使用以下示例:
1. elephant : .data : peanuts.o *popcorn.o; 4. monkey = LOAD V0x80000000 L0x4000; 2. monkey : $PROGBITS ?AX; 3. monkey : .data; 6. donkey = ?RX A0x1000; 5. donkey : .data; 7. text = V0x80008000;
以下 mapfile 示例使用段内节的排序:
1. text = LOAD ?RXN V0xf0004000; 2. text | .text; 3. text | .rodata; 4. text : $PROGBITS ?A!W; 5. data = LOAD ?RWX R0x1000;
此示例中处理了 text 和 data 段。第 1 行声明 text 段的 virtual_address 为 0xf0004000,并且没有将 ELF 头或任何程序头作为此段的地址计算的一部分包括在内。第 2 行和第 3 行启用段内节排序,并指定 .text 和 .rodata 节是此段中的前两个节。结果是 .text 节的虚拟地址为 0xf0004000,并且 .rodata 节紧跟该地址之后。
构成 text 段的任何其他 $PROGBITS 节位于 .rodata 节之后。第 5 行声明了 data 段,并指定其虚拟地址必须从 0x1000 字节边界开始。构成 data 段的第一个节也驻留在文件映像内的 0x1000 字节边界上。