Lab1 Report
Lab1 Report
思考题
Thinking 1.1
- 请阅读附录中的编译链接详解,尝试分别使用实验环境中的原生 x86
工具链(gcc、ld、readelf、objdump 等)和 MIPS 交叉编译工具链(带有
mips-linux-gnu- 前缀),重复其中的编译和解析过程,观察相应的结果,并解释其中向
objdump 传入的参数的含义。
- 编译程序 hello.c,再用 objdump 反编译.o 与可执行文件
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
28x86:
gcc -c hello.c 生成 hello.o 文件
gcc -o hello_x86 hello.c 链接
objdump -DSt hello.o x86 工具链反编译 x86 下的.o 文件
objdump -DSt hello_x86 x86 工具链反编译 x86 下的可执行文件
mips-linux-gnu-objdump -DSt hello.o :can't disassemble for architecture UNKNOWN!
mips-linux-gnu-objdump -DSt hello_x86 :can't disassemble for architecture UNKNOWN!
=>mips-linux-gnu- 工具链不可反编译 x86 下的.o 与可执行文件
MIPS 交叉编译工具链:
mips-linux-gnu-gcc -c hello.c 生成 hello.o 文件
mips-linux-gnu-gcc -o hello_mips hello.o 链接
objdump -DSt hello.o x86 工具链反编译 mips 下的.o 文件
objdump -DSt hello_mips x86 工具链反编译 mips 下的可执行文件
mips-linux-gnu-objdump -DSt hello.o mips-linux-gnu- 工具链工具链反编译 mips 下的.o 文件
mips-linux-gnu-objdump -DSt hello_mips >mips-linux-gnu- 工具链反编译 mips 下的可执行文件
-D
--disassemble-all
与 -d 类似,但反汇编所有 section.
-S
--source
尽可能反汇编出源代码,尤其当编译的时候指定了 -g 这种调试参数时,效果比较明显。隐含了 -d 参数。
-t:显示可执行文件的符号表。- 反编译.o 文件时某一些指令的地址为 0,没有取得应有的地址,但在链接成为可执行文件后,则被填入地址。
- 通过观察不同工具链编译出的可执行文件和使用 objdump 解析的结果,可以发现它们在汇编指令和符号表等方面存在差异。不同的工具链可能使用不同的指令集,因此编译出的可执行文件也会有所不同。
Thinking 1.2
尝试使用我们编写的 readelf 程序,解析之前在 target 目录下生成的内核 ELF 文件。
- readelf 解析之前在 target 目录下生成的内核 ELF 文件结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
170:0x0
1:0x80400000
2:0x80401a80
3:0x80401a98
4:0x80401ab0
5:0x0
6:0x0
7:0x0
8:0x0
9:0x0
10:0x0
11:0x0
12:0x0
13:0x0
14:0x0
15:0x0
16:0x0也许你会发现我们编写的 readelf 程序是不能解析 readelf 文件本身的,而我们刚才介绍的系统工具 readelf 则可以解析,这是为什么呢?(提示:尝试使用 readelf-h,并阅读 tools/readelf 目录下的 Makefile,观察 readelf 与 hello 的不同)
- 使用 readelf -h 得到两个文件文件头差异
- 编写的 readelf 中 Elf32_Ehdr 等针对的是 32 位的 ELF 的解析,hello 程序 ELF 类别是 32 位,可被编写的 readelf 解析,但 readelf 文件本身位 64 位 ELF,不可被解析。系统工具则都可解析
Thinking 1.3
- 在理论课上我们了解到,MIPS 体系结构上电时,启动入口地址为
0xBFC00000(其实启动入口地址是根据具体型号而定的,由硬件逻辑确定,也有可能不是这个地址,但一定是一个确定的地址),但实验操作系统的内核入口并没有放在上电启动地址,而是按照内存布局图放置。思考为什么这样放置内核还能保证内核入口被正确跳转到?(提示:思考实验中启动过程的两阶段分别由谁执行。)
- 在实验操作系统的启动过程中,有一个引导加载程序的阶段。引导加载程序位于启动入口地址处,它的作用是将内核从磁盘中加载到内存中,并将控制权转移到内核入口地址。实验操作系统的内核入口地址放置在内存布局图的正确位置时,引导加载程序可以正确地将控制权转移到内核入口地址处,进入内核。
- 因此,尽管内核入口地址不是启动入口地址,但通过引导加载程序的正确执行,内核入口仍然可以被正确地跳转到。
难点分析
- 理解整体架构,查找、理解所需内存配置信息与关联函数参数使用,如:
- 1.1 中查找各个结构体中成员表示的含义,对应 ELF 文件结构。节头中的地址信息需要通过 binary ELF 的文件头地址 +shoff 为入口偏移 + 节头数 * 节头大小 e_shentsize 得到当前节头地址,再通过该节头结构体中的 sh_addr 得到节头中的地址信息。
- 1.4 中 printk 时第三个参数传入的是 unsigned long,十进制有符号数需要提前判断是否为负数,取绝对值,提出负号单独处理
- 1.4 中 c 的语法和与逻辑,一些指针的使用,以及一点点 mips 的语法
实验体会
- 体会到内核设计运行的复杂与严谨,内存信息需有序规划分配。以及多种类型文件的不同方式的编译,分别负责整体的不同功能方面。
- 体会到一些 c 语言的强大的灵活基础能力
- 记得要读网站上的题目,以及教程 exercise 上下文的信息提示,如“Note 1.3.5 通过查看内存布局图,同学们应该能找到.text 节的加载地址了,.data 和.bss 只需要紧随其后即可。”