编译内核 https://cdn.kernel.org/pub/linux/kernel/v2.6/linux-2.6.39.tar.xz

1. 生成.config并编译

linux内核有数千个编译配置选项,以致于管理这些配置项都需要写个程序来管理了.
管理配置项的程序有好几个, make menuconfig 就是其中一个.
他们最终的目的就是生成一个.config文件.

在我的电脑上,执行 make menuconfig 后,什么选项都不更改,直接退出,就得到了这样一个.config文件.
Download .config
把这个.config文件copy到linux源码目录,执行 make 命令,然后等上好一段时间,编译就完成了.

cp .config /path/to/linux-2.6.39/
cd /path/to/linux-2.6.39
make

2. 几个重要的编译结果

文件名 大小 怎么来的
vmlinux 141438505 gcc编译,只不过用了自己的链接脚本 arch/x86/kernel/vmlinux.lds.S
这是一个标准的ELF文件, readelf -h -S vmlinux 可以查看ELF Header及Section Headers
System.map 这个文件的大小我们不关心 这个文件非常有用,它记录着函数,变量的内存地址
readelf -s vmlinux 也可以拿到vmlinux的symbol table
不过这个System.map是由 scripts/mksysmap 这个脚本生成的.
arch/x86/boot/compressed/vmlinux.bin 18545760 objcopy -R .comment -S vmlinux arch/x86/boot/compressed/vmlinux.bin
@see arch/x86/boot/compressed/.vmlinux.bin.cmd
arch/x86/boot/compressed/vmlinux.bin.gz 4559912 cat vmlinux.bin | gzip -f -9 > vmlinux.bin.gz
@see arch/x86/boot/compressed/.vmlinux.bin.gz.cmd
arch/x86/boot/compressed/piggy.S 这个文件的大小我们不关心 mkpiggy vmlinux.bin.gz
前边生成的vmlinux.bin.gz被include到了这个文件里
.globl input_data, input_data_end
input_data:
.incbin "arch/x86/boot/compressed/vmlinux.bin.gz"
input_data_end:
arch/x86/boot/compressed/vmlinux 6681360 ld -m elf_x86_64 -T vmlinux.lds head_64.o misc.o string.o cmdline.o early_serial_console.o piggy.o -o vmlinux
@see arch/x86/boot/compressed/.vmlinux.cmd
arch/x86/boot/vmlinux.bin 4579584 objcopy -O binary -R .note -R .comment -S compressed/vmlinux vmlinux.bin
@see arch/x86/boot/.vmlinux.bin.cmd
arch/x86/boot/setup.bin 16620 objcopy setup.elf 而来, 这个文件我们不太关心
@see arch/x86/boot/.setup.elf.cmd
@see arch/x86/boot/.setup.bin.cmd
arch/x86/boot/bzImage 4596496 tools/build setup.bin vmlinux.bin CURRENT > bzImage
@see arch/x86/boot/.bzImage.cmd

3. bzImage构成分析(tools/build.c解读)

build.c 的作用是把 setup.bin 和 vmlinux.bin 合成一个 bzImage.
合成前,需要计算出几个值,覆盖掉 setup.bin 里的默认值.
setup.bin的前两个sector(共1K)的内容是由 header.S 生成的, 链接脚本是 setup.ld
自己写过bootloader的话能很容易看明白 header.S 这段程序.

需要计算的几个值:

  1. ROOT Device Number: 我们可以通过 stat / 取得. 由于我们的.config 里配置了
    CONFIG_BLK_DEV_INITRD=y
    也就是说系统启动需要一个initrd image, 而GRUB加载initrd的话,会把ROOT Device Number重设为一个固定值,所以这个值在这里就无所谓了
    不过当我们使用hexdump验证bzImage时,知道这个值还是有帮助的.
  2. setup.bin的大小占用几个sector, 它的大小前边我们已经知道了, 占用的sector数可以很容易计算出来.
  3. arch/x86/boot/vmlinux.bin的大小,这次不是计算占用多少个sector,而是看有多少个16字节,计算时要多出4个字节再计算,因为要在最后放个CRC32校验值,占4个字节

值计算好后,写入setup.bin

