2323
24241. `* ` 应用程序在执行过程中,会占用哪些计算机资源?
25252. `* ` 请用相关工具软件分析并给出应用程序A的代码段/数据段/堆/栈的地址空间范围。
26- 3. `* ` 请用分析并给出应用程序C的代码段/数据段/堆/栈的地址空间范围。
26+ 3. `* ` 请用分析并给出应用程序C的代码段/数据段/堆/栈的地址空间范围。
27274. `* ` 请结合编译器的知识和编写的应用程序B,说明应用程序B是如何建立调用栈链信息的。
28285. `* ` 请简要说明应用程序与操作系统的异同之处。
29296. `** ` 请基于QEMU模拟RISC—V的执行过程和QEMU源代码,说明RISC-V硬件加电后的几条指令在哪里?完成了哪些功能?
30307. `* ` RISC-V中的SBI的含义和功能是啥?
31- 8. `** ` 为了让应用程序能在计算机上执行,操作系统与编译器之间需要达成哪些协议?
31+ 8. `** ` 为了让应用程序能在计算机上执行,操作系统与编译器之间需要达成哪些协议?
32329. `** ` 请简要说明从QEMU模拟的RISC-V计算机加电开始运行到执行应用程序的第一条指令这个阶段的执行过程。
333310. `** ` 为何应用程序员编写应用时不需要建立栈空间和指定地址空间?
34+ 11. `*** ` 现代的很多编译器生成的代码,默认情况下不再严格保存/恢复栈帧指针。在这个情况下,我们只要编译器提供足够的信息,也可以完成对调用栈的恢复。
35+
36+ 我们可以手动阅读汇编代码和栈上的数据,体验一下这个过程。例如,对如下两个互相递归调用的函数:
37+
38+ .. code-block ::
39+
40+ void flip(unsigned n) {
41+ if ((n & 1) == 0) {
42+ flip(n >> 1);
43+ } else if ((n & 1) == 1) {
44+ flap(n >> 1);
45+ }
46+ }
47+
48+ void flap(unsigned n) {
49+ if ((n & 1) == 0) {
50+ flip(n >> 1);
51+ } else if ((n & 1) == 1) {
52+ flap(n >> 1);
53+ }
54+ }
55+
56+ 在某种编译环境下,编译器产生的代码不包括保存和恢复栈帧指针 ``fp `` 的代码。以下是 GDB 输出的本次运行的时候,这两个函数所在的地址和对应地址指令的反汇编,为了方便阅读节选了重要的控制流和栈操作(省略部分不含栈操作):
57+
58+ .. code-block ::
59+
60+ (gdb) disassemble flap
61+ Dump of assembler code for function flap:
62+ 0x0000000000010730 <+0>: addi sp,sp,-16 // 唯一入口
63+ 0x0000000000010732 <+2>: sd ra,8(sp)
64+ ...
65+ 0x0000000000010742 <+18>: ld ra,8(sp)
66+ 0x0000000000010744 <+20>: addi sp,sp,16
67+ 0x0000000000010746 <+22>: ret // 唯一出口
68+ ...
69+ 0x0000000000010750 <+32>: j 0x10742 <flap+18>
70+
71+ (gdb) disassemble flip
72+ Dump of assembler code for function flip:
73+ 0x0000000000010752 <+0>: addi sp,sp,-16 // 唯一入口
74+ 0x0000000000010754 <+2>: sd ra,8(sp)
75+ ...
76+ 0x0000000000010764 <+18>: ld ra,8(sp)
77+ 0x0000000000010766 <+20>: addi sp,sp,16
78+ 0x0000000000010768 <+22>: ret // 唯一出口
79+ ...
80+ 0x0000000000010772 <+32>: j 0x10764 <flip+18>
81+ End of assembler dump.
82+
83+ 启动这个程序,在运行的时候的某个状态将其打断。此时的 ``pc ``, ``sp ``, ``ra `` 寄存器的值如下所示。此外,下面还给出了栈顶的部分内容。(为阅读方便,栈上的一些未初始化的垃圾数据用 ``??? `` 代替。)
84+
85+ .. code-block ::
86+
87+ (gdb) p $pc
88+ $1 = (void (*)()) 0x10752 <flip>
89+
90+ (gdb) p $sp
91+ $2 = (void *) 0x40007f1310
92+
93+ (gdb) p $ra
94+ $3 = (void (*)()) 0x10742 <flap+18>
95+
96+ (gdb) x/6a $sp
97+ 0x40007f1310: ??? 0x10750 <flap+32>
98+ 0x40007f1320: ??? 0x10772 <flip+32>
99+ 0x40007f1330: ??? 0x10764 <flip+18>
100+
101+ 根据给出这些信息,调试器可以如何复原出最顶层的几个调用栈信息?假设调试器可以理解编译器生成的汇编代码 [#dwarf ]_ 。
102+
34103
35104
36105实验练习
@@ -92,7 +161,7 @@ lab1 的工作使得我们从硬件世界跳入了软件世界,当看到自己
92161.. code-block :: rust
93162
94163 // 这段代码输出了 os 内存空间布局,这到这些信息对于编写 os 十分重要
95-
164+
96165 info!(".text [{:#x}, {:#x})", s_text as usize, e_text as usize);
97166 debug!(".rodata [{:#x}, {:#x})", s_rodata as usize, e_rodata as usize);
98167 error!(".data [{:#x}, {:#x})", s_data as usize, e_data as usize);
@@ -111,7 +180,7 @@ lab1 的工作使得我们从硬件世界跳入了软件世界,当看到自己
111180- 完成实验指导书中的内容并在裸机上实现 ``hello world `` 输出。
112181- 实现彩色输出宏(只要求可以彩色输出,不要求 log 等级控制,不要求多种颜色)
113182- 隐形要求
114-
183+
115184 可以关闭内核所有输出。从 lab2 开始要求关闭内核所有输出(如果实现了 log 等级控制,那么这一点自然就实现了)。
116185
117186- 利用彩色输出宏输出 os 内存空间布局
@@ -154,7 +223,7 @@ challenge: 支持多核,实现多个核的 boot。
154223tips
155224^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
156225
157- - 对于 Rust, 可以使用 crate `log <https://docs.rs/log/0.4.14/log/ >`_ ,推荐参考 `rCore <https://github.com/rcore-os/rCore/blob/master/kernel/src/logging.rs >`_
226+ - 对于 Rust, 可以使用 crate `log <https://docs.rs/log/0.4.14/log/ >`_ ,推荐参考 `rCore <https://github.com/rcore-os/rCore/blob/master/kernel/src/logging.rs >`_
158227- 对于 C,可以实现不同的函数(注意不推荐多层可变参数解析,有时会出现不稳定情况),也可以参考 `linux printk <https://github.com/torvalds/linux/blob/master/include/linux/printk.h#L312-L385 >`_ 使用宏实现代码重用。
159228- 两种语言都可以使用 ``extern `` 关键字获得在其他文件中定义的符号。
160229
163232
1642331. 请学习 gdb 调试工具的使用(这对后续调试很重要),并通过 gdb 简单跟踪从机器加电到跳转到 0x80200000 的简单过程。只需要描述重要的跳转即可,只需要描述在 qemu 上的情况。
165234
166- 2. tips:
235+ 2. tips:
167236
168237 - 事实上进入 rustsbi 之后就不需要使用 gdb 调试了。可以直接阅读代码。`rustsbi起始代码 <https://github.com/rustsbi/rustsbi-qemu/blob/main/rustsbi-qemu/src/main.rs#L146 >`_ 。
169238 - 可以使用示例代码 Makefile 中的 ``make debug `` 指令。
185254- 由于彩色输出不好自动测试,请附正确运行后的截图。
186255- 完成问答问题。
187256- (optional) 你对本次实验设计及难度/工作量的看法,以及有哪些需要改进的地方,欢迎畅所欲言。
257+
258+ .. [#dwarf ] 对编译器如何向调试器提供生成的代码的信息,有兴趣可以参阅 `DWARF 规范 <https://dwarfstd.org >`_
0 commit comments