0
点赞
收藏
分享

微信扫一扫

【Linux 0.11】第十六章 建造工具

赵炯;《Linux 内核完全注释 0.11 修正版 V3.0》

Linux 内核源代码中的 tools 目录中包含一个生成内核磁盘映像文件的工具程序 build.c,该程序将单独编译成可执行文件,在 linux/ 目录下的 Makefile 文件被调用运行,用于将所有内核编译代码链接和合并成一个可运行的内核映像文件 Image。具体方法是对 boot/ 中的 bootsect.s、setup.s 使用 8086 汇编器进行编译,分别生成各自的执行模块,再对源代码中的其他所有程序使用 GNU 的编译器 gcc/gas 进行编译,并连接成模块 system,然后使用 build 工具将这三块组合成一个内核映像文件 Image。

​linux/Makefile​​​ 中的命令行:​​tools/build boot/bootsect boot/setup tools/system $(ROOT_DEV) > Image​

build 程序有 4 个参数,分别是 bootsect 文件名、setup 文件名、system 文件名和可选的根文件系统设备文件名。前二者是由 as86 和 ld86 编译链接产生,它们具有 MINIX 执行文件格式,而 system 是由源代码各个子目录中编译产生的模块链接而成,具有 GNU a.out 执行文件格式。build 程序的主要工作就是去掉 bootsect 和 setup 的 MINIX 执行文件头结构信息、去掉 system 文件中的 a.out 头结构信息,只保留它们的代码和数据部分,然后把它们顺序组合在一起写入名为 Image 的文件中。

  1. 程序首先检查命令行上最后一个根设备文件名可选参数,若其存在,则读取设备文件的状态信息结构(stat),取出设备号。若命令行上不带该参数,则使用默认值。
  2. 然后对 bootsect 文件进行处理,读取该文件的 minix 执行头部信息,判断其有效性,然后读取随后 512 字节的引导代码数据,判断其是否具有可引导标志 0xAA55,并将前面获取的根设备号写入到 508,509 位移处,最后将该512 字节代码数据写到 stdout 标准输出,由 Make 文件重定向到 Image 文件。
  3. 接下来以类似的方法处理 setup 文件,若该文件长度小于 4 个扇区,则用 0 将其填满为 4 个扇区的长度,并写到标准输出 stdout 中。
  4. 最后处理 system 文件。该文件是使用 GCC 编译器产生的,所以执行头部格式是 GCC 类型的,与 linux 定义的 a.out 格式一样,在判断执行入口点是 0 后,就将数据写到标准输出 stdout 中,若其代码数据长度超过 128KB,则显示出错信息,最终形成的内核 Image 文件是:
  • 第 1 个扇区上存放的是 bootsect 代码,长度正好是 512 字节;
  • 第 2 个扇区开始的 4 个扇区,存放着 setup 代码,长度不超过 4 个扇区大小;
  • 从第 6 个扇区开始存放 system 模块代码,长度不超过 build.c 第 35 行上定义的大小(​​#define SYS_SIZE 0x2000​​);

/*
* linux/tools/build.c
*
* (C) 1991 Linus Torvalds
*/

/*
* This file builds a disk-image from three different files:
*
* - bootsect: max 510 bytes of 8086 machine code, loads the rest
* - setup: max 4 sectors of 8086 machine code, sets up system parm
* - system: 80386 code for actual system
*
* It does some checking that all files are of the correct type, and
* just writes the result to stdout, removing headers and padding to
* the right amount. It also writes some system data to stderr.
*/

/*
* Changes by tytso to allow root device specification
*/

#include <stdio.h> /* fprintf */
#include <string.h>
#include <stdlib.h> /* contains exit */
#include <sys/types.h> /* unistd.h needs this */
#include <sys/stat.h>
#include <linux/fs.h>
#include <unistd.h> /* contains read/write */
#include <fcntl.h>

#define MINIX_HEADER 32
#define GCC_HEADER 1024

#define SYS_SIZE 0x2000

#define DEFAULT_MAJOR_ROOT 3
#define DEFAULT_MINOR_ROOT 6

/* max nr of sectors of setup: don't change unless you also change
* bootsect etc */
#define SETUP_SECTS 4

#define STRINGIFY(x) #x

void die(char * str)
{
fprintf(stderr,"%s\n",str);
exit(1);
}

void usage(void)
{
die("Usage: build bootsect setup system [rootdev] [> image]");
}

int main(int argc, char ** argv)
{
int i,c,id;
char buf[1024];
char major_root, minor_root;
struct stat sb;

if ((argc != 4) && (argc != 5))
usage();
if (argc == 5) {
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);
if ((major_root != 2) && (major_root != 3) &&
(major_root != 0)) {
fprintf(stderr, "Illegal root device (major = %d)\n",
major_root);
die("Bad root device --- major #");
}
for (i=0;i<sizeof buf; i++) buf[i]=0;
if ((id=open(argv[1],O_RDONLY,0))<0)
die("Unable to open 'boot'");
if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
die("Unable to read header of 'boot'");
if (((long *) buf)[0]!=0x04100301)
die("Non-Minix header of 'boot'");
if (((long *) buf)[1]!=MINIX_HEADER)
die("Non-Minix header of 'boot'");
if (((long *) buf)[3]!=0)
die("Illegal data segment in 'boot'");
if (((long *) buf)[4]!=0)
die("Illegal bss in 'boot'");
if (((long *) buf)[5] != 0)
die("Non-Minix header of 'boot'");
if (((long *) buf)[7] != 0)
die("Illegal symbol table in 'boot'");
i=read(id,buf,sizeof buf);
fprintf(stderr,"Boot sector %d bytes.\n",i);
if (i != 512)
die("Boot block must be exactly 512 bytes");
if ((*(unsigned short *)(buf+510)) != 0xAA55)
die("Boot block hasn't got boot flag (0xAA55)");
buf[508] = (char) minor_root;
buf[509] = (char) major_root;
i=write(1,buf,512);
if (i!=512)
die("Write call failed");
close (id);

if ((id=open(argv[2],O_RDONLY,0))<0)
die("Unable to open 'setup'");
if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
die("Unable to read header of 'setup'");
if (((long *) buf)[0]!=0x04100301)
die("Non-Minix header of 'setup'");
if (((long *) buf)[1]!=MINIX_HEADER)
die("Non-Minix header of 'setup'");
if (((long *) buf)[3]!=0)
die("Illegal data segment in 'setup'");
if (((long *) buf)[4]!=0)
die("Illegal bss in 'setup'");
if (((long *) buf)[5] != 0)
die("Non-Minix header of 'setup'");
if (((long *) buf)[7] != 0)
die("Illegal symbol table in 'setup'");
for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
if (write(1,buf,c)!=c)
die("Write call failed");
close (id);
if (i > SETUP_SECTS*512)
die("Setup exceeds " STRINGIFY(SETUP_SECTS)
" sectors - rewrite build/boot/setup");
fprintf(stderr,"Setup is %d bytes.\n",i);
for (c=0 ; c<sizeof(buf) ; c++)
buf[c] = '\0';
while (i<SETUP_SECTS*512) {
c = SETUP_SECTS*512-i;
if (c > sizeof(buf))
c = sizeof(buf);
if (write(1,buf,c) != c)
die("Write call failed");
i += c;
}

if ((id=open(argv[3],O_RDONLY,0))<0)
die("Unable to open 'system'");
if (read(id,buf,GCC_HEADER) != GCC_HEADER)
die("Unable to read header of 'system'");
if (((long *) buf)[5] != 0)
die("Non-GCC header of 'system'");
for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
if (write(1,buf,c)!=c)
die("Write call failed");
close(id);
fprintf(stderr,"System is %d bytes.\n",i);
if (i > SYS_SIZE*16)
die("System is too big");
return(0);
}


举报

相关推荐

0 条评论