1.bzImage的生成过程
1.1
生成bzImage的过程分析
-
a. 第1步生成vmlinux,格式是ELF-32
-
ld -m elf_i386 -T /work/os/linux-2.4.12/arch/i386/vmlinux.lds -e stext arch/i386/kernel/head.o arch/i386/kernel/init_task.o init/main.o init/version.o \
-
--start-group \
-
arch/i386/kernel/kernel.o arch/i386/mm/mm.o kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o \
-
drivers/char/char.o drivers/block/block.o drivers/misc/misc.o drivers/net/net.o drivers/media/media.o drivers/char/agp/agp.o drivers/char/drm/drm.o drivers/ide/idedriver.o drivers/scsi/scsidrv.o drivers/cdrom/driver.o drivers/sound/sounddrivers.o drivers/pci/driver.o drivers/pcmcia/pcmcia.o drivers/net/pcmcia/pcmcia_net.o drivers/video/video.o drivers/usb/usbdrv.o \
-
net/network.o \
-
/work/os/linux-2.4.12/arch/i386/lib/lib.a /work/os/linux-2.4.12/lib/lib.a /work/os/linux-2.4.12/arch/i386/lib/lib.a \
-
--end-group \
-
-o vmlinux
-
/work/os/gcc/gcc-3.34/bin/nm vmlinux | grep -v '\(compiled\)\|\(\.o$\)\|\( [aUw] \)\|\(\.\.ng$\)\|\(LASH[RL]DI\)' | sort > System.map
-
-
b. 第2步在arch/i386/boot目录下生成bbootsect 与 bsetup
-
make[1]: Entering directory `/work/os/linux-2.4.12/arch/i386/boot'
-
/work/os/gcc/gcc-3.34/bin/gcc -E -D__KERNEL__ -I/work/os/linux-2.4.12/include -D__BIG_KERNEL__ -traditional -DSVGA_MODE=NORMAL_VGA bootsect.S -o bbootsect.s
-
/work/os/gcc/gcc-3.34/bin/as -o bbootsect.o bbootsect.s
-
/work/os/gcc/gcc-3.34/bin/ld -m elf_i386 -Ttext 0x0 -s --oformat binary bbootsect.o -o bbootsect
-
/work/os/gcc/gcc-3.34/bin/gcc -E -D__KERNEL__ -I/work/os/linux-2.4.12/include -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional -DSVGA_MODE=NORMAL_VGA setup.S -o bsetup.s
-
/work/os/gcc/gcc-3.34/bin/as -o bsetup.o bsetup.s
-
/work/os/gcc/gcc-3.34/bin/ld -m elf_i386 -Ttext 0x0 -s --oformat binary -e begtext -o bsetup bsetup.o
-
-
c.compressed目录下-->先把vmlinux用objcopy生成raw-bin格式,然后用gzip压缩生成-->piggy.o
-
make[2]: Entering directory `/work/os/linux-2.4.12/arch/i386/boot/compressed'
-
tmppiggy=_tmp_$$piggy; \
-
rm -f $tmppiggy $tmppiggy.gz $tmppiggy.lnk; \
-
/work/os/gcc/gcc-3.34/bin/objcopy -O binary -R .note -R .comment -S /work/os/linux-2.4.12/vmlinux $tmppiggy; \
-
gzip -f -9 < $tmppiggy > $tmppiggy.gz; \
-
echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $tmppiggy.lnk; \
-
/work/os/gcc/gcc-3.34/bin/ld -m elf_i386 -r -o piggy.o -b binary $tmppiggy.gz -b elf32-i386 -T $tmppiggy.lnk; \
-
rm -f $tmppiggy $tmppiggy.gz $tmppiggy.lnk
-
-
d.compressed目录下--> 将解压头head.o与misc.o与压缩过的piggy.o连接到1M处-->bvmlinux
-
/work/os/gcc/gcc-3.34/bin/gcc -g -D__KERNEL__ -I/work/os/linux-2.4.12/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe -mpreferred-stack-boundary=2 -march=i686 -c misc.c
-
/work/os/gcc/gcc-3.34/bin/ld -m elf_i386 -Ttext 0x100000 -e startup_32 -o bvmlinux head.o misc.o piggy.o
-
make[2]: Leaving directory `/work/os/linux-2.4.12/arch/i386/boot/compressed'
-
-
e.用objcopy对添加了解压头的compressed/bvmlinux去符号生成raw-bin格式的 -->bvmlinux.out
-
gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o tools/build tools/build.c -I/work/os/linux-2.4.12/include
-
/work/os/gcc/gcc-3.34/bin/objcopy -O binary -R .note -R .comment -S compressed/bvmlinux compressed/bvmlinux.out
-
-
f. 将arch/i386/boot下的bbootsect bsetup 与加上解压头的bvmlinux.out 合并到bzImage中
-
tools/build -b bbootsect bsetup compressed/bvmlinux.out CURRENT > bzImage
-
Root device is (8, 7)
-
Boot sector 512 bytes.
-
Setup is 2385 bytes.
-
System is 790 kB
-
make[1]: Leaving directory `/work/os/linux-2.4.12/arch/i386/boot
1.2 关于tools/build.c的作用
a. 如果没有加-b参数,则认为是普通的内核,其最大长度是#define DEF_SYSSIZE 0x7F00,内核长度最大为:7F00*16=508K
b. bbootsect-->arch/i386/boot/bootsect.S编译出来的,就是一个512字节的MBR-->写到bzImage开头
c. bsetup-->arch/i386/boot/Setup.S编译出来的-->按512个字节为单位写到bzImage中去,接着bbootsect
d. compressed/bvmlinux.out
e. CURRENT-->代表major_root与minor_root,即文件系统的设备结点-->这会写到bzImage的buf[508-509]去。
2. 各个部分的运行地址分析
附录1: tools/build.c的分析
-
cong@msi:/work/os/linux-2.4.12/arch/i386/boot$ cat tools/build.c
-
#include <stdio.h>
-
#include <string.h>
-
#include <stdlib.h>
-
#include <stdarg.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <sys/sysmacros.h>
-
#include <unistd.h>
-
#include <fcntl.h>
-
#include <asm/boot.h>
-
-
typedef unsigned char byte;
-
typedef unsigned short word;
-
typedef unsigned long u32;
-
-
#define DEFAULT_MAJOR_ROOT 0
-
#define DEFAULT_MINOR_ROOT 0
-
-
/* Minimal number of setup sectors (see also bootsect.S) */
-
#define SETUP_SECTS 4
-
-
byte buf[1024];
-
int fd;
-
int is_big_kernel;
-
-
void die(const char * str, ...)
-
{
-
va_list args;
-
va_start(args, str);
-
vfprintf(stderr, str, args);
-
fputc('\n', stderr);
-
exit(1);
-
}
-
//对open进行封装
-
void file_open(const char *name)
-
{
-
if ((fd = open(name, O_RDONLY, 0)) < 0)
-
die("Unable to open `%s': %m", name);
-
}
-
-
void usage(void)
-
{
-
die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
-
}
-
-
int main(int argc, char ** argv)
-
{
-
unsigned int i, c, sz, setup_sectors;
-
u32 sys_size;
-
byte major_root, minor_root;
-
struct stat sb;
-
-
if (argc > 2 && !strcmp(argv[1], "-b"))
-
{
-
is_big_kernel = 1; //-b的意思是big,有了-b说明允许生成超过508K的内核
-
argc--, argv++;
-
}
-
if ((argc < 4) || (argc > 5))
-
usage();
-
//下面这个if是确定major_root与minor_root,即确定rootfs是在哪个设备上
-
if (argc > 4) {
-
if (!strcmp(argv[4], "CURRENT")) {
-
if (stat("/", &sb)) {
-
perror("/");
-
die("Couldn't stat /");
-
}
-
major_root = major(sb.st_dev);
-
minor_root = minor(sb.st_dev);
-
} else if (strcmp(argv[4], "FLOPPY")) {
-
if (stat(argv[4], &sb)) {
-
perror(argv[4]);
-
die("Couldn't stat root device.");
-
}
-
major_root = major(sb.st_rdev);
-
minor_root = minor(sb.st_rdev);
-
} else {
-
major_root = 0;
-
minor_root = 0;
-
}
-
} else {
-
major_root = DEFAULT_MAJOR_ROOT;
-
minor_root = DEFAULT_MINOR_ROOT;
-
}
-
fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
-
//第1步-->打开512个字节的bootsect,然后写到bzImage的开头,bootsect的位置[0-0x200]
-
file_open(argv[1]);
-
i = read(fd, buf, sizeof(buf));
-
fprintf(stderr,"Boot sector %d bytes.\n",i);
-
if (i != 512)
-
die("Boot block must be exactly 512 bytes");
-
if (buf[510] != 0x55 || buf[511] != 0xaa) -->0x55aa启动标志
-
die("Boot block hasn't got boot flag (0xAA55)");
-
buf[508] = minor_root; -->将rootfs设备号写到508,509处
-
buf[509] = major_root;
-
if (write(1, buf, 512) != 512) -->修改好buf之后真正的写在bzImage上
-
die("Write call failed");
-
close (fd);
-
-
//第2步-->把setup写到bzImage中,不足一个扇区部分的补0。setup紧接着bootsect-->setup的位置[0x200-0x200*n]
-
file_open(argv[2]); /* Copy the setup code */
-
for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c ) //把setup写到bzImage中
-
if (write(1, buf, c) != c)
-
die("Write call failed");
-
if (c != 0)
-
die("read-error on `setup'");
-
close (fd);
-
setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */
-
/* for compatibility with ancient versions of LILO. */
-
if (setup_sectors < SETUP_SECTS) //不到4个扇区凑够4个扇区
-
setup_sectors = SETUP_SECTS;
-
fprintf(stderr, "Setup is %d bytes.\n", i);
-
memset(buf, 0, sizeof(buf));
-
while (i < setup_sectors * 512) { //把不到1个扇区的内容补0
-
c = setup_sectors * 512 - i;
-
if (c > sizeof(buf))
-
c = sizeof(buf);
-
if (write(1, buf, c) != c)
-
die("Write call failed");
-
i += c;
-
}
-
-
//第3步-->把bvmlinux.out写到bzImage中。vmlinux紧接着sectup
-
file_open(argv[3]);
-
if (fstat (fd, &sb))
-
die("Unable to stat `%s': %m", argv[3]);
-
sz = sb.st_size;
-
fprintf (stderr, "System is %d kB\n", sz/1024);
-
sys_size = (sz + 15) / 16;
-
/* 0x28000*16 = 2.5 MB, conservative estimate for the current maximum */
-
if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE)) -->普通内核508K,bzImage的内核可达2.5M
-
die("System is too big. Try using %smodules.", is_big_kernel ? "" : "bzImage or ");
-
if (sys_size > 0xefff)
-
fprintf(stderr,"warning: kernel is too big for standalone boot " "from floppy\n");
-
while (sz > 0) {
-
int l, n;
-
-
l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
-
if ((n=read(fd, buf, l)) != l) {
-
if (n < 0)
-
die("Error reading %s: %m", argv[3]);
-
else
-
die("%s: Unexpected EOF", argv[3]);
-
}
-
if (write(1, buf, l) != l)
-
die("Write failed");
-
sz -= l;
-
}
-
close(fd);
-
//到bootsect中写入一些值
-
if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */
-
die("Output: seek failed");
-
buf[0] = setup_sectors; -->497字节是setup的sector数目
-
if (write(1, buf, 1) != 1)
-
die("Write of setup sector count failed");
-
if (lseek(1, 500, SEEK_SET) != 500) -->500字节是bvmliux.out的字节数/16的大小
-
die("Output: seek failed");
-
buf[0] = (sys_size & 0xff);
-
buf[1] = ((sys_size >> 8) & 0xff);
-
if (write(1, buf, 2) != 2)
-
die("Write of image length failed");
-
-
return 0; /* Everything is OK */
-
}
a. 说明-->
这是./arch/i386/boot/bzImage的前512个字节的最后
b. 0005是setup的扇区数
cong@msi:/work/os/linux-2.4.12$ ls arch/i386/boot/bsetup -l
-rwxrwxr-x 1 cong cong 2385 Oct 29 10:10 arch/i386/boot/bsetup
(2385+512)/512=5
c. b4c5 0000 是vmlinux.out的segment数
cong@msi:/work/os/linux-2.4.12$ ls arch/i386/boot/compressed/bvmlinux.out -l
-rwxrwxr-x 1 cong cong 809790 Oct 29 10:10 arch/i386/boot/compressed/bvmlinux.out
(809790+15)/16=50612=C5B4
阅读(1232) | 评论(0) | 转发(0) |