Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2150641
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2016-10-28 14:36:38

1.bzImage的生成过程
1.1 生成bzImage的过程分析
  1. a. 第1步生成vmlinux,格式是ELF-32
  2. 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 \
  3.         --start-group \
  4.         arch/i386/kernel/kernel.o arch/i386/mm/mm.o kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o \
  5.          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 \
  6.         net/network.o \
  7.         /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 \
  8.         --end-group \
  9.         -o vmlinux
  10. /work/os/gcc/gcc-3.34/bin/nm vmlinux | grep -v '\(compiled\)\|\(\.o$\)\|\( [aUw] \)\|\(\.\.ng$\)\|\(LASH[RL]DI\)' | sort > System.map

  11. b. 第2步在arch/i386/boot目录下生成bbootsect 与 bsetup
  12. make[1]: Entering directory `/work/os/linux-2.4.12/arch/i386/boot'
  13. /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
  14. /work/os/gcc/gcc-3.34/bin/as -o bbootsect.o bbootsect.s
  15. /work/os/gcc/gcc-3.34/bin/ld -m elf_i386 -Ttext 0x0 -s --oformat binary bbootsect.o -o bbootsect
  16. /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
  17. /work/os/gcc/gcc-3.34/bin/as -o bsetup.o bsetup.s
  18. /work/os/gcc/gcc-3.34/bin/ld -m elf_i386 -Ttext 0x0 -s --oformat binary -e begtext -o bsetup bsetup.o

  19. c.compressed目录下-->先把vmlinux用objcopy生成raw-bin格式,然后用gzip压缩生成-->piggy.o
  20. make[2]: Entering directory `/work/os/linux-2.4.12/arch/i386/boot/compressed'
  21. tmppiggy=_tmp_$$piggy; \
  22.     rm -f $tmppiggy $tmppiggy.gz $tmppiggy.lnk; \
  23.     /work/os/gcc/gcc-3.34/bin/objcopy -O binary -R .note -R .comment -S /work/os/linux-2.4.12/vmlinux $tmppiggy; \
  24.     gzip -f -9 < $tmppiggy > $tmppiggy.gz; \
  25.     echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $tmppiggy.lnk; \
  26.     /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; \
  27.     rm -f $tmppiggy $tmppiggy.gz $tmppiggy.lnk

  28. d.compressed目录下--> 将解压头head.o与misc.o与压缩过的piggy.o连接到1M处-->bvmlinux
  29. /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
  30. /work/os/gcc/gcc-3.34/bin/ld -m elf_i386 -Ttext 0x100000 -e startup_32 -o bvmlinux head.o misc.o piggy.o
  31. make[2]: Leaving directory `/work/os/linux-2.4.12/arch/i386/boot/compressed'

  32. e.用objcopy对添加了解压头的compressed/bvmlinux去符号生成raw-bin格式的 -->bvmlinux.out
  33. gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -o tools/build tools/build.c -I/work/os/linux-2.4.12/include
  34. /work/os/gcc/gcc-3.34/bin/objcopy -O binary -R .note -R .comment -S compressed/bvmlinux compressed/bvmlinux.out

  35. f. 将arch/i386/boot下的bbootsect bsetup 与加上解压头的bvmlinux.out 合并到bzImage中
  36. tools/build -b bbootsect bsetup compressed/bvmlinux.out CURRENT > bzImage
  37. Root device is (8, 7)
  38. Boot sector 512 bytes.
  39. Setup is 2385 bytes.
  40. System is 790 kB
  41. 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的分析
  1. cong@msi:/work/os/linux-2.4.12/arch/i386/boot$ cat tools/build.c
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <stdarg.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <sys/sysmacros.h>
  9. #include <unistd.h>
  10. #include <fcntl.h>
  11. #include <asm/boot.h>

  12. typedef unsigned char byte;
  13. typedef unsigned short word;
  14. typedef unsigned long u32;

  15. #define DEFAULT_MAJOR_ROOT 0
  16. #define DEFAULT_MINOR_ROOT 0

  17. /* Minimal number of setup sectors (see also bootsect.S) */
  18. #define SETUP_SECTS 4

  19. byte buf[1024];
  20. int fd;
  21. int is_big_kernel;

  22. void die(const char * str, ...)
  23. {
  24.     va_list args;
  25.     va_start(args, str);
  26.     vfprintf(stderr, str, args);
  27.     fputc('\n', stderr);
  28.     exit(1);
  29. }
  30. //对open进行封装
  31. void file_open(const char *name)
  32. {
  33.     if ((fd = open(name, O_RDONLY, 0)) < 0)
  34.         die("Unable to open `%s': %m", name);
  35. }

  36. void usage(void)
  37. {
  38.     die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
  39. }

  40. int main(int argc, char ** argv)
  41. {
  42.     unsigned int i, c, sz, setup_sectors;
  43.     u32 sys_size;
  44.     byte major_root, minor_root;
  45.     struct stat sb;

  46.     if (argc > 2 && !strcmp(argv[1], "-b"))
  47.     {
  48.          is_big_kernel = 1;    //-b的意思是big,有了-b说明允许生成超过508K的内核
  49.          argc--, argv++;
  50.     }
  51.     if ((argc < 4) || (argc > 5))
  52.         usage();
  53. //下面这个if是确定major_root与minor_root,即确定rootfs是在哪个设备
  54.     if (argc > 4) {
  55.         if (!strcmp(argv[4], "CURRENT")) {
  56.             if (stat("/", &sb)) {
  57.                 perror("/");
  58.                 die("Couldn't stat /");
  59.             }
  60.             major_root = major(sb.st_dev);
  61.             minor_root = minor(sb.st_dev);
  62.         } else if (strcmp(argv[4], "FLOPPY")) {
  63.             if (stat(argv[4], &sb)) {
  64.                 perror(argv[4]);
  65.                 die("Couldn't stat root device.");
  66.             }
  67.             major_root = major(sb.st_rdev);
  68.             minor_root = minor(sb.st_rdev);
  69.         } else {
  70.             major_root = 0;
  71.             minor_root = 0;
  72.         }
  73.     } else {
  74.         major_root = DEFAULT_MAJOR_ROOT;
  75.         minor_root = DEFAULT_MINOR_ROOT;
  76.     }
  77.     fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
  78. //第1步-->打开512个字节bootsect,然后写到bzImage的开头,bootsect的位置[0-0x200]
  79.     file_open(argv[1]);
  80.     i = read(fd, buf, sizeof(buf));
  81.     fprintf(stderr,"Boot sector %d bytes.\n",i);
  82.     if (i != 512)
  83.         die("Boot block must be exactly 512 bytes");
  84.     if (buf[510] != 0x55 || buf[511] != 0xaa)               -->0x55aa启动标志
  85.         die("Boot block hasn't got boot flag (0xAA55)");
  86.     buf[508] = minor_root;                                  -->将rootfs设备号写到508,509处
  87.     buf[509] = major_root;
  88.     if (write(1, buf, 512) != 512)                          -->修改好buf之后真正的写在bzImage上  
  89.         die("Write call failed");
  90.     close (fd);

  91. //第2步-->把setup写到bzImage中,不足一个扇区部分的补0。setup紧接着bootsect-->setup的位置[0x200-0x200*n]
  92.     file_open(argv[2]);                 /* Copy the setup code */
  93.     for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c )   //把setup写到bzImage中
  94.         if (write(1, buf, c) != c)
  95.             die("Write call failed");
  96.     if (c != 0)
  97.         die("read-error on `setup'");
  98.     close (fd);
  99.     setup_sectors = (i + 511) / 512;    /* Pad unused space with zeros */
  100.     /* for compatibility with ancient versions of LILO. */
  101.     if (setup_sectors < SETUP_SECTS)      //不到4个扇区凑够4个扇区
  102.         setup_sectors = SETUP_SECTS;
  103.     fprintf(stderr, "Setup is %d bytes.\n", i);
  104.     memset(buf, 0, sizeof(buf));
  105.     while (i < setup_sectors * 512) {        //把不到1个扇区的内容补0
  106.         c = setup_sectors * 512 - i;
  107.         if (c > sizeof(buf))
  108.             c = sizeof(buf);
  109.         if (write(1, buf, c) != c)          
  110.             die("Write call failed");
  111.         i += c;
  112.     }

  113. //第3步-->把bvmlinux.out写到bzImage中。vmlinux紧接着sectup
  114.     file_open(argv[3]);
  115.     if (fstat (fd, &sb))
  116.         die("Unable to stat `%s': %m", argv[3]);
  117.     sz = sb.st_size;
  118.     fprintf (stderr, "System is %d kB\n", sz/1024);
  119.     sys_size = (sz + 15) / 16;
  120.     /* 0x28000*16 = 2.5 MB, conservative estimate for the current maximum */
  121.     if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE))         -->普通内核508K,bzImage的内核可达2.5M
  122.         die("System is too big. Try using %smodules."is_big_kernel ? "" : "bzImage or ");
  123.     if (sys_size > 0xefff)
  124.         fprintf(stderr,"warning: kernel is too big for standalone boot " "from floppy\n");
  125.     while (sz > 0) {
  126.         int l, n;

  127.         l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
  128.         if ((n=read(fd, buf, l)) != l) {
  129.             if (n < 0)
  130.                 die("Error reading %s: %m", argv[3]);
  131.             else
  132.                 die("%s: Unexpected EOF", argv[3]);
  133.         }
  134.         if (write(1, buf, l) != l)
  135.             die("Write failed");
  136.         sz -= l;
  137.     }
  138.     close(fd);
  139. //到bootsect中写入一些值
  140.     if (lseek(1, 497, SEEK_SET) != 497)         /* Write sizes to the bootsector */
  141.         die("Output: seek failed");
  142.     buf[0] = setup_sectors;                      -->497字节是setup的sector数目
  143.     if (write(1, buf, 1) != 1)
  144.         die("Write of setup sector count failed");
  145.     if (lseek(1, 500, SEEK_SET) != 500)          -->500字节是bvmliux.out的字节数/16的大小
  146.         die("Output: seek failed");
  147.     buf[0] = (sys_size & 0xff);
  148.     buf[1] = ((sys_size >> 8) & 0xff);
  149.     if (write(1, buf, 2) != 2)
  150.         die("Write of image length failed");

  151.     return 0;                     /* Everything is OK */
  152. }
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) |
给主人留下些什么吧!~~