NEMU 代码导读
项目构建
首先得了解一些 make 的行为,重要的就是查看make 的行为以及make 的子进程如何与系统进行交互,比如 :
- strace -f make
- make -nB # 只打印命令不执行 B强制构建
- make -d
- make -debug=v
具体RTFM。
- nemu/Makefile
- SRCS: 和YEMU差不多, 是需要编译的源文件
- CFLAGS: 刚才看到的编译选项
- include $(NEMU_HOME)/scripts/native.mk: 包含其他文件
- nemu/scripts/native.mk
- 一些用于运行和清除编译结果的伪目标
- nemu/scripts/build.mk
- 编译规则
- 包含源文件与头文件的依赖关系(由gcc的-MMD选项生成, 并通过fixdep工具处理)
代码选讲
gdb
使用 gdb 来查看程序入口,是一种很好的方法,并且可以根据 gdb 的操作可以看到程序依次执行的各个函数。
1 |
|
可以使用 GDB 来 RTFSC:
1 |
|
一些常用的命令:
- r - 重新开始执行程序
- s - 单步执行一行源代码 / n - 类似但不进入函数(可用于跳过库函数)
- finish - 执行直到当前函数返回
- p - 打印变量或寄存器的值
- x - 扫描内存
- bt - 查看调用栈
- b - 设置断点 / watch - 设置监视点
- help xxx - 查看xxx命令的帮助
RTFSC
1 |
|
首先,执行的是init_monitor(argc, argv):
1 |
|
通过init_monitor初始化NEMU的大部分功能。
首先是解析参数,nemu 是一个命令行工具,它在启动的时候,可以接受参数。
1 |
|
接着是,init_rand(),初始化随机数。
1 |
|
接下来进行日志功能,打开日志文件:
1 |
|
接着是 init_mem(),初始化状态机的 M
1 |
|
这是将内存初始化为随机数,可以暴露访问初始化内存的未定义行为。
接下来是初始化状态机的状态:init_isa():
1 |
|
这个过程是将 img 中的一些指令复制到 host 地址中执行。接着设置客户机的 pc 为 0,以及 cpu.gpr[0] = 0。零寄存器很好用,可以方便得让 CPU 产生 0.
接着为load_img,但是参数中并没有给出,因此直接略过:
1 |
|
接着就是初始化 sdb 了。
1 |
|
接着就是,welcome()
- 输出欢迎信息
- 以及trace的状态信息
- 还输出了编译的时间和日期
1 |
|
接着回到 main,执行engine_start()–>sdb_mainloop():
1 |
|
这里就是 PA1 的 sdb 了。
指令执行
执行指令和 YEMU 中的 inst_cycle 很相似,类似于 CPU 执行一个一个指令。
1 |
|
其中 decode 解码和执行:
1 |
|
以上,就是 nemu 的一个大概的过程,当然要想更全面理解 nemu,需要深入仔细阅读源码。
NEMU 代码导读
http://blog.luliang.online/2024/08/12/NEMU代码导读/