BUAA_OS_lab1

操作系统lab1学习日记

一、思考题

Thinking1.1

  • objdump -DS 要反汇编的目标文件名 > 导出文本文件名
    • -D:反汇编所有的section;
    • -d:反汇编那些特定指令机器码的section;
    • -S :尽可能反汇编出源代码,尤其当编译的时候指定了-g 这种调试参数时,效果比较明显,隐含了-d参数;
    • -s:显示指定section的完整内容。默认所有的非空section都会被显示

printf 的实现是在链接 (Link) 这一步骤中被插入到最终的可执行文件中的。节省了过程中对printf这些频繁使用的程序的编译。

编译链接

Thinking1.2

问题:

  • 尝试使用我们编写的 readelf 程序,解析之前在 target 目录下生成的内核 ELF 文 件。
  • 也许你会发现我们编写的 readelf 程序是不能解析 readelf 文件本身的,而我们刚 才介绍的系统工具 readelf 则可以解析,这是为什么呢?(提示:尝试使用 readelf -h,并阅读 tools/readelf 目录下的 Makefile,观察 readelf 与 hello 的不同)

readelf [option(s)] ,用来解析一个或者多个 ELF 文件的信息,使用readeif可以查看具体用法,我们执行 readelf -S hello 命令后,hello 文件中各个节的详细信息将以列表的形式为我们展示出来。我们可以利用 readelf 工具来验证我们自己写的简易版 readelf 输出的结果是否正确,还可以使用 readelf —help 看到该命令各个选项及其对 ELF 文件的解析方式

执行./tools/readelf/readelf ./target/mos后输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mos
0:0x0
1:0x80020000
2:0x80022080
3:0x80022098
4:0x800220b0
5:0x0
6:0x0
7:0x0
8:0x0
9:0x0
10:0x0
11:0x0
12:0x0
13:0x0
14:0x0
15:0x0
16:0x0
17:0x0

执行readelf -h readelf输出如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ELF 头:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
类别: ELF64
数据: 2 补码,小端序 (little endian)
Version: 1 (current)
OS/ABI: UNIX - System V
ABI 版本: 0
类型: DYN (Position-Independent Executable file)
系统架构: Advanced Micro Devices X86-64
版本: 0x1
入口点地址: 0x1180
程序头起点: 64 (bytes into file)
Start of section headers: 14488 (bytes into file)
标志: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 30

./readelf readelf无输出,readelf无法解析本身但是readelf命令可以

下面的图用于辅助理解下面的Makefile

Makefile预定义变量

readelf 与 hello 的不同在于hello有static修饰是静态的,且hello文件被编译为32位而readelf是64位的

1
2
3
4
5
6
readelf: main.o readelf.o
$(CC) $^ -o $@

hello: hello.c
$(CC) $^ -o $@ -m32 -static -g
#-g可执行程序包含调试信息,-g为了调试用的,加个-g 是为了gdb 用,不然gdb用不到

Thinking1.3

问题:

在理论课上我们了解到,MIPS 体系结构上电时,启动入口地址为 0xBFC00000 (其实启动入口地址是根据具体型号而定的,由硬件逻辑确定,也有可能不是这个地址,但 一定是一个确定的地址),但实验操作系统的内核入口并没有放在上电启动地址,而是按照 内存布局图放置。思考为什么这样放置内核还能保证内核入口被正确跳转到? (提示:思考实验中启动过程的两阶段分别由谁执行。)

解答:

  • bootloader 将内核可执行文件拷贝到内存中,之后将控制权交给操作系统,只需要启动入口地址为 bootloader 的入口地址。
  • Linker Script——控制加载地址,Linker Script 中记录了各个节应该如何映射到段,以及各个段应该被加载到的位置。程序执行的第一条指令的地址称为入口地址(entrypoint),与此同时kernel.lds规定了 ENTRY(_start) ,即把内核入口定为 _start 这个函数。
  • 通过对 /init/start.S 中 _start 函数的设置,即可以正确的跳转至 mips_init 函数。

二、测试题Exercise

exercise 1.1

核心思路:认识结构体中各个变量的意义计算地址及其他变量即可

测试结果:

exercise1.1

exercise 1.2

Linker Script

.text 保存可执行文件的操作指令。 .data 保存已初始化的全局变量和静态变量。 .bss 保存未初始化的全局变量和静态变量。

1
2
3
4
5
. = 0x8002000; /*load address of test section*/
/*。例如“.bss : {*(.bss)}”表示将所有输入文件中的 .bss 节(右边的 .bss)都放到输出的 .bss 节(左边的 .bss)中,请注意代码结尾无;*/
.test : {*(.test)}
.data : {*(.data)}
.bss : {*(.bss)}

exercise 1.3

