Skip to content

浙江大学实验报告

:material-circle-edit-outline: 约 1956 个字 :fontawesome-solid-code: 14 行代码 :material-clock-time-two-outline: 预计阅读时间 7 分钟

课程名称:操作系统 实验类型:综合型/设计型

实验项目名称:实验0 RV64 环境搭建和内核编译

学生姓名:俞仲炜 专业:计算机科学与技术 学号:3220104929

电子邮件地址:zhongweiy@zju.edu.cn 实验日期:2024.9.11

一、实验内容或步骤

包括思考题回答,对每一步的命令以及结果进行必要的解释

实验内容

搭建实验环境环境

安装的时候

$ sudo apt install  gcc-riscv64-linux-gnu
$ sudo apt install  autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev \
                    gawk build-essential bison flex texinfo gperf libtool patchutils bc \
                    zlib1g-dev libexpat-dev git

第一条命令通过 apt 包管理器获取了适用于RISC-V 64位Linux系统的GNU编译器集合(GCC),就是在系统上安装了一个专门用于编译RISC-V架构程序的编译器。

第二条又臭又长,安装了一堆用于构建、配置和管理大型软件的包,比如前三个 \(auto\) 开头的包能自动生成配置脚本和 \(Makefile\)\(curl\) 用于下载文件、传输数据,\(gawk\) 是一个强大的文本处理工具,\(build-essential\) 包含了编译软件所必需的基本工具,如make,\(patchutils\) 用于打补丁,\(git\) 是一个分布式版本控制系统,用于管理代码。

这些工具我已经安装过了

image-20240911112924857

image-20240911112847486

$ sudo apt install qemu-system-misc
$ sudo apt install gdb-multiarch

第一条命令下载了 \(qemu\) 的一些基本组件。

第二条下载了 \(GDB\) 的一个多架构版本。

image-20240911112951718

总的来说,这一步是在下载各种之后要用到的工具。

获取 Linux 源码和已经编译好的文件系统

获取 Linux 源码压缩包并用 \(tar\) 解压

$ wget https://git.kernel.org/torvalds/t/linux-6.11-rc7.tar.gz
$ tar -xf linux-6.11-rc7.tar.gz

image-20240911113722142

通过 git 获取已经准备好的根文件系统镜像 rootfs.img

$ git clone https://github.com/ZJU-SEC/os24fall-stu.git

我已经克隆了,懒得删了重下了

image-20240911113709133

如此我们已经准备好了这次实验要用到的资源

编译 Linux 内核

$ make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
$ make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)
  • ARCH=riscv 指定了目标架构为RISC-V
  • CROSS_COMPILE=riscv64-linux-gnu- 指定了交叉编译器的前缀,表示我们要编译的代码将运行在RISC-V 64位Linux系统上
  • defconfig 表示使用默认的配置文件
  • $(nproc) 获取的是当前进程可用的CPU数量,我的电脑是 32,-j的参数可根据实际情况往下调整

第一条命令为RISC-V架构的Linux内核配置一个默认的配置文件

.config 文件是一个文本文件,至关重要,里面保存了关于内核编译时所做的各种配置选项,决定了最终生成的内核包含哪些功能、支持哪些硬件设备、以及如何运行

image-20240911113826108

第二条命令编译Linux内核

image-20240911114324468

使用 QEMU 运行内核

qemu-system-riscv64 -nographic -machine virt -kernel arch/riscv/boot/Image     -device virtio-blk-device,drive=hd0 -append "root=/dev/vda ro console=ttyS0"     -bios default -drive file=~/24fall-os/os24fall-stu/src/lab0/rootfs.img,format=raw,id=hd0

这里的各个参数实验文档均已给出详细解释,故不再赘述

这条命令启动了一个 QEMU 虚拟机,用来模拟一个 RISC-V 64 位的 Linux 系统

image-20240911114427069

使用 GDB 对内核进行调试

我们开两个终端,一个负责打开程序,一个负责远程调试程序

qemu-system-riscv64 -nographic -machine virt -kernel arch/riscv/boot/Image \
    -device virtio-blk-device,drive=hd0 -append "root=/dev/vda ro console=ttyS0" \
    -bios default -drive file=~/24fall-os/os24fall-stu/src/lab0/rootfs.img,format=raw,id=hd0 -S -s

这各命令就是使用 QEMU 运行内核,只不过多了 -s-S 两个参数服务于远程调试

gdb-multiarch vmlinux

这条命令表示使用支持多架构的 GDB 调试器来调试 Linux 内核。

