ucore练习一实验报告

问题1: 操作系统镜像文件 ucore-img 是如何一步一步生成的(需要比较详细的解释Makefile中的每一条相关命令和命令参数的含义,以及说明命令导致的结果)?

生成ucore-img的代码:

下述代码取自Makefile文件中

UCOREIMG := $(call totarget,ucore.img)   //此时通过call函数来实现创建ucore.img的过程,UCOREIMG代表的就是即将生成的ucore.img文件     
$(UCOREIMG): $(kernel) $(bootblock)        //这里表示ucore-img文件的生成依赖于kernel 和 bootblock 
     $(V)dd if=/dev/zero of=$@ count=10000    //为UCOREIMG分配一个10000*512字节大小的空间
     $(V)dd if=$(bootblock) of=$@ conv=notrunc  //将bootblock拷贝到UCOREIMG中,大小为521字节
     $(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc //将kernel拷贝到UCOREIMG中,从文件开头跳过seek个块之后开始拷贝

$(call create_target,ucore.img)

上述的UCOREEIMG文件的生成依赖于kernel和bootblock。下述给出kernel生成的代码以及bootblock生成的代码

创建kernel

# create kernel target
kernel = $(call totarget,kernel)

$(kernel): tools/kernel.ld        //生成kernel目标文件需要依赖于kernel的链接配置文件以及tools

$(kernel): $(KOBJS)               //kernel的生成还依赖KOBJS
	@echo + ld $@                 //$@代表目标文件 将以下文件和目标文件链接起来
	$(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS)   //链接obj/libs/*和obj/kernel/init/*...所有的目标文件,使用kernel.ld做连接器脚本
	@$(OBJDUMP) -S $@ > $(call asmfile,kernel)   //最终的内核文件去除符号表等信息,并输出符号表信息,汇编文件信息,和输出信息
	@$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,kernel)

$(call create_target,kernel)

# -------------------------------------------------------------------

创建bootblock

# create bootblock             //为了生成bootblock,首先应生成bootasm.o,bootmain.c和sign
bootfiles = $(call listf_cc,boot)      //用boot替换listf_cc里面的变量,将listf_cc的返回值赋给bootfiles
$(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc))

bootblock = $(call totarget,bootblock) 

$(bootblock): $(call toobj,$(bootfiles)) | $(call totarget,sign)  //生成目标文件bootblock需要依赖于sign和bootfiles
	@echo + ld $@        //将以下文件与bootblock连接起来
	$(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 $^ -o $(call toobj,bootblock)
	@$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock)    //移除bootblock中所有的符号和重定位信息
	@$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock)
	@$(call totarget,sign) $(call outfile,bootblock) $(bootblock)

$(call create_target,bootblock)

# -------------------------------------------------------------------

下面表示在终端中运行make qemu指令编译链接生成ucore.img文件的过程

+ cc kern/init/init.c
+ cc kern/libs/readline.c
+ cc kern/libs/stdio.c
+ cc kern/debug/kdebug.c
+ cc kern/debug/kmonitor.c
+ cc kern/debug/panic.c
+ cc kern/driver/clock.c
+ cc kern/driver/console.c
+ cc kern/driver/intr.c
+ cc kern/driver/picirq.c
+ cc kern/trap/trap.c
+ cc kern/trap/trapentry.S
+ cc kern/trap/vectors.S
+ cc kern/mm/pmm.c
+ cc libs/printfmt.c
+ cc libs/string.c
+ ld bin/kernel

在ubuntu下使用make qemu运行lab1_result指令,出现了上述的代码。cc在这里代表gcc 表示编译源文件。可以看到在生成ucore.img的过程中,首先对kern文件下的一系列.c和.s文件进行了编译。随后的ld表示链接,ld bin/kernel表示将bin以及kern下的所有文件链接起来,最后通过此条命令生成kernel程序

+ cc boot/bootasm.S
+ cc boot/bootmain.c
+ 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

通过cc对boot底下的bootasm.S和bootmain.c文件进行了编译,同时也将tools下的sign.c文件也进行了编译,随后通过ld指令,生成了bootblock程序

dd if=/dev/zero of=bin/ucore.img count=10000
10000+0 records in
10000+0 records out
5120000 bytes (5.1 MB) copied, 0.0456474 s, 163MB/s
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.00281044 s, 134 kB/s
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
138+1 records in
138+1 records out
70775 bytes (71 kB) copied, 0.000473867 s, 127 MB/s

通过dd指令,将生成的kernel和bootblock的ELF文件拷贝到ucore.img当中,根据拷贝的顺序可以看到,首先是将bootblock拷贝进了ucore.img,然后才是将kernel拷贝进ucore.img,所以可以得出bootblock是引导区,kernel是操作系统内核。

  • 综上 ucore.img文件的生成主要经过下面几步:

1 编译所有生成bin/kernel所需的文件
2 链接生成bin/kernel
3 编译bootasm.S bootmain.c sign.c
4 根据sign规范生成obj/bootblock.o
5 生成ucore.img

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

根据问题1可知通过sign.c文件的操作使得bootblock.o成为一个符合规范的引导扇区,因此查看sign.c的内容

sign.c的部分代码

char buf[512];
    memset(buf, 0, sizeof(buf));
    FILE *ifp = fopen(argv[1], "rb");  //rb表示读取二进制文件
    int size = fread(buf, 1, st.st_size, ifp);
    // 文件实际大小需和文件头描述一致
    if (size != st.st_size) {
        fprintf(stderr, "read '%s' error, size is %d.\n", argv[1], size);
        return -1;
    }
    fclose(ifp);
    buf[510] = 0x55;
    buf[511] = 0xAA;
    // 写入结束位
    FILE *ofp = fopen(argv[2], "wb+");
    size = fwrite(buf, 1, 512, ofp);
    if (size != 512) {
        fprintf(stderr, "write '%s' error, size is %d.\n", argv[2], size);
        return -1;
    }

主引导扇区的规则如下:

大小为512字节
多余的空间填0
第510个(倒数第二个)字节是0x55,
第511个(倒数第一个)字节是0xAA。

发布了33 篇原创文章 · 获赞 2 · 访问量 1737

猜你喜欢

转载自blog.csdn.net/weixin_42469716/article/details/88534618