1
2
3
4
/* set up the kernel stack */
/*注意Kernel Stack是向下增长,即栈顶在低地址*/
li sp, 0x80400000
jal mips_init

exercise 1.4

根据格式符%[flags][width][length]补齐即可

三、难点分析与感想

lab1实验主要是大致理解printf函数的内部实现,与我们最初印象不同,printf并不是全部在C语言库中全部实现,而是通过一系列编译链接后,在操作系统基础上实现。

3.1 编译链接部分

在链接阶段,链接器会将所有的目标文件链接在一起,并填写具体的地址等信息,形成最终的可执行文件。核心在于ELF文件

ELF文件结构

其由五部分构成,ELF头(包含程序基本信息、段头表与节头表的偏移量)、段头表、节头表、段头表中的每一个表项(记录了该段数据载入内存时的目标位置等,记录了用于指导应用 程序加载的各类信息)、节头表(记录了该段数据载入内存时的目标位置等,记录了用于指导应用 程序加载的各类信息)

3.2 内存布局以及内核被加载到哪里

附录中给出了对于内存布局,根据Linker Script——控制加载地址,在使用了我们自定义的 Linker Script 以后,生成的程序中,各个节的位置就被 调整到了我们所指定的地址上。段是由节组合而成的,节的地址被调整了,那么最终段的地址也 会相应地被调整,我们的实验就在 kernel.lds 中通过 ENTRY(_start) 来设置程序入口为 _start。

3.3 Make中是如何构建内核的?

mos 的构建会在在完成了所有 (modules) 目标的构建后开始。从代码中可以看出,这里执 行了 $(LD) -o $(mos_elf) -N -T $(link_script) $(objects)

$(LD)调用链接器,-o参数后设置输出文件名,-T 文件, —script 文件 读取链接脚本,这条命令作用是使用$(link_script) 将 $(objects) 链接, 输出到$(mos_elf) 位置。

3.4 _start函数怎么设置的?

EXPORT(_start)是一个宏,它将 _start 函数导出为一个符号,使得链接器可以找到它。函数中实现跳转mips_init函数

3.5 内核是如何输出到控制台的?

print.c函数实现了格式化输出的主体逻辑,outputk 函数指针传入 vprintfmt 这个函数中,这个函数实际上是用来输出一个字符串的,它实际上调用了一个叫做 printcharc 的函数(调用往 QEMU 的控制台输出字符,其原理为读写某一个特殊的内存地址的函数),想让控制台输出一个字符,实际上是对某一个内存地址写了一个字节。

总体感想:本次实验相比lab0理解要更难,重在理解 操作系统中mos的启动与构建

四、附录

lab1核心——课程内存布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
o 4G -----------> +----------------------------+------------0x100000000
o | ... | kseg2
o KSEG2 -----> +----------------------------+------------0xc000 0000
o | Devices | kseg1
o KSEG1 -----> +----------------------------+------------0xa000 0000
o | Invalid Memory | /|\
o +----------------------------+----|-------Physical Memory Max
o | ... | kseg0
o KSTACKTOP-----> +----------------------------+----|-------0x8040 0000-------end
o | Kernel Stack | | KSTKSIZE /|\
o +----------------------------+----|------ |
o | Kernel Text | | PDMAP
o KERNBASE -----> +----------------------------+----|-------0x8002 0000 |
o | Exception Entry | \|/ \|/
o ULIM -----> +----------------------------+------------0x8000 0000-------
o | User VPT | PDMAP /|\
o UVPT -----> +----------------------------+------------0x7fc0 0000 |
o | pages | PDMAP |
o UPAGES -----> +----------------------------+------------0x7f80 0000 |
o | envs | PDMAP |
o UTOP,UENVS -----> +----------------------------+------------0x7f40 0000 |
o UXSTACKTOP -/ | user exception stack | PTMAP |
o +----------------------------+------------0x7f3f f000 |
o | | PTMAP |
o USTACKTOP ----> +----------------------------+------------0x7f3f e000 |
o | normal user stack | PTMAP |
o +----------------------------+------------0x7f3f d000 |
a | | |
a ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
a . . |
a . . kuseg
a . . |
a |~~~~~~~~~~~~~~~~~~~~~~~~~~~~| |
a | | |
o UTEXT -----> +----------------------------+------------0x0040 0000 |
o | reserved for COW | PTMAP |
o UCOW -----> +----------------------------+------------0x003f f000 |
o | reversed for temporary | PTMAP |
o UTEMP -----> +----------------------------+------------0x003f e000 |
o | invalid memory | \|/
a 0 ------------> +----------------------------+ ----------------------------
o
*/
/* End of Key Code "load-kernel" */


BUAA_OS_lab1
https://fantasylee21.github.io/2024/03/16/BUAA-OS-lab1/
作者
Fantasylee
发布于
2024年3月16日
更新于
2024年4月7日
许可协议