gdb 即 GNU 调试器,multiarch 即多架构,gdb-multiarch 就是支持多架构的 GDB 调试器,意味着它可以调试编译成不同 CPU 架构的程序,比如 x86、ARM、RISC-V 等。

在交叉编译环境下调试 Linux 内核时,gdb-multiarch 就显得非常有用。

vmlinux是 Linux 内核的可执行文件,包含了内核的所有代码和符号信息。

符号信息即程序中的函数名、变量名等,这些信息对于调试非常重要,因为调试器可以通过符号名来找到代码中的对应位置。

image-20240911114523350

GDB 命令尝试片段

image-20240913121200655

frame 用于查看某个栈帧

每个函数调用都会产生一个新的栈帧,用于存储函数的局部变量、参数、返回地址等信息。当一个函数调用另一个函数时,新的栈帧就会被压入栈中。

image-20240913121615552

蓝色太深了好难看,不知道怎么调

btbacktrace,用于显示当前函数调用栈的信息

frame 不同, backtrace 提供的是整个函数调用栈的鸟瞰图,可以一次性显示多个栈帧的信息

frame 是查看单个栈帧的详细信息,比较局部

思考题

使用 riscv64-linux-gnu-gcc 编译单个 .c 文件

image-20240913114858656

riscv64-linux-gnu-gcc 是一条完整的交叉编译器命令

riscv64 指明目标处理器架构是 RISC-V 64 位

linux-gnu 表示目标操作系统是 Linux,并且使用 GNU C 库(glibc)

glibc 是 Linux 系统中最常用的 C 运行库,提供了许多系统调用和标准 C 库函数

使用 riscv64-linux-gnu-objdump 反汇编 1 中得到的编译产物

image-20240913115051692

-d 指示 objdump 执行反汇编操作

> hello.asm 将反汇编结果输出到 hello.asm 文件,这个箭头指示数据流向目标

下图为 \(VSCode\) 远程连接 \(WSL\) 查看反编译得到的 hello.asm

image-20240913115117888

调试 Linux 时 :

  • 在 GDB 中查看汇编代码
  • 在 0x80000000 处下断点
  • 查看所有已下的断点
  • 在 0x80200000 处下断点
  • 清除 0x80000000 处的断点
  • 继续运行直到触发 0x80200000 处的断点
  • 单步调试一次
  • 退出 QEMU

image-20240911104857828

补充图里没有的:

  1. 在 GDB 中查看汇编代码: layout asm
  2. 在 0x80000000 处下断点:b * 0x80000000
  3. 退出 QEMU:

image-20240911104928134

使用 make 工具清除 Linux 的构建产物

image-20240911104713155

vmlinuxImage 的关系和区别是什么?

前者是 Linux 内核编译的原始产物,是一个 \(ELF\) 格式的可执行文件,包含了内核所有代码和符号信息,提供了调试信息,所以可用于调试。

后者是对前者进行处理后得到的内核镜像二进制文件,可以进行压缩,所以可能不能调试。

总结来说,\(vmlinux\) 是内核的开发阶段使用的文件,而 \(Image\) 是内核的发布阶段使用的文件。\(vmlinux\) 提供了更详细的信息,方便开发者调试内核,而 \(Image\) 则更适合在实际系统中使用。

二、讨论、心得

实验中遇到的问题和解决方案

本次实验基本顺畅,没有遇到半天都解决不了的阻碍,都是一学就懂的东西。

这是本人第一次接触 Linux,所以认知障碍是非常大的,好在借助 gpt 和搜索引擎快速熟悉了 Linux 的基本知识与操作,并将新知识全部记录在了前面的实验报告里以便后续学习。

此外,深感 WSL 是披着 Linux 外衣的 Windows 系统,很多现成的软件可以直接远程连接 WSL 进行工作,十分便利,甚至资源管理器可以直接对 WSL 的文件进行管理。

个人感觉这样可能会限制学生的思维,毕竟 Linux 与 Windows 的操作思维应该相差挺大的?

额外啰嗦,与实验无关:

本人在此之前基本没有体验过命令行式交互,所以遇到的最大问题是无法确定交互后得到的反馈是不是正确的反馈。不过在有已经相对成熟的 gpt 的环境下学习一个计算机工具的成本已经非常低了,每条命令都可以喂给 gpt,进而可以学习到这条命令本身的作用和各个参数的作用,以及相应的反馈是什么,等等,所以这次实验整体做下来是十分轻松的,对于学生而言,gpt 用于辅助学习的价值远远大于直接获取答案的价值,gpt更像是一个次世代的搜索引擎,但似乎止步于此了?

20240913