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