Linux vmlinux二进制组成格式

Linux 的 vmlinux 是未经压缩的、完整的内核可执行文件(ELF 格式),通常用于调试或符号分析。它的二进制组成格式遵循 ELF(Executable and Linkable Format) 标准,但具体结构和内容与普通用户态程序有所不同。以下是 vmlinux 的主要组成部分和特性:


1. ELF 文件结构

vmlinux 是一个标准的 ELF 文件(通常是 ELF64 格式),包含以下核心部分:

  • ELF Header
    描述文件的元信息,如架构(如 x86_64ARM)、入口地址(内核启动地址)、程序头表和节头表的位置等。

    • 使用 readelf -h vmlinux 可查看 ELF 头信息。
  • Program Headers(程序头表)
    描述内核在内存中加载的段(如代码段、数据段、BSS 段),供引导加载器或内核自身初始化时使用。

    • 使用 readelf -l vmlinux 查看程序头表。
  • Section Headers(节头表)
    描述文件中的各个节(section),如 .text(代码)、.data(已初始化的全局变量)、.rodata(只读数据)等。

    • 使用 readelf -S vmlinux 查看节头表。

2. 关键节(Sections)

内核的代码和数据按功能划分到不同的节中,常见的节包括:

  • .text
    内核的核心代码(如调度、内存管理、系统调用等)。
  • .rodata
    只读数据(如字符串常量、内核版本信息)。
  • .data
    已初始化的全局变量。
  • .bss
    未初始化的全局变量(实际不占用文件空间,但加载到内存时会清零)。
  • .init.text.init.data
    内核初始化阶段使用的代码和数据,初始化完成后会被释放。
  • .head.text
    内核启动早期的汇编代码(如引导阶段的低级别初始化)。
  • .symtab.strtab
    符号表和字符串表(需开启内核编译选项 CONFIG_DEBUG_INFO 才会包含调试符号)。

3. 内核特有的段

内核在链接时会通过链接脚本(vmlinux.lds.S)组织内存布局,确保关键部分按正确顺序加载。例如:

  • 内核代码段
    从虚拟地址 0xffffffff80000000(x86_64)开始,包含 .text.rodata
  • 内核数据段
    包含 .data.bss,通常位于代码段之后。
  • 初始化段
    .init 相关的段在启动后会被释放,以节省内存。

4. 符号信息

如果编译时启用了 CONFIG_DEBUG_INFOvmlinux 会包含完整的调试符号(函数名、变量名等),用于:

  • 使用 objdumpgdb 分析内核崩溃的堆栈。
  • 生成 System.map 文件,记录符号地址映射。

5. 与压缩内核镜像的区别

  • vmlinux
    未经压缩的 ELF 文件,不可直接用于引导系统(需要引导加载器支持 ELF 格式)。
  • bzImage/zImage
    压缩后的内核镜像(通常使用 gzip 或 LZ4),附加了引导代码(如 arch/x86/boot/header.S),可被 BIOS/UEFI 直接加载。

6. 分析工具

  • readelf
    查看 ELF 头、程序头、节头等信息。
  • objdump
    反汇编代码或查看节内容(如 objdump -d vmlinux)。
  • nm
    列出符号表(如 nm vmlinux | grep start_kernel)。
  • gdb
    结合 vmlinux 调试内核(需 QEMU 等模拟器配合)。

总结

vmlinux 是一个符合 ELF 格式的内核可执行文件,包含内核代码、数据、符号表和调试信息。其结构由链接脚本(vmlinux.lds.S)定义,确保内核在内存中正确布局。通过工具分析 vmlinux,可以深入理解内核的启动流程和运行时行为。