Linux vmlinux二进制布局解析
Linux vmlinux中的二进制布局
Linux内核的vmlinux
是未经压缩的ELF格式可执行文件,其二进制布局由链接脚本控制,主要分为以下几个关键部分:
1. ELF文件结构
- ELF头部:描述文件的基本信息(如架构、入口点、程序头和节区头的位置)。
- 程序头表(Program Headers):定义如何将段(如代码、数据)加载到内存。
- 节区(Sections):实际代码、数据和其他信息的存储区域。
- 节区头表(Section Headers):描述各节区的元数据(位于文件末尾)。
2. 核心节区布局
代码段
- **
.text
**:内核核心代码(如调度、内存管理)。 - **
.text.head
**(某些架构):启动相关代码(如x86的实模式初始化)。 - **
.init.text
**:初始化阶段代码,完成后可能被释放。
只读数据
- **
.rodata
**:只读数据(如字符串常量、驱动名称)。
数据段
- **
.data
**:已初始化的全局变量。 - **
.data..page_aligned
**:页面对齐的全局数据(如页表)。
未初始化数据
- **
.bss
**:未初始化的全局变量,文件不占空间,加载时清零。
特殊用途节区
- **
__ex_table
**:异常处理表(如x86的故障恢复指令)。 __ksymtab
/ **__ksymtab_gpl
**:内核符号表(用于模块依赖)。- **
.init.data
**:初始化阶段数据,完成后释放。 - **
.rodata.str1.1
**:优化后的只读字符串池。 - **
.notes
**:内核版本和构建信息。
3. 内存布局与加载
- 入口点:由ELF头部指定,通常指向架构相关的启动代码(如x86的
startup_64
)。 - 虚拟地址:内核代码和数据链接到高地址(如x86_64的
0xffffffff80000000
),与物理地址通过页表映射。 - 程序头加载:通过程序头表指导加载器将各段映射到内存(如
.text
到可执行区域,.data
到读写区域)。
4. 链接脚本控制
链接脚本(如arch/x86/kernel/vmlinux.lds.S
)决定节区顺序和对齐,典型逻辑如下:
- 放置启动代码(如
.text.head
)。 - 主代码段(
.text
)和只读数据(.rodata
)。 - 数据段(
.data
)和BSS(.bss
)。 - 初始化代码和数据(
.init.*
),可能标记为可释放。 - 特殊节区(如符号表、异常表)。
5. 工具验证
- **
readelf -S vmlinux
**:查看节区列表及文件偏移。 - **
objdump -d vmlinux
**:反汇编代码段。 - **
nm vmlinux
**:查看符号地址。
示例布局(x86_64简化)
1 | ELF Header |
关键点
- 调试符号:若开启
CONFIG_DEBUG_INFO
,会包含.debug_*
节区,显著增大文件。 - 架构差异:ARM可能包含
.vectors
(异常向量表),x86关注实模式代码。 - 优化:某些节区可能合并(如
.text
和.init.text
)或按需对齐。
通过链接脚本和ELF工具,可以精确控制内核的二进制布局,确保正确加载和执行。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Helloeuler!