找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2843

积分

0

好友

379

主题
发表于 3 天前 | 查看: 15| 回复: 0

上一篇文章:简说-编译Linux内核中,我们概括了Linux内核的编译流程。整个编译过程的核心产出,其实就是生成 vmlinux 和内核模块文件。

今天,我们就来深入聊聊这个核心产物——vmlinux。本文会聚焦于它的基本概念、作用以及一些关键特性,暂时不深入其复杂的生成细节和加载机制,旨在帮助你快速建立起对vmlinux的清晰认知。

Linux内核源码目录中的vmlinux文件位置

简单来说,vmlinux是一个未经压缩的、可直接引导的Linux内核镜像文件。它是由编译脚本 scripts/link-vmlinux.sh 将众多编译好的内核子模块(比如调度器、内存管理、文件系统等)链接在一起而形成的。可以说,vmlinux就是最“纯粹”、最完整的Linux内核本体。

那么,名字里的“vm”代表什么?它指的是 Virtual Memory(虚拟内存),这直接点明了Linux内核在虚拟内存管理层面的核心地位。

在编译内核时,你可能还见过 make bzImage 这个命令。它的作用,正是对编译好的vmlinux进行压缩。为什么要多此一举进行压缩呢?

核心原因在于:vmlinux文件太大了。 作为一个标准的ELF文件,vmlinux是编译后的可执行内核。理论上,它确实可以被直接放到启动分区,由引导程序加载并执行,从而启动系统。但现实情况是,未经压缩的vmlinux体积动辄几百MB,直接占用宝贵的启动分区空间显然不划算。因此,实际存储在启动分区中的,是压缩后的内核镜像(如bzImage)。经过压缩,内核镜像大小可能骤降至几MB,极大地节省了空间。

既然vmlinux也是一个ELF文件,它和我们平时在用户态编译生成的ELF程序(比如一个简单的C程序)有什么区别呢?

如果单从ELF文件自身的结构来看,答案是:没有本质区别。它们都遵循相同的ELF格式规范。真正的差异在于运行环境

用户态程序在生成和运行时,操作系统内核已经就绪,提供了完整的运行环境,包括构建好的页表等。加载器只需根据ELF头信息,将各个段(Section)加载到内存,然后跳转到入口地址(Entry Point)即可运行。

但vmlinux本身是要创造这个运行环境的“奠基者”。在它被执行之前,没有现成的页表,也没有内存管理单元(MMU)开启的虚拟地址空间。因此,vmlinux无法“自力更生”,它的加载需要外部引导程序的辅助。例如,在ARM平台上通常由U-Boot负责,在x86平台上则由GRUB等引导加载器完成。

我们可以通过 readelf 工具查看vmlinux的ELF头信息,来验证它的结构。下面的输出显示,这个vmlinux是针对x86-64架构的,其程序入口地址是 0x1000000

root@ubuntu:/usr/src/linux-6.1.1# readelf -h vmlinux
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2’s complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x1000000
  Start of program headers:          64 (bytes into file)
  Start of section headers:          1096716808 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         5
  Size of section headers:           64 (bytes)
  Number of section headers:         79
  Section header string table index: 78

当引导程序将压缩的内核镜像(内含vmlinux)解压并加载到内存的正确位置后,CPU就会跳转到上述的入口地址开始执行。内核执行的第一步,就是进行最基础的环境构建:初始化CPU寄存器、创建初始页表、开启MMU、切换到虚拟地址模式等等。一旦这些最基础的操作系统运行环境准备就绪,代码便会跳转到著名的 start_kernel() 函数,从这里开始,Linux内核的完整初始化之旅才正式拉开帷幕。

希望这篇简析能帮助你理解vmlinux在内核世界中的角色与特殊性。对技术细节的探讨,欢迎在云栈社区交流。




上一篇:Linux内核符号表System.map深度剖析:生成机制、动态视图与调试实战
下一篇:量化选股中BR因子表现如何?深度评测四大股票池表现
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-7 17:09 , Processed in 0.579552 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表