练习1: 理解通过make生成执行文件的过程

练习1文档

  • 操作系统镜像文件ucore.img是如何一步一步生成的
  • 一个被系统认为符合规范的硬盘主引导扇区的特征是什么

相关文件

操作系统镜像文件ucore.img是如何一步一步生成的

背景知识

  1. 什么是make

    在这里,make一般指的是GNU make。在软件开发中,GNU make是一个工具程序,经由读取叫做Makefile的文件,自动化建构软件。

    它是一种转化文件形式的工具,转换的目标称为target;与此同时,它也检查文件的依赖关系,如果需要的话,它会调用一些外部软件来完成任务。它的依赖关系检查系统非常简单,主要根据依赖文件的修改时间进行判断。大多数情况下,它被用来编译源代码,生成结果代码,然后把结果代码连接起来生成可执行文件或者库文件。它使用叫做Makefile的文件来确定一个target文件的依赖关系,然后把生成这个target的相关命令传给shell去执行。

  2. 什么是Makefile

    MakefileGNU make进行操作的规则,开发者在里面定义了不同的target,可以根据需要去执行不同的操作。

    比如,在uCore中的Makefile包含以下targetlab1-mon, debug-mon, qemu-mon, qemu, qemu-nox等,直接执行make或在命令后面填写target的名称可进行不同的操作。

  3. 如何调试Makefile

    当执行make时,一般只会显示输出,不会显示make到底执行了哪些命令。

    如想了解make执行了哪些命令,可以执行:

    $ make "V="
    

    要获取更多有关make的信息,可上网查询,并请执行

    $ man make
    