从setup.ld里得知 .header 在 offset 497.
SECTIONS
{
	. = 0;
	.bstext		: { *(.bstext) }
	.bsdata		: { *(.bsdata) }

	. = 497;
	.header		: { *(.header) }
对应 header.S
	.section ".header", "a"
	.globl	hdr
hdr:
setup_sects:	.byte 0			/* Filled in by build.c */      # offset 497 (0x1f1)
root_flags:	.word ROOT_RDONLY                                   # offset 498,499 (0x1f2, 0x1f3)
syssize:	.long 0			/* Filled in by build.c */          # offset 500,501,502,503 (0x1f4, 0x1f5, 0x1f6, 0x1f7)
ram_size:	.word 0			/* Obsolete */                      # offset 504, 505
vid_mode:	.word SVGA_MODE                                     # offset 506, 507
root_dev:	.word 0			/* Filled in by build.c */          # offset 508, 509
boot_flag:	.word 0xAA55
对应build.c
     /* Set the default root device */
     buf[508] = minor_root;
     buf[509] = major_root;
     /* Patch the setup code with the appropriate size parameters */
     buf[0x1f1] = setup_sectors-1;
     buf[0x1f4] = sys_size;
     buf[0x1f5] = sys_size >> 8;
     buf[0x1f6] = sys_size >> 16;
     buf[0x1f7] = sys_size >> 24;

合并生成bzImage

首先写入setup.bin,前边我们已经计算好了它要占几个sector,setup.bin不会恰好占满这多么sector,余下的字节以0填充.
写入vmlinux.bin,前边我们已经计算好了它要占多少个16字节,vmlinux.bin也不会恰好占满这多么个16字节,保留最后4个字节,其它字节以0填充.
计算setup.bin + padded zero + vmlinux.bin + padded zero 的CRC32检验值,结果写到最后,占4个字节.
OK, bzImage就这样生成了.

setup.bin
padded zero
vmlinux.bin
padded zero
crc32

一个php版的build.c

Download build.php

crc32

Download crc32 Download crc32.c

验证

stat -c %D /
803

php build.php ../../linux-2.6.39/arch/x86/boot/setup.bin ../../linux-2.6.39/arch/x86/boot/vmlinux.bin 3 8
setup.bin padded zeros: 276
vmlinux.bin padded zeros: 12

./crc32 /tmp/bzImage.pad
bzImage.pad size = 4596492
crc32 bzImage.pad = 5fcb720e
/tmp/bzImage.pad
arch/x86/boot/bzImage
# root_dev
hexdump -C -n 2 -s 508 /tmp/bzImage.pad
000001fc  03 08                                             |..|

# setup_sects
hexdump -C -n 1 -s 497 /tmp/bzImage.pad
000001f1  20                                                | |

# sys_size
hexdump -C -n 4 -s 500 /tmp/bzImage.pad
000001f4  11 5e 04 00                                       |.^..|

# setup.bin padded zeros
hexdump -C -n $((16+276+16)) -s $((16620-16)) /tmp/bzImage.pad
000040dc  2b 00 00 00 00 0f 50 00  19 00 00 00 55 aa 5a 5a  |+.....P.....U.ZZ|
000040ec  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000041fc  00 00 00 00 fc f6 86 11  02 00 00 40 75 0c fa b8  |...........@u...|
0000420c  18 00 00 00                                       |....|

# vmlinux.bin padded zeros
hexdump -C -n 512 -s $(((16620+511)/512*512+4579584-16)) /tmp/bzImage.pad
004622f0  00 00 00 00 00 89 80 00  00 00 00 00 00 00 00 00  |................|
00462300  00 00 00 00 00 00 00 00  00 00 00 00              |............|
        
# root_dev
hexdump -C -n 2 -s 508 bzImage
000001fc  03 08                                             |..|

# setup_sects
hexdump -C -n 1 -s 497 bzImage
000001f1  20                                                | |

# sys_size
hexdump -C -n 4 -s 500 bzImage
000001f4  11 5e 04 00                                       |.^..|

# setup.bin padded zeros
hexdump -C -n $((16+276+16)) -s $((16620-16)) bzImage
000040dc  2b 00 00 00 00 0f 50 00  19 00 00 00 55 aa 5a 5a  |+.....P.....U.ZZ|
000040ec  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000041fc  00 00 00 00 fc f6 86 11  02 00 00 40 75 0c fa b8  |...........@u...|
0000420c  18 00 00 00                                       |....|

# vmlinux.bin padded zeros
hexdump -C -n 512 -s $(((16620+511)/512*512+4579584-16)) bzImage
004622f0  00 00 00 00 00 89 80 00  00 00 00 00 00 00 00 00  |................|
00462300  00 00 00 00 00 00 00 00  00 00 00 00 0e 72 cb 5f  |.............r._|
        

4. 参考资料