练习1 report

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

  1.   GNU make是一种代码维护工具,在大中型项目中,它将根据程序各个模块的更target新情况,自动地维护和生成目标代码。make命令执行时,需要一个Makefile文件,以告诉make命令需要怎样去编译和链接程序。使用Makefile文件时,有如下规则:(1)如果这个工程没有编译过,那么所有的c文件都要编译并链接;(2)如果这个工程的某几个c文件被修改,那么只编译被修改的c文件,并链接目标程序;(3)如果这个工程的头文件被改变了,那么需要编译引用这几个头文件的c文件,并链接目标程序。

    Makefile文件大致由target、prerequisites、command组成,target表示要生成的目标文件,prerequisites指要生成target所需要的文件或是目标,command是make需要执行的命令(shell命令),必须以[tab]开头。只要prerequisites中有一个以上的文件比文件要新,command的指令就会被执行,这就是Makefile的规则。

    2.    编译所有生成bin/kernel所需的文件:

生成这些.o文件的相关makefile代码为

$(call add_files_cc,$(call listf_cc,$(KSRCDIR)),kernel,$(KCFLAGS))

1) init.c是OS的初始化启动代码,把init.c编译为名为init.o的中间目标文件(-c参数表示生成init.o的目标文件,-o表示生成可执行文件。gcc -c a.c -o a.o表示把源文件a.c编译成指定文件名a.o的中间目标文件。):

gcc -c kern/init/init.c -o obj/kern/init/init.o

2) 把readline.c编译为名为readline的中间目标文件:

gcc -c kern/libs/readline.c -o obj/kern/libs/readline.o

3) 编译stdio.c生成stdio.o:

gcc -c kern/libs/stdio.c -o obj/kern/libs/stdio.o

4) kdebug.c提供源码和二进制对应关系的查询功能,用于显示调用栈关系。编译kdebug.c生成kdebug.o:

gcc  -c kern/debug/kmonitor.c -o obj/kern/debug/kmonitor.o

5) panic.c提供了panic函数,便于在发现错误后,调用kernel monitor。编译panic.c生成panic.o:

gcc  -c kern/debug/panic.c -o obj/kern/debug/panic.o

6) clock.c实现了对时钟控制器8253的初始化操作。编译clock.c生成panic.o:

gcc  -c kern/driver/clock.c -o obj/kern/driver/clock.o

7) kmonitor.c实现提供动态分析命令的kernel monitor,便于在ucore出现bug或问题之后,能够进入kernel monitor中,查看当前调用关系。编译kmonitor.c生成kmonitor.o:

gcc  -c kern/debug/kmonitor.c -o obj/kern/debug/kmonitor.o

8) console.c实现了对串口和键盘的中断方式的处理操作。将console.c编译生成console.o:

gcc -c kern/driver/console.c -o obj/kern/driver/console.o

9) intr.c实现了通过设置CPU的Eflags来屏蔽和使能中断的函数。编译intr.c生成intr.o:

gcc -c kern/driver/intr.c -o obj/kern/driver/intr.o

10) picirq.c实现了对控制中断器8259A的初始化和使能操作。编译picriq.c生成picriq.o:

gcc -c kern/driver/picirq.c -o obj/kern/driver/picirq.o

11) vectors.S包括256个中断服务例程的入口地址和第一步初步处理时先。此文件是由tools/vector.c在编译ucore期间动态生成的。编译voctor.S生成vector.o:

gcc -c kern/trap/vectors.S -o obj/kern/trap/vectors.o

12) trapentry.S紧接着第一步初步处理后,进一步完成第二步初步处理;并且又恢复中断上下文的处理,即中断处理完毕后的返回准备操作。编译trapentry.S生成trapentry.o:

gcc -c kern/trap/trapentry.S -o obj/kern/trap/trapentry.o

13) trap.c紧接着第二步初步处理后,继续完成具体的各种中断处理操作。编译trap.c生成trap.o:

gcc -c kern/trap/trap.c -o obj/kern/trap/trap.o

14) pmm.c设定ucore操作系统在段机制中要用到的全局变量:任务状态栏ts,全局描述符表gdt[],加载全局描述符表寄存器的函数lgdt,临时的内核栈stack(),以及对全局描述符表和任务状态段的初始化函数gdt_init。编译pmm.c生成pmm.o:

gcc -c kern/mm/pmm.c -o obj/kern/mm/pmm.o

15) 编译printfmt.c生成printfmt.o:

gcc -c libs/printfmt.c -o obj/libs/printfmt.o

16) 编译string.c生成string.o:

gcc -c libs/string.c -o obj/libs/string.o

  3.链接生成bin/kernel:

生成kernel需要第一步所生成的那些.o文件和kernel.ld,而kernel.ld已经存在。生成kernel的Makefile相关代码为

$(kernel): tools/kernel.ld

$(kernel): $(KOBJS)

@echo + ld $@

$(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS)

@$(OBJDUMP) -S $@ > $(call asmfile,kernel)

@$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; \

/^$$/d' > $(call symfile,kernel)

