PA1: nemu相关学习记录

编译中出错:提示没有 <SDL2/SDL.h>头文件

查看错误信息,出错的文件在abstract-machine文件夹里,叫input.c,里面引用了SDL2/SDL.h  这个头文件,但是我只在fceux文件夹里搜到了sdl.h,考虑到linux区分大小写,搜索以后,我觉得我应该是系统缺少了SDL库。

sudo apt install libsdl2-dev   安装以后编译通过,和fc文件夹的sdl.h没有关系。

然后运行make ARCH=native mainargs=k run,经过检查,按键没有问题。

 

ysyx项目文件架构:框架 官方文档 (oscc.cc)

 

nemu/include/generated/autoconf.h  这个文件是一些宏定义相关,nemu/include/config/auto.conf 这个文件是一些配置参数,大致是编译时要选择的编译参数。

make menuconfig打开完整选项

----------------------

插入一下编译c/c++的过程:

1. 预编译,ifdef这样的语句在这一步会被处理,头文件也会被引入。c++的话,constexpr标记的函数也会在这一步处理,生成.i文件

2. 编译  生成.s文件 ,对应即将代码变成汇编文件

3. 汇编 将上一步得到的汇编文件变为二进制文件  对应.o后缀

4. 链接 将.o文件与库链接,生成可执行的.exe文件

  想要直接把test.c生成带调试的可执行文件  就需要gcc -g -o test  test.c 这条指令

------------------

讲义里给出了makefile的规则:

$(OBJ_DIR)/%.o: %.c
  @echo + CC $<
  @mkdir -p $(dir $@)
  @$(CC) $(CFLAGS) -c -o $@ $<
  $(call call_fixdep, $(@:.o=.d), $@)

第一行表示 obj_dir  这个变量对应的目录下,每个.o文件都依赖于同名.c文件

第二行表示命令行输出+CC 和第一个依赖文件的名字  $<表示第一个依赖文件

第三行表示创建目标文件的所在目录  $@表示目标文件  dir $@就是目标文件所在目录

第四行是规则,表示gcc 以CFLAGS参数编译第一个依赖文件,生成目标文件

这三行前面有@,表示这三行不显示出来

最后一行则是调用自定义函数,同时传入两个参数,一个是.o文件对应的.d文件,一个是目标文件

终端会显示的内容:(也就是第四行指令对应内容)

gcc -O2 -MMD -Wall -Werror -I/home/user/ics2023/nemu/include
-I/home/user/ics2023/nemu/src/engine/interpreter -I/home/use
r/ics2023/nemu/src/isa/riscv32/include -O2    -D__GUEST_ISA__
=riscv32  -c -o /home/user/ics2023/nemu/build/obj-riscv32-nem
u-interpreter/src/utils/timer.o src/utils/timer.c

$@ -> /home/user/ics2023/nemu/build/obj-riscv32-nemu-interpreter/src/utils/timer.o
$< -> src/utils/timer.c    剩下的都是CFLAGS

-o表示要指定生成的文件的名字 它和后面紧挨的参数是一起的

----------------------------------

init_monitor这个函数里调用别的函数而不是直接把代码展开,可以让函数看起来更简洁,此外被调用的函数在其他地方也可以进行二次利用。

此外,对于nemu/src/monitor/monitor.c这个文件,针对不同架构,通过宏决定了哪些需要进行编译。

 

在nemu目录下make run以后,报错信息同讲义,提示monitor.c:36:welcome:assertion '0' failed。同时make指令会提示scripts/native.mk:38:run 会提示core dumped

检查montitor.c,发现这一行是assert(0)  断言这么用似乎没什么意义,所以我屏蔽了。

 

疑问回答:cpu_exec()这个函数的参数是无符号整数,传入-1,实际上是传入int型最大值,大致相当于while(1)。  

 --------------------------------以下一段是错误的,留作记录,不要学习-----------

  关于程序的进入和退出。在进入时,系统会将pc寄存器的值设置为当前程序的首条指令地址。退出时,系统会检测退出码,0就是向系统回报正常退出的信号。然后系统释放掉这个进程,如果有父进程的话,向父进程发一个SIGCHLD信号量,通知子进程结束的消息。

  假如make run以后,直接在nemu中输入q,那么native.mk:38会提示报错。打开这个mk文件,第38行对应NEMU_EXEC这个变量,这个变量对应 $(BINARY) $(ARGS) $(IMG)

  直接退出报错,可能是因为当前还在执行make指令,但是直接退出,对应的sdb.c里是返回-1值。返回非0值,那么make报错。   我把这一行变量后面加了个  ||true,这样最终这行返回一定是零值。加上以后,确实不再报错。

 

makefile的工作原理(个人理解):make指令运行到程序开始运行,并不代表make已经运行结束。nemu里直接退出,导致程序在退出时没有正确返回值,所以make的这一行指令也没有对应到零值,进而报错。对于make,返回零才表示是正常退出

如果想要不报错,要么用 ||true,要么在这一行指令前加  -   ,表示忽略错误继续执行。

 

---------------24/7/1-------------正确的理解----------

  从nemu的main函数入手,我们可以看到engine_start()和is_exit_status_bad()两个函数。前者是主函数,后者则是用来检查nemu的退出状态。进入engine_start(),我们可以看到sdb_mainloop()函数,这又跳转到了我们已经不断完善的sdb.c。这样一看来,程序流程就很显而易见了:nemu启动后,会顺序进入sdb的mainloop函数,然后无限循环读取指令,直到强制退出或者q退出。

  退出时,进入is_exit_status_bad()函数,这个函数判断nemu的退出状态是否符合原目标。

  那么,怎么实现“优雅的退出”呢?怎么样才算优雅呢?至少在makefile里修改肯定不是,因为这样做只是修改了程序退出的状态信息。内层并没有得到妥善处理。 修改退出状态函数也是同理。 想要优雅退出,在主循环里就应该对退出做出反应。

posted @ 2024-02-01 17:53  namezhyp  阅读(55)  评论(0编辑  收藏  举报