vmlinux,vmlinuz,bzimage,zimage,initrd.img uimage的区别与联系

时间:2022-07-31 16:29:08

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的解剖图:

vmlinux,vmlinuz,bzimage,zimage,initrd.img uimage的区别与联系

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