浅析Linux内核镜像格式

文章目录

Linux内核镜像格式

尽管不同硬件平台在实际实现上,内核镜像布局有差异,但总体来说,Linux内核镜像格式及构建过程是趋于一致的:

vmlinux

vmlinux是编译内核生成的原始ELF格式可执行文件,内核目录下执行编译命令即可得到,包含完整的符号表和调试信息,文件体积较大(通常几十到上百MB),用于调试或生成其它格式的镜像文件。

Image

Image是未压缩的内核镜像,执行make Image命令便可生成,由vmlinux通过objcopy转换为纯二进制格式,去除符号表和重定位信息,体积较大,可以进一步压缩。Image可以支持引导,但通常很少直接在生产环境中使用。

vmlinuz

vmlinuz是压缩后的内核镜像,也是zImage、bzImge以及uImage压缩镜像的统称,区别只是在于使用的压缩格式不同。vmlinuz是实际使用并可引导的压缩内核。

  • zImage:Image经gzip压缩后的镜像,体积小于512KB,适用于旧版引导加载程序或ARM架构。包含解压代码,启动时加载到内存低端(如640KB以下)解压后执行。
  • bzImage:"big zImage"的缩写,采用更高压缩率的算法(如xz),解压后内核可加载到内存高端(1MB以上),支持更大的内核文件,常用于x86架构,与zImage的主要区别在于压缩算法和内存加载位置,现代Linux内核默认生成bzImage。
  • uImage:专为U-Boot设计的镜像,在zImage基础上添加64字节头部信息,包含内核版本、加载地址等元数据。使用mkimage工具将zImage封装为uImage,常见于嵌入式系统。随着U-Boot对zImage的支持增强,uImage逐渐减少使用。

ARM64下Linux内核镜像布局及构建

在ARM64架构下,编译出来的Linux内核默认是不支持自解压的,因此类似arch/arm64/boot/compressed的目录也是不存在的。Linux将这部分功能放到了外部压缩工具以及Bootloader,若需要减小内核体积,可以通过gzip等压缩工具将整个内核镜像压缩成指定的格式(如Image.gz),并由Bootloader在引导时配合完成内核解压。由于不涉及自解压,ARM64内核镜像的布局与构建过程,相对于x86,都简化了很多。

vmlinux

vmlinux是标准的ELF文件,可以使用readelf -h查看ELF文件头信息:

Aarch64平台下,vmlinux链接脚本使用arch/arm64/kernel/vmlinux.ld.S描述内核镜像中各个Section的排布。

通过 readelf -l命令,查看vmlinux的可加载段信息:

未压缩的内核镜像(Image)

ARM64平台下,未压缩的内核镜像会包含一个固定格式的64字节头部,其格式如下:

复制代码
  u32 code0;			/* Executable code */
  u32 code1;			/* Executable code */
  u64 text_offset;		/* Image load offset, little endian */
  u64 image_size;		/* Effective Image size, little endian */
  u64 flags;			/* kernel flags, little endian */
  u64 res2	= 0;		/* reserved */
  u64 res3	= 0;		/* reserved */
  u64 res4	= 0;		/* reserved */
  u32 magic	= 0x644d5241;	/* Magic number, little endian, "ARM\x64" */
  u32 res5;			/* reserved (used for PE COFF offset) */
  • code0/code1:存放可执行指令,即内核执行入口;
  • text_offset:描述内核代码段相对于镜像加载基址的偏移;
  • image_size:内核镜像大小;
  • flags:标志位,包含大小端、物理页面大小等标记,定义在arch/arm64/include/asm/image.h
  • magic:固定魔术数字,Arm64平台下是"ARM\x64";
  • res5:若内核配置成支持EFI Stub引导,则该字段用于指示PE头相对于Image的偏移,由于Image头部总共为64字节大小,因此这个偏移固定会设置成0x40;如果不支持EFI Stub,则字段可设置为0。

EFI Stub:若Linux内核镜像配置支持EFI Stub引导,那么code0字段会编译生成MZ签名,用于UEFI将内核镜像识别为PE/COFF可执行文件,从而通过EFI Stub引导内核;否则code0默认生成为nop指令。

压缩的内核镜像(Image.gz)

通过编译过程可以看到,Image.gz是通过gzip工具压缩后生成的,是标准的gzip压缩文件,这也是会安装到boot目录下的可引导内核镜像。

查看/boot下的内核镜像信息

通常放置在/boot目录下的内核镜像都是压缩之后的格式,通常都会命名为vmlinuz-xxx,可以通过file工具查看镜像压缩格式:

添加上.gz后缀后使用gzip进行解压缩。查看解压缩后的内核镜像信息:

x86下Linux内核镜像布局及构建

待完善...

相关参考