ld -m    elf_i386 -nostdlib -T tools/kernel.ld -o bin/kernel \

obj/kern/init/init.o obj/kern/libs/readline.o \

obj/kern/libs/stdio.o obj/kern/debug/kdebug.o \

obj/kern/debug/kmonitor.o obj/kern/debug/panic.o \

obj/kern/driver/clock.o obj/kern/driver/console.o \

obj/kern/driver/intr.o obj/kern/driver/picirq.o \

obj/kern/trap/trap.o obj/kern/trap/trapentry.o \

obj/kern/trap/vectors.o obj/kern/mm/pmm.o \

obj/libs/printfmt.o obj/libs/string.o

其中ld命令是关键,用于把目标代码文件连接为可执行文件或者库文件:

-m模拟指定的连接器elf_i386;

-T指定命令文件为tools/kernel.ld,即让连接器使用指定的该脚本;

-o指定输出文件名字为kernel。

  4.生成bootblock:

在生成bootblock之前需要生成bootasm.o、bootmain.o、sign:

1) 生成bootasm.o需要bootasm.S,bootasm.S定义并实现bootloader最先执行的函数start,此函数进行了一定的初始化,完成了从实模式到保护模式的转换,并调用了bootmain.c中的bootmain函数。实际命令为:

gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs \

-nostdinc  -fno-stack-protector -Ilibs/ -Os -nostdinc \

-c boot/bootasm.S -o obj/boot/bootasm.o

关键的参数:

-ggdb:生成可供gdb使用的调试信息。这样才能用qemu+gdb来调试bootloader or ucore;

-m32:生成适用于32位环境的代码。我们用的模拟硬件是32bit的80386,所以ucore也要是32位的软件;

-gstabs:生成stabs格式的调试信息。这样要ucore的monitor可以显示出便于开发者阅读的函数调用栈信息

-nostdinc:不使用标准库。标准库是给应用程序用的,我们是编译ucore内核,OS内核是提供服务的,所以所有的服务要自给自足。

-fno-stack-protector:不生成用于检测缓冲区溢出的代码。

-Os:为减小代码大小而进行优化。根据硬件spec,主引导扇区只有512字节,我们写的简单bootloader的最终大小不能大于510字节。

-I<dir>:添加搜索头文件的路径。

-Wall:产生尽可能多的警告信息。

-fno-builtin:除非用__builtin_前缀,否则不进行builtin函数的优化

2) 生成bootmain.o需要bootmain.c,bootmain.c定义并实现了bootmain函数,实现了通过屏幕、串口和并口显示字符串,bootmain函数加载ucore操作系统到内存,然后跳到ucore的入口处执行。实际命令为:

gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc \

-fno-stack-protector -Ilibs/ -Os -nostdinc \

-c boot/bootmain.c -o obj/boot/bootmain.o

其参数与前面提到的一致。

3) 生成sign需要sign.c,sign.c是一个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

关键的参数:

-I<dir>:添加搜索头文件的路径。

-Wall:产生尽可能多的警告信息。

-O2:优化程序。

-g:生成可供gdb使用的调试信息。

4) 由bootasm.o,bootmain.o,sign生成bootblock.o:

实际命令为:

ld -m elf_i386 -nostdlib -N -e start -Ttext 0x7C00 \

obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o

关键的参数:

-m:模拟指定的连接器为elf_i386;

-N:指定读取/写入文本和数据段;

-e:使用指定的符号start作为程序的初始执行点;

-Ttext:使用指定的地址0x7C00作为文本段的起始点;

-nonstdlib:不使用标准库。

5) 拷贝二进制代码bootblock.o到bootblock.out

objcopy -S -O binary obj/bootblock.o obj/bootblock.out

关键的参数:

-S:移除所有符号和重定位信息

-O <bfdname>:指定输出格式

6) 使用sign工具处理bootblock.out,生成bootblock

bin/sign obj/bootblock.out bin/bootblock

  

  5.生成ucore.img:

1) 生成一个有10000个块的文件,每个块默认512字节,用0填充

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

2) 把bootblock中的内容写到第一个块

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

3) 从第二个块开始写kernel中的内容

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

其中dd命令的作用是用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的 转换。第一条命令即将/dev/zero全盘数据,这里用0填充,备份到bin/下的 ucore.img文件。

关键参数:

if=文件名:输入文件名,缺省即标准输入;

of=文件名:输出文件名,缺省即标准输出;

seek=blocks:从输出文件开头跳过blocks个块后开始复制;

conv:用指定的参数转换文件,此处的参数notrunc为不截短输出文件。

 

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

通常,我们将包含MBR引导代码的扇区称为主引导扇区。通常由3部分组成:

主引导程序(MBR,占446字节)、磁盘分区表项(占4×16个字节,负责说明磁盘上的分区情况)、结束标志(占2个字节,其值为AA55)。

因为sign.c是用于生成一个符合规范的硬盘主引导扇区,所以我截取了sign.c中的部分代码并加以注释来更清晰地分析主引导分区的特征:

char buf[512];          //定义buff数组

