南大pa-Lab1
南大pa是一个设计非常巧妙而且指引非常足的一个实验,由于其指引已经很足了,我在这里不会写实验具体是怎么做的,具体写一下我的思考。
开天辟地的篇章
程序的执行可以看成是一个有限状态机,每一个时刻可能对应一个状态。状态可以用程序计数器的值来进行表述,在不同的状态下,执行的指令和存储器的值也是不一样的,每一个状态可以指令一个访存或者计算指令。不同的程序是不同的状态机。
RTFSC
pa的实验分成三个部分,一个是基础的nemu,nemu本质上是一个硬件模拟,它并不承担软件的部分,它为其他的部份提供硬件层面上的支持。对于其他的部份来说,他们会天真的认为自己是在一个真实的计算机进行执行,但是这一切都是nemu假扮的。nemu并不完善,它只能假扮CPU的执行和部分IO。
还有一个是am,am是抽象计算机,它可以称为静态链接库,这个本质上属于软件,它为其他运行程序提供基础的IO服务,在编译的时候它会和其他的用户程序一起编译在一起。所以说软件部份=am+用户程序,在实验的不同部分中,用户程序是不同的。
这个实验的运行逻辑其实可以知道了。nemu充当硬件的成份,am+用户程序充当软件,在编译后写入进nemu的假想的存储内,由nemu模拟运行。
Makefile
一般来说一个成熟的系统会使用make来自动化构建。pa使用了下面这条make语句进行构建
$(OBJ_DIR)/%.o: %.c
@echo + CC $<
@mkdir -p $(dir $@)
@$(CC) $(CFLAGS) -c -o $@ $<
$(call call_fixdep, $(@:.o=.d), $@)
其中%.表示对于任何一个.o文件,这个是什么意思呢,我们看下面的这个make文件:
CC=gcc
%.o: %.cpp
$(CC) -c -o $@ $<
main: main.o fun.o
$(CC) -o main main.o fun.o
其中系统的输出是这样子的:
gcc -c -o main.o main.cpp
gcc -c -o fun.o fun.cpp
gcc -o main main.o fun.o
%.保证在依赖链中所有依赖相似的依赖都会被构建,我们可以将%.的替换称为一次“展开”,在一次展开中,$<表示第一个依赖文件,$^表示所有依赖文件,$@指代所有目标文件。当然这个指代仅指代一次展开。这是一个省力的好办法。
客户程序载入
众所周知,nemu是一个硬件模拟器,硬件需要运行软件,软件是以操作码储存在内存中的,nemu提供了一个默认的客户程序,这个客户程序很小,只有4B,在启动的时候首先把这个客户程序放在指定的位置中,然后让pc寄存器指向这个客户程序的第一个字节码。当然,这个客户程序执行完之后是nemu_trap命令。执行中断操作,这个后面会讲为什么。
当然我们可以定义一个自选的默认程序来执行相关操作。这个程序的读取在parse_arg已经做好了。如果有自选的程序,会覆盖掉之前的默认的客户程序。
客户程序运行
当代码初始化了之后就会进入sdb_mainloop中,sdb_mainloop是nemu自带的一个控制台小程序,它可以接收控制台的命令然后控制客户程序的执行。
执行的核心逻辑是cpu_exec(),括号内可以传一个整数,表示执行多少条指令,如果传的数是-1就一直循环执行下去。
什么东西可以打断cpu的执行呢,那就是中断,当遇到中断的时候,执行结束,nemu会根据中断的类型判断:
HIT GOOD TRAP
– 客户程序正确地结束执行HIT BAD TRAP
– 客户程序错误地结束执行ABORT
– 客户程序意外终止, 并未结束执行
对于nemu来说,我们可以简单地认为,遇到BAD TRAP/GOOD TRAP就算是一次程序运行的结束。复杂点说就是对于nemu这一个硬件平台,可以运行很多次软件,一次TRAP就是一次软件的运行。实际上对于C语言或者别的,程序运行的结束有另外的表示,nemu本身也是一个大型的C语言项目,nemu运行的结束也需要有表示。
优雅地退出
作为一个C语言代码,我们可以认为main是C语言的核心框架,当main执行完了之后,整个C语言代码就执行完了,一般OS需要在这个时候回收一个信号,这个信号提示刚刚的C语言代码运行情况。这就是return 0的作用,return 0就是告诉上层(或者叫调用该C语言代码的模块),我运行地挺好。
我们注意到nemu退出的时候输出了一堆奇怪的东西,其实是return的结果不是0而是-1,如果return的结果是-1,一般就是运行出现了问题。RTFSC之后可以很快更改。
基础设施
这个是实验本身的部分,本身其实是C语言编程的一个训练,比较简单。
0 条评论