ELF(Executable and Linkable Format)是一种常用的文件格式,用于定义程序、库或者其他可执行文件的结构。它在Unix-like系统中广泛使用,特别是在Linux系统中。ELF文件主要用于两个目的:作为可执行文件运行,以及作为链接器的输入来合并多个对象文件。
ELF文件的主要组成部分包括:
-
文件头(File Header):
- 描述了整个文件的基本属性,如ELF版本信息、系统架构类型、入口点地址等。
-
程序头表(Program Header Table):
- 指定了生成的可执行文件中各个段(如代码段、数据段)的位置和大小。
-
节头表(Section Header Table):
- 描述了文件中的各个节(如
.text
、.data
、.bss
等),包括每个节的位置、大小和其他属性。
- 描述了文件中的各个节(如
-
节(Sections):
- 文件的实际内容,包括代码、数据、符号表、重定位信息等。
ELF文件的使用场景:
- 作为可执行文件:加载到内存中,由操作系统执行。
- 作为动态库:在运行时被动态链接到其他程序中。
- 作为静态库:在编译时被链接器合并到其他对象文件中。
工具:
readelf
:用于显示ELF文件的详细信息,如readelf -h
显示文件头,readelf -l
显示程序头表。objdump
:用于显示二进制文件的信息,可以用来查看ELF文件的节、符号等。
ELF格式的灵活性和功能强大使其成为Unix-like系统中标准的二进制文件格式。
ELF 文件的节头表(Section Header Table)
ELF 文件的节头表是一个重要的数据结构,它描述了文件中所有节(section)的属性和位置。每个节可以包含代码、数据、符号表、重定位信息等。节头表中的每个条目称为一个节头(section header),它指定了一个节的大小、位置、类型和其他属性。
主要字段功能:
-
sh_name:
- 节名称的字符串表索引。这个索引指向节头字符串表(通常是
.shstrtab
),用于获取节的名称。
- 节名称的字符串表索引。这个索引指向节头字符串表(通常是
-
sh_type:
- 定义节的类型,如
SHT_PROGBITS
(程序数据)、SHT_SYMTAB
(符号表)、SHT_STRTAB
(字符串表)、SHT_RELA
(重定位条目,带加法因子)、SHT_HASH
(符号哈希表)、SHT_DYNAMIC
(动态链接信息)等。
- 定义节的类型,如
-
sh_flags:
- 描述节的属性,如
SHF_WRITE
(可写)、SHF_ALLOC
(在内存中分配)、SHF_EXECINSTR
(可执行指令)。
- 描述节的属性,如
-
sh_addr:
- 如果节将出现在进程的内存映像中,此字段给出节的第一个字节应处的地址。否则,此字段为0。
-
sh_offset:
- 从文件头到节的第一个字节的字节偏移。
-
sh_size:
- 节的长度(字节)。
-
sh_link:
- 额外信息的索引,具体含义依赖于节类型。
-
sh_info:
- 额外信息,其含义依赖于节类型。
-
sh_addralign:
- 某些节中的条目需要按此值对齐,必须是2的幂。
-
sh_entsize:
- 如果节中包含固定大小的条目,则表示每个条目的字节大小;如果条目大小不固定或节不包含条目,则为0。
字符设备(Character Device)
字符设备是一种可以按字符(字节)进行数据读写的设备。与块设备不同,字符设备不需要数据缓冲区,它们允许直接和即时的数据传输,例如键盘、鼠标或串口。在Linux内核中,字符设备通过设备文件(通常位于 /dev
目录下)与用户空间程序交互。
字符设备的主要特点是:
- 数据可以一个字节一个字节地处理。
- 通常不支持随机访问。
- 设备操作如读写通常是阻塞的。
在Linux内核中,每个字符设备都关联一个 cdev
结构体,这个结构体包含了设备的操作函数,如打开、读取、写入等。开发者需要在驱动程序中实现这些操作函数,然后将 cdev
结构体注册到内核中,使得用户空间的程序可以通过设备文件访问硬件设备。