ucore/docs/lab1/练习一.md

12 KiB
Raw Permalink Blame History

练习一


lab1中包含一个bootloader和一个OS。这个bootloader可以切换到X86保护模式能够读磁盘并加载ELF执行文件格式并显示字符。而这lab1中的OS只是一个可以处理时钟中断和显示字符的幼儿园级别OS。

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

回答:在 labcodes/lab1 目录下运行 make "V=" 得到如下结果:

# 编译 init.c 文件,生成 init.o 
+ cc kern/init/init.c
gcc -Ikern/init/ -fno-builtin -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

# 编译 stdio.c 文件,生成 stdio.o
+ cc kern/libs/stdio.c
gcc -Ikern/libs/ -fno-builtin -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

# 编译 readline.c 文件,生成 readline.o
+ cc kern/libs/readline.c
gcc -Ikern/libs/ -fno-builtin -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

# 编译 panic.c 文件,生成 painc.o
+ cc kern/debug/panic.c
gcc -Ikern/debug/ -fno-builtin -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

# 编译 kdebug.c 文件,生成 kdebug.o
+ cc kern/debug/kdebug.c
gcc -Ikern/debug/ -fno-builtin -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

# 编译 kmonitor.c 文件,生成 kmonitor.o
+ cc kern/debug/kmonitor.c
gcc -Ikern/debug/ -fno-builtin -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

# 编译 clock.c 文件,生成 clock.o
+ cc kern/driver/clock.c
gcc -Ikern/driver/ -fno-builtin -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

# 编译 console.c 文件,生成 console.o
+ cc kern/driver/console.c
gcc -Ikern/driver/ -fno-builtin -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

# 编译 picirq.c 文件,生成 picirq.o
+ cc kern/driver/picirq.c
gcc -Ikern/driver/ -fno-builtin -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

# 编译 intr.c 文件,生成 intr.o
+ cc kern/driver/intr.c
gcc -Ikern/driver/ -fno-builtin -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

# 编译 trap.c 文件,生成 trap.o
+ cc kern/trap/trap.c
gcc -Ikern/trap/ -fno-builtin -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

# 编译 vectors.S 生成 vectors.o
+ cc kern/trap/vectors.S
gcc -Ikern/trap/ -fno-builtin -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

# 编译 trapentry.S 生成 trapentry.o
+ cc kern/trap/trapentry.S
gcc -Ikern/trap/ -fno-builtin -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

# 编译 pmm.c 生成 pmm.o
+ cc kern/mm/pmm.c
gcc -Ikern/mm/ -fno-builtin -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

# 编译 string.c 生成 string.o
+ cc libs/string.c
gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/  -c libs/string.c -o obj/libs/string.o

# 编译 printfmt.c 生成 printfmt.o
+ cc libs/printfmt.c
gcc -Ilibs/ -fno-builtin -Wall -ggdb -m32 -gstabs -nostdinc  -fno-stack-protector -Ilibs/  -c libs/printfmt.c -o obj/libs/printfmt.o

# 链接生成的所有目标文件,并生成 kernel 二进制文件
+ 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

# 编译 bootasm.S / bootmain.c / sign.c / 
+ cc boot/bootasm.S
gcc -Iboot/ -fno-builtin -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 -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

# 生成 sign 文件
gcc -g -Wall -O2 obj/sign/tools/sign.o -o bin/sign

# 链接生成 bootblock 二进制文件
+ 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: 488 bytes
build 512 bytes boot sector: 'bin/bootblock' success!

# 生成ucore.img 文件
dd if=/dev/zero of=bin/ucore.img count=10000
10000+0 records in
10000+0 records out
5120000 bytes (5.1 MB, 4.9 MiB) copied, 0.0242314 s, 211 MB/s
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
1+0 records in
1+0 records out
512 bytes copied, 9.9196e-05 s, 5.2 MB/s
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
146+1 records in
146+1 records out
74828 bytes (75 kB, 73 KiB) copied, 0.000607019 s, 123 MB/s