memset(buf, 0, sizeof(buf));     //将buff数组初始化为0

buf[510] = 0x55;

buf[511] = 0xAA;    //将buff数组最后两位初始化为0x55,0xAA

得出主引导扇区的特征:

  1. 大小为512个字节;
  2. 第510个字节为0x55;
  3. 第511个字节为0xAA;
  4. 其余字节为0。

ucore-lab1-练习1report的更多相关文章

  1. 《ucore lab1》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 练习1:理解通过make生成执行文件的过程 详见<ucore lab1 exercise1>实验报告 练习2:使用qemu执行并调试 ...

  2. ucore lab1 bootloader学习笔记

    ---恢复内容开始--- 开机流程回忆 以Intel 80386为例,计算机加电后,CPU从物理地址0xFFFFFFF0(由初始化的CS:EIP确定,此时CS和IP的值分别是0xF000和0xFFF0 ...

  3. 《ucore lab1 exercise5》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:实现函数调用堆栈跟踪函数 我们需要在lab1中完成kdebug.c中函数print_stackframe的实现,可以通过函数print_s ...

  4. 《ucore lab1 exercise3》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:分析bootloader进入保护模式的过程 BIOS将通过读取硬盘主引导扇区到内存,并转跳到对应内存中的位置执行bootloader.请分 ...

  5. 《ucore lab1 exercise2》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:使用qemu执行并调试lab1中的软件 为了熟悉使用qemu和gdb进行的调试工作,我们进行如下的小练习: 从CPU加电后执行的第一条指令 ...

  6. 《ucore lab1 exercise1》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:理解通过make生成执行文件的过程 列出本实验各练习中对应的OS原理的知识点,并说明本实验中的实现部分如何对应和体现了原理中的基本概念和关 ...

  7. ucore操作系统学习笔记(一) ucore lab1系统启动流程分析

    一.ucore操作系统介绍 操作系统作为一个基础系统软件,对下控制硬件(cpu.内存.磁盘网卡等外设),屏蔽了底层复杂多样的硬件差异:对上则提供封装良好的应用程序接口,简化应用程序开发者的使用难度.站 ...

  8. Ucore lab1实验报告

    练习一 Makefile 1.1 OS镜像文件ucore.img 是如何一步步生成的? + cc kern/init/init.c + cc kern/libs/readline.c + cc ker ...

  9. ucore lab1练习2 qemu+gdb 不能协作调试的问题make lab1-mon

    本练习是qemu结合gdb调试,但是我做实验的时候并不能像视频输入make lab1-mon那样顺利调试,期间有各种error,后来我找到原因,请看解决方法. 请先把ucore_lab文件删除,以下全 ...

  10. 《ucore lab1 exercise4》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:分析bootloader加载ELF格式的OS的过程 通过阅读bootmain.c,了解bootloader如何加载ELF文件.通过分析源代 ...

随机推荐

  1. PHP + NGINX 控制视频文件播放,并防止文件下载

    最简单的方法是使用NGINX的 internal 功能 server {    listen 80;    server_name www.xxx.com;     location / {      ...

  2. span标签 宽度无效解决方案

    完美的解决方案 下 面代码的CSS定义完美解决了span的宽度设置问题. 由于浏览器通常对不支持的CSS属性采取忽略处理的态度, 所以最好将display:inline -block行写在后面,这样在 ...

  3. HashSet和LinkedHashSet解析

    一.简介 1.Set概念 Set可以理解为集合,非常类似数据概念中的集合,集合三大特征:1.确定性:2.互异性:3.无序性,因此Set实现类也有类似的特征. 2.HashSet HashSet继承自A ...

  4. Linux命令:unzip

    语法: unzip [-Z] [-opts[modifiers]] file[.zip] [list] [-x xlist] [-d exdir] 默认行为将zip文件中的内容全部解压缩到当前目录下. ...

  5. svn的上传冲突问题

    上传报错实际是 1 . 之前上传的代码与现代码不一样 2. 上传的代码中有错误 需要先拉下来,对比删除不要的,再上传 eclipse加入svn :  1.import  ---从svn检出项目---创 ...

  6. Spring3.0学习1.2(使用annotation)

    使用annotation 首先 xml文件更改  新加xslt <?xml version="1.0" encoding="UTF-8"?> < ...

  7. C# WInForm中 窗体的this.width和this.height的属性值不能大于显示器的最大分辨率

    最近在做一个小项目的时候,发现在 1680x1050 分辨率显示器上写的代码,将窗体的宽度和高度 设置成了 1600×900,在高于1600×900的分辨率上缩放显示很正常, 而后转移到 分辨率低于 ...

  8. kubernetes ui 搭建

    1.部署Kubernetes云计算平台,至少准备两台服务器,此处为3台 Kubernetes Master节点:192.168.0.111 Kubernetes Node1节点:192.168.0.1 ...

  9. bootstrap 参考文档

    https://getbootstrap.com/docs/3.3/css/#sass-installation

  10. OpenCV批量读入(处理)

    #include <windows.h> #include <iostream> #include <opencv2/opencv.hpp> using names ...