问题分析

  1. 操作系统镜像文件ucore.img是如何一步一步生成的

    我们先执行make "V="查看所得输出

    + cc kern/init/init.c

    gcc -Ikern/init/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/init/init.c -o obj/kern/init/init.o

    + cc kern/libs/stdio.c

    gcc -Ikern/libs/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/stdio.c -o obj/kern/libs/stdio.o

    + cc kern/libs/readline.c

    gcc -Ikern/libs/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/libs/readline.c -o obj/kern/libs/readline.o

    + cc kern/debug/panic.c

    gcc -Ikern/debug/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/panic.c -o obj/kern/debug/panic.o

    + cc kern/debug/kdebug.c

    gcc -Ikern/debug/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/kdebug.c -o obj/kern/debug/kdebug.o

    + cc kern/debug/kmonitor.c

    gcc -Ikern/debug/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/debug/kmonitor.c -o obj/kern/debug/kmonitor.o

    + cc kern/driver/clock.c

    gcc -Ikern/driver/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/clock.c -o obj/kern/driver/clock.o

    + cc kern/driver/console.c

    gcc -Ikern/driver/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/console.c -o obj/kern/driver/console.o

    + cc kern/driver/picirq.c

    gcc -Ikern/driver/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/picirq.c -o obj/kern/driver/picirq.o

    + cc kern/driver/intr.c

    gcc -Ikern/driver/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/driver/intr.c -o obj/kern/driver/intr.o

    + cc kern/trap/trap.c

    gcc -Ikern/trap/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/trap.c -o obj/kern/trap/trap.o

    + cc kern/trap/vectors.S

    gcc -Ikern/trap/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/vectors.S -o obj/kern/trap/vectors.o

    + cc kern/trap/trapentry.S

    gcc -Ikern/trap/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/trap/trapentry.S -o obj/kern/trap/trapentry.o

    + cc kern/mm/pmm.c

    gcc -Ikern/mm/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Ikern/debug/ -Ikern/driver/ -Ikern/trap/ -Ikern/mm/ -c kern/mm/pmm.c -o obj/kern/mm/pmm.o

    + cc libs/string.c

    gcc -Ilibs/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -c libs/string.c -o obj/libs/string.o

    + cc libs/printfmt.c

    gcc -Ilibs/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -c libs/printfmt.c -o obj/libs/printfmt.o

    + ld bin/kernel

    ld -m elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel obj/kern/init/init.o obj/kern/libs/stdio.o obj/kern/libs/readline.o obj/kern/debug/panic.o obj/kern/debug/kdebug.o obj/kern/debug/kmonitor.o obj/kern/driver/clock.o obj/kern/driver/console.o obj/kern/driver/picirq.o obj/kern/driver/intr.o obj/kern/trap/trap.o obj/kern/trap/vectors.o obj/kern/trap/trapentry.o obj/kern/mm/pmm.o obj/libs/string.o obj/libs/printfmt.o

    + cc boot/bootasm.S

    gcc -Iboot/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootasm.S -o obj/boot/bootasm.o

    + cc boot/bootmain.c

    gcc -Iboot/ -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootmain.c -o obj/boot/bootmain.o

    + cc tools/sign.c

    gcc -Itools/ -g -Wall -O2 -c tools/sign.c -o obj/sign/tools/sign.o

    gcc -g -Wall -O2 obj/sign/tools/sign.o -o bin/sign

    + ld bin/bootblock

    ld -m elf_i386 -nostdlib -N -e start -Ttext 0x7C00 obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o

    'obj/bootblock.out' size: 496 bytes

    build 512 bytes boot sector: 'bin/bootblock' success!

    dd if=/dev/zero of=bin/ucore.img count=10000

    dd if=bin/bootblock of=bin/ucore.img conv=notrunc

    dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc

    注意: 此处仅列出stdout的输出结果,并没有列出stderr的内容;在进行编译/链接操作时,先输出了命令的简化描述,后输出了执行的完整命令

    由该内容可以看出,make进行操作的顺序为

    1. 编译kern目录下的所有文件(cc kern/*

    2. 链接以上文件,生成内核文件kernelld bin/kernel

      其文件格式为:bin/kernel: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped

    3. 编译boot目录下的所有文件(cc boot/*

    4. 编译用来生成扇区文件的工具sign.ccc tools/sign.c

    5. 链接boot目录编译出的文件,生成文件bootblockld bin/bootblock

      注意: 在链接bootblock时,ld命令指定了程序bootasm被实际加载到内存的位置为0x7C00。另外,进一步分析Makefile文件可以得知,ld链接后的文件为bootblock.o,该文件为Linux下的可执行文件。而后经过objcopy命令,将该可执行文件复制并转换为纯粹的,机器可直接执行的二进制文件bootblock.out,同时也为其缩小了文件尺寸,从超过1k缩小到了512字节以内,为编辑成主引导扇区提供了条件。

      #    File:    Makefile
      #    Line:    156
      
          @$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock)
      
    6. bootblock编辑成为符合规范的硬盘主引导扇区

      注意:make "V="的输出内未列出执行的命令(该命令位于Makefile第157行),但列出了sign执行的结果(见下方代码):

      build 512 bytes boot sector: 'bin/bootblock' success!

      执行完成后,bootblock的文件格式为:bin/bootblock: DOS/MBR boot sector

      #        File:    Makefile
      #        Line:    157
      
          @$(call totarget,sign) $(call outfile,bootblock) $(bootblock)
      
      //    File:    sign.c
      //    Line:    40
      
          printf("build 512 bytes boot sector: '%s' success!\n", argv[2]);
      
    7. 使用dd命令创建空的镜像ucore.img,然后将bootblockkernel分别写入ucore.img,至此创建完成。

参考文献

一个被系统认为符合规范的硬盘主引导扇区的特征是什么

背景知识

  1. 什么是主引导扇区

    主引导扇区位于整个磁盘的0磁头0柱面1扇区,包括主引导记录和分区表。

问题分析

  1. 符合规范的硬盘主引导扇区的特征是什么

    查阅文档可知,主引导扇区的特征为:

    1. 大小为512字节

    2. 0x55AA结束

    参考tools/sign.c可以发现,该代码执行结果符合以上特征

    //    File:    sign.c
    //    Line:    22
    
    char buf[512];
    
    //    Line:    31-34
    
    buf[510] = 0x55;
    buf[511] = 0xAA;
    FILE *ofp = fopen(argv[2], "wb+");
    size = fwrite(buf, 1, 512, ofp);
    

    该代码定义了长度为512的char型数组buf,把最后两个字节设为0x55AA后将其写入文件。

参考文献

results matching ""

    No results matching ""

    results matching ""

      No results matching ""