注意:上面显示的编译过程,我删去了一些警告信息。只将有用的信息标记出来。

GCC 编译选项详解:

编译选项 含义
-I 指定库文件包含路径(① 指定值 ② 环境变量 ③ 标准系统搜索路径)
-fno-builtin 只识别以 __builtin_为前缀的 GCC 內建函数,禁用大多数內建函数,防止与其重名
-Wall 编译后显示所有警告信息
-ggdb 使用 GDB 加入调试信息
-m32 生成 32位机器代码,int long pointer 都是 32 位,指定x86处理器特定选项 处理器依赖选项
-gstabs 产生 stabs 格式的调试信息,不包含 GDB 扩展
-nostdinc 不搜索标准系统目录的头文件,只搜索 -I / -iquote / -isystem / -dirafter指定的头文件, 目录选项
-fno-stack-protector 禁用堆栈保护机制,工具选项
-c 编译或汇编源文件,但是不进行链接。将.c/.i/.s等后缀的文件编译成 .o 后缀。输出类型控制
-O 优化生成的代码,-Os 仅仅是优化生成代码的大小,它开启了所有的-O2优化选项,除了那些会使代码尺寸增大的选项。 优化选项

LD 编译选项详解:

编译选项 含义
-m 指定生成文件的格式,默认使用 LDEMULATION环境变量如果没有这个环境变量则依赖与linker 的默认配置。通过 ld -V 可以查看它支持的 emulation
-nostdlib 只搜索命令行中显示制定的库目录,链接脚本里面制定的目录被忽略,包括命令行中制定的链接脚本。
-N 设置 text and data section 可读写,数据段不进行页对其,不链接动态链接库
-e entry 指定程序开始执行的入口函数,而不是默认的入口点。
-Tbss=org / -Tdata=org / -Ttext=org 通过 org 制定一个 section 在输出文件中的绝对地址。

dd 磁盘维护命令详解:

Linux dd命令用于读取、转换并输出数据。dd可从标准输入或文件中读取数据根据指定的格式来转换数据再输出到文件、设备或标准输出。

if = 文件名:输入文件名,缺省为标准输入。
of = 文件名:输出文件名,缺省为标准输出。
	ibs = bytes一次读入bytes个字节即指定一个块大小为bytes个字节。默认 512 字节)
	obs = bytes一次输出bytes个字节即指定一个块大小为bytes个字节。默认 512 字节)
	bs = bytes同时设置读入/输出的块大小为bytes个字节。
	cbs = bytes一次转换bytes个字节即指定转换缓冲区大小。
skip = blocks从输入文件开头跳过blocks个块后再开始复制。
seek = blocks从输出文件开头跳过blocks个块后再开始复制。
count = blocks仅拷贝blocks个块块大小等于ibs指定的字节数。
conv = <关键字>关键字可以有以下11种
	conversion用指定的参数转换文件。
	ascii转换ebcdic为ascii
	ebcdic转换ascii为ebcdic
	ibm转换ascii为alternate ebcdic
	block把每一行转换为长度为cbs不足部分用空格填充
	unblock使每一行的长度都为cbs不足部分用空格填充
	lcase把大写字符转换为小写字符
	ucase把小写字符转换为大写字符
	swab交换输入的每对字节
	noerror出错时不停止
	notrunc不截短输出文件
	sync将每个输入块填充到ibs个字节不足部分用空NUL字符补齐。

N and BYTES may be followed by the following multiplicative suffixes:
c =1, w =2, b =512, kB =1000, K =1024, MB =1000*1000, M =1024*1024, xM =M
GB =1000*1000*1000, G =1024*1024*1024, and so on for T, P, E, Z, Y.

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

回答:硬盘主引导扇区的 size = 512 Bytes并且最后两个字节为0x55AA