Linux内核二进制布局

Linux内核的二进制布局涉及编译后的内核镜像在内存中的结构和段分布,主要分为以下几个关键部分:


1. 内核二进制文件组成

  • vmlinux:未经压缩的原始ELF格式内核文件,包含完整的符号信息,通常用于调试。
  • bzImage:压缩后的可引导内核镜像(常见于x86架构),由引导加载程序(如GRUB)加载到内存。其结构包括:
    • 引导程序(Bootsector):负责实模式初始化。
    • setup部分:完成硬件检测和进入保护模式的准备工作。
    • 压缩内核:包含压缩的vmlinux镜像和解压代码(如gunzip)。

2. 内存中的物理布局(以x86为例)

  • 实模式阶段
    • 引导扇区:加载到物理地址 0x7C00
    • setup部分:通常加载到 0x90000,负责切换到保护模式。
  • 保护模式阶段
    • 内核解压后的基地址:物理地址 0x100000(1MB),这是内核代码段(.text)的起始位置。
    • 内核镜像布局
      • **.text**:代码段,包含内核核心逻辑。
      • **.rodata**:只读数据(如字符串常量)。
      • **.data**:已初始化的全局变量。
      • **.bss**:未初始化的全局变量(清零区)。
      • init:初始化代码和数据(启动完成后可能被释放)。

3. 链接脚本(vmlinux.lds.S)

内核的段布局由链接脚本(如arch/x86/kernel/vmlinux.lds.S)定义,关键部分包括:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.text : {          /* 代码段 */
_text = .;
*(.text.head)
*(.text .text.*)
}

.rodata : { /* 只读数据 */
*(.rodata .rodata.*)
}

.data : { /* 可读写数据 */
*(.data .data.*)
}

.bss : { /* 未初始化数据 */
_bss = .;
*(.bss .bss.*)
_ebss = .;
}

.init : { /* 初始化专用段 */
*(.init.text)
*(.init.data)
}

4. 虚拟地址空间布局(x86-64)

内核启动后通过分页机制映射到高地址虚拟内存:

  • 内核虚拟基址0xffffffff80000000(起始地址)。
  • 直接映射区(Direct Mapping):物理内存与虚拟地址线性映射,范围通常为 0xffff888000000000
  • vmalloc/IO映射区:动态分配非连续内存。
  • 内核代码段:位于虚拟地址 0xffffffff81000000 附近。

5. 关键符号与入口点

  • 入口点_start(定义于链接脚本),通常位于.text.head段。
  • 初始化流程:从实模式引导跳转到startup_32(32位)或startup_64(64位),最终调用start_kernel()进入主初始化逻辑。

6. 架构差异

  • ARM:内核通常加载到物理地址 0x8000(如树莓派),链接地址由设备树(DTB)决定。
  • UEFI系统:可能直接加载内核到高地址(如x86_64的0x200000)。

总结

Linux内核的二进制布局是启动过程的核心,涵盖从实模式到虚拟内存管理的过渡。理解其布局需结合物理加载地址、链接脚本和架构特性,具体细节可通过objdump -d vmlinuxreadelf -S工具进一步分析。