1.vmlinux
vmlinux是未压缩的内核, vmlinux 是ELF文件,即编译出来的最原始的文件。用于kernel-debug,产生system.map符号表,不能用于直接加载,不可以作为启动内核。只是启动过程中的中间媒体。 vmlinux.bin : The same as vmlinux, but in a binary file format.
vmlinux的获得
vmlinux是Linux源码编译后未压缩的内核,我们查看源码根目录下的.vmlinux.cmd文件,可以看到:
cmd_vmlinux := ld -m elf_i386 -m elf_i386 -o vmlinux -T arch/i386/kernel/vmlinux.lds arch/i386/kernel/head.o arch/i386/kernel/init_task.o init/built-in.o --start-group usr/built-in.o arch/i386/kernel/built-in.o arch/i386/mm/built-in.o arch/i386/mach-default/built-in.o arch/i386/crypto/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o lib/lib.a arch/i386/lib/lib.a lib/built-in.o arch/i386/lib/built-in.o drivers/built-in.o sound/built-in.o arch/i386/pci/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o
这说明vmlinux是由arch/i386/kernel/head.o和arch/i386/kernel /init_task.o以及各个相关子目录下的built-in.o链接而成的。注意按照链接顺序我们可以发现arch/i386/kernel /head.S的目标文件似乎比较靠前。
2.vmlinuz
vmlinuz是可引导的、压缩的内核。“vm”代表“Virtual Memory”。Linux 支持虚拟内存,不像老的操作系统比如DOS有640KB内存的限制。Linux能够使用硬盘空间作为虚拟内存,因此得名“vm”。vmlinuz是可执行的Linux内核,它位于/boot/vmlinuz,它一般是一个软链接。但是,它已经丢失了调试信息等,不可用于调试,这就是为什么perf和systemtap等内核级别的调试软件安装的时候,需要重新编译内核的原因。同理,解压缩vmlinuz是不能得到Vmlinux的。相对于vmlinux,它增加了解压缩和boot的部分
3.zimage
zImage是vmlinuz经过gzip压缩后的文件,适用于小内核(512KB以内),加载到内存的开始640KB处。
4.bzimage(not bzizp but big)
bzImage是vmlinuz经过gzip压缩后的文件,适用于大内核。为什么会发明bzimage这种内核镜像呢?随着linux内核的成熟,linux内核大小逐渐增大,超过了一些体系结构的限制,导致存储压缩内核的空间受到限制。bzimage这种格式就是为了克服这种限制,它通过把kernel分解到不相邻的内存区域来达到这一个目的。
bzimage包含以下目标文件 bootsect.o + setup.o + misc.o + piggy.o .
bootsect:这个程序是linuxkernel的第一个程序,包括了linux自己的bootstrap程序,主要进行开机后加载真正内核镜像之前的各种准备工作.注意它是用来load bzimage,不是bzimage的一部分(这句话存在质疑)。
setup:进行实模式设置 misc: piggy.o 包含被压缩的vmlinux
bzimage的解剖图:
bzImage的获得
bzImage是内核的压缩版本,一般可以是vmlinux大小的三分之一左右。
首先查看生成bzImage的链接文件arch/i386/boot/.bzImage.cmd
cmd_arch/i386/boot/bzImage := arch/i386/boot/tools/build -b arch/i386/boot/bootsect arch/i386/boot/setup arch/i386/boot/vmlinux.bin CURRENT > arch/i386/boot/bzImage
接下去根据线索我们查看生成vmlinux.bin的链接文件arch/i386/boot/.vmlinux.bin.cmd
cmd_arch/i386/boot/vmlinux.bin := objcopy -O binary -R .note -R .comment -S arch/i386/boot/compressed/vmlinux arch/i386/boot/vmlinux.bin
然后查看生成vmlinux的链接文件arch/i386/boot/compressed/.vmlinux.cmd
cmd_arch/i386/boot/compressed/vmlinux := ld -m elf_i386 -m elf_i386 -T arch/i386/boot/compressed/vmlinux.lds arch/i386/boot/compressed/head.o arch/i386/boot/compressed/misc.o arch/i386/boot/compressed/piggy.o -o arch/i386/boot/compressed/vmlinux
接下去查看生成piggy.o的链接文件arch/i386/boot/compressed/.piggy.o.cmd
cmd_arch/i386/boot/compressed/piggy.o := ld -m elf_i386 -m elf_i386 -r --format binary --oformat elf32-i386 -T arch/i386/boot/compressed/vmlinux.scr arch/i386/boot/compressed/vmlinux.bin.gz -o arch/i386/boot/compressed/piggy.o
然后接下去查看生成vmlinux.bin.gz的链接文件arch/i386/boot/compressed/.vmlinux.bin.gz.cmd
cmd_arch/i386/boot/compressed/vmlinux.bin.gz := gzip -f -9 < arch/i386/boot/compressed/vmlinux.bin > arch/i386/boot/compressed/vmlinux.bin.gz
最后我们查看生成vmlinux.bin的链接文件arch/i386/boot/compressed/.vmlinux.bin.cmd,注意这里的vmlinux就是根目录下的vmlinux。
cmd_arch/i386/boot/compressed/vmlinux.bin := objcopy -O binary -R .note -R .comment -S vmlinux arch/i386/boot/compressed/vmlinux.bin
下面我们将生成bzImage的过程总结一下:
a。由vmlinux文件strip掉符号表得到arch/i386/boot/compressed/vmlinux.bin
b。将vmlinux.bin压缩成vmlinux.bin.gz
c。将vmlinux.scr和vmlinux.bin.gz链接成piggy.o
d。将head.o、misc.o和piggy.o链接成当前目录下的vmlinux
e。将vmlinux文件strip掉符号表得到arch/i386/boot/vmlinux.bin
f。将bootsect、setup和vmlinux.bin拼接成bzImage
5. uImage
uboot专用的内核镜像,在zImage前加了一个64字节的头,描述内核版本、加载地址生成时间,文件大小等等。 其0x40后的内容和zImage一样。它是由uboot的工具mkImage生成的。
mkimage是在制作镜像文件时候, 在原来的image文件前增加一个0x40字节长度的头,增加的头结构描述如下
/*
* Legacy format image header,
* all data in network byte order (aka natural aka bigendian).
*/
typedef struct image_header {
uint32_t ih_magic; /* Image Header Magic Number */
uint32_t ih_hcrc; /* Image Header CRC Checksum */
uint32_t ih_time; /* Image Creation Timestamp */
uint32_t ih_size; /* Image Data Size */
uint32_t ih_load; /* Data Load Address */
uint32_t ih_ep; /* Entry Point Address */
uint32_t ih_dcrc; /* Image Data CRC Checksum */
uint8_t ih_os; /* Operating System */
uint8_t ih_arch; /* CPU architecture */
uint8_t ih_type; /* Image Type */
uint8_t ih_comp; /* Compression Type */
uint8_t ih_name[IH_NMLEN]; /* Image Name */
} image_header_t;
Image Name占用了32字节,其他信息占用了32字节
mkimage用法:
Usage: ./mkimage -l image
-l ==> list image header information
./mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
-A ==> set architecture to 'arch'
-O ==> set operating system to 'os'
-T ==> set image type to 'type'
-C ==> set compression type 'comp'
-a ==> set load address to 'addr' (hex)
-e ==> set entry point to 'ep' (hex)
-n ==> set image name to 'name'
-d ==> use image data from 'datafile'
-x ==> set XIP (execute in place)
./mkimage [-D dtc_options] -f fit-image.its fit-image
-A 设定架构类型,可取值参照uboot/common/image.c
-O 设定操作系统类型,可取值参照uboot/common/image.c
-T image类型,可取值参照uboot/common/image.c
-a 指定image在内存中的加载地址
-e 指定image运行的入口点地址
-C 指定压缩方式,压缩方式参考uboot/common/image.c
-d data_file[:data_file...] 制作image的源文件
示例
$MKIMAGE_TOOL -A arm -O linux -T kernel -C none -a 0x90008000 -e 0x90008000 -n "Android Linux Kernel" -d ./zImage ./uImage