除了上一章实验的页表机制外,中断机制也是组成操作系统不可或缺的部分。本章的实验主要集中于 xv6 的中断机制,通过改进 xv6 的中断机制来学习并应用关于中断的一些概念。

我们先切换到trap分支

4.1 学习 RISC-V 汇编

由于本次实验及之后的实验中,会涉及到机器指令级别的操作和调试,故而了解一些关于 RISC-V 汇编的知识将有助于实验的进行。这个实验几乎不需要编写代码,主要内容是观察 一些汇编代码和它们的行为。

我们首先需要使用make 将 user/call.c 源文件编译为对应的目标代码,在这个过程中, xv6 的 Makefile 会自动生成反汇编后的代码。编译完成后,打开新生成的user/call.asm,回答 xv6 实验手册中提出的问题。

<aside> 💡 .d .sym .asm .o的文件都是什么

这些文件都是在编译和链接过程中生成的中间文件或输出文件:

在编译 C 语言源代码时,编译器会将源代码文件编译成汇编语言文件(通常扩展名为 .s),然后将汇编语言文件汇编成目标文件(通常扩展名为 .o)。最后,链接器将所有目标文件链接在一起,生成可执行文件。

</aside>

Question 1

Which registers contain arguments to functions? For example, which register holds 13 in main’s call to printf? 函数的参数存在哪

Untitled

通过阅读 call.asm 文件中的 main 函数可知,调用 printf 函数时,13 被寄存器 a2 保存。其中 li a2,13 意思如下:

所以答案为: a1, a2, a3 等通用寄存器;13 被寄存器 a2 保存。

Question 2

Where is the call to function f in the assembly code for main? Where is the call to g? (Hint: the compiler may inline functions.) f和g的调用

通过阅读函数 f 和 g 得知:函数 f 调用函数 g ;函数 g 使传入的参数加 3 后返回。

所以总结来说,函数 f 就是使传入的参数加 3 后返回。考虑到编译器会进行内联优化,这就意味着一些显而易见的,编译时可以计算的数据会在编译时得出结果,而不是进行函数调用。

查看 main 函数可以发现,printf 中包含了一个对 f 的调用。

Untitled

但是对应的会汇编代码却是直接将 f(8)+1 替换为 12 。这就说明编译器对这个函数调用进行了优化,所以对于 main 函数的汇编代码来说,其并没有调用函数 f 和 g ,而是在运行之前由编译器对其进行了计算。