除了最常见的为 .text, .data, .bss 这 3 个段之外,还有其它的一些常见段,如下所示:
.strtab : String Table 字符串表,用于存储 ELF 文件中用到的各种字符串。
.symtab : Symbol Table 符号表,从这里可以所以文件中的各个符号。
.shstrtab : 是各个段的名称表,实际上是由各个段的名字组成的一个字符串数组。
.hash : 符号哈希表。
.line : 调试时的行号表,即源代码行号与编译后指令的对应表。
.dynamic : 动态链接信息。
.debug : 调试信息。
.comment : 存放编译器版本信息,比如 "GCC:(GNU)4.2.0"。
.plt 和 .got : 动态链接的跳转表和全局入口表。
.init 和 .fini : 程序初始化和终结代码段。
.rodata1 : Read Only Data,只读数据段,存放字符串常量,全局 const 变量,该段和 .rodata 一样。
由上可见,这些段的名字前都有一个 '.' 点符号前缀,其义表示这些段的名字为系统所保留。应用程序可以使用非系统保留的名字作为自己的自定义段名,但是自定义的段名就不能使用 '.' 符号作为前缀,否则容易和系统保留的段名冲突。
一个 ELF 文件中允许存在两个及以上的同名段,比如可能会看到多个 .text 段。
可以用 objcopy 命令将一个普通二进制文件,如图片,多媒体之类的东西作为目标文件中的一个段。制作方法如下:
[beyes@beyes ELF]$ objcopy -I binary -O elf32-i386 -B i386 mypic.jpg temp.o
[beyes@beyes ELF]$ objdump -t temp.o
temp.o: file format elf32-i386
SYMBOL TABLE:
00000000 l d .data 00000000 .data
00000000 g .data 00000000 _binary_mypic_jpg_start
00011855 g .data 00000000 _binary_mypic_jpg_end
00011855 g *ABS* 00000000 _binary_mypic_jpg_size
objcopy 命令用于将目标文件的的部分或全部内容拷贝到另一个目标文件中,并可以实现格式的变换。
上面的 objcopy 命令中:
-I 选项表示指定输入的目标文件格式。
-O 选项表示指定输出的目标文件格式。
-B 选项指定要欲转入目标文件的输入文件的适用平台。这里指定 i386 表示该图片格式适用于 i386 平台。但由于 objcopy 所使用的 BFD 库中已经识别了 i386 平台,所以这里不用 -B 选项也是可以的。
在使用 objcopy 将图片文件转换进目标文件 temp.o 中后,默认会用
_binary_objfile_start 和
_binary_objfile_end 来标识被转换文件在内存中的起始地址,结束地址;以及使用 _binary_objfile_size 来表示大小。
自定义段
通常,在 gcc 编译出来的目标文件中,代码一般是放到 .text 段,全局变量和静态变量被放到 .data 和 .bss 段。这只是默认行为,我们有时可能希望变量或某些代码放在一个自定义的段中去以实现某些特定功能,比如为了满足某些硬件的内存和 I/O 地址布局,或者像 Linux 内核中用来完成一些初始化和用户控件复制时出现的错误异常等。GCC 提供了一个扩展机制,使得我们可以将变量放在我们自定义的段中。如下代码示例:
#include <stdio.h>
__attribute__((section("myvarsection"))) int global_var = 18;
__attribute__((section("myfuncsection"))) void hello(void);
void hello(void)
{
printf ("hello world\n");
printf ("my global_var:%d\n", global_var);
}
int main()
{
hello();
return 0;
}
查看相应的目标文件:
[beyes@beyes ELF]$ objdump -h sefsec.o
sefsec.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000012 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 00000000 00000000 00000048 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000048 2**2
ALLOC
3 myvarsection 00000004 00000000 00000000 00000048 2**2
CONTENTS, ALLOC, LOAD, DATA
4 .rodata 0000001e 00000000 00000000 0000004c 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 myfuncsection 0000002b 00000000 00000000 0000006a 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
6 .comment 0000002e 00000000 00000000 00000095 2**0
CONTENTS, READONLY
7 .note.GNU-stack 00000000 00000000 00000000 000000c3 2**0
CONTENTS, READONLY
8 .eh_frame 00000058 00000000 00000000 000000c4 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
程序中使用 GCC 的扩展机制 __attribute__((section()) 来自定义自己的段。