没有合适的资源?快使用搜索试试~ 我知道了~
PA1实验报告1
5星 · 超过95%的资源 需积分: 0 102 下载量 174 浏览量
2022-08-03
13:36:49
上传
评论 7
收藏 4.49MB PDF 举报
温馨提示
试读
37页
1. 熟悉指令集的架构 2. 探究图灵机中程序运行的原理 3. 探究调试器的工作原理与简单实现 1. 用代码模拟寄存器结构,实现调试器基本功能 2. 实现表达式
资源推荐
资源详情
资源评论
PA1实验报告
概述
1
实验目的
1.1
1. 熟悉指令集的架构
2. 探究图灵机中程序运行的原理
3. 探究调试器的工作原理与简单实现
实验内容
1.2
1. 用代码模拟寄存器结构,实现调试器基本功能
2. 实现表达式求值功能
3. 实现监视点功能,学习断点知识与i386手册
阶段一
2
在阶段一开始之前对NEMU有个简单的了解,NEMU就是一个模拟器,类似于VMware,主
要用来模拟计算机的,他是一个程序,他的作用是让其他程序能够像运行在相应的物理机上
那样在NEMU上运行。然后是指令集的选择,我自己是对RISC v比较感兴趣,但由于老师说
如果做其他指令集需要做两份,那就暂时放弃了。还是选择的x86。图灵机的简单介绍如
下:
结构上, TRM有存储器, 有PC, 有寄存器, 有加法器
工作方式上, TRM不断地重复以下过程: 从PC指示的存储器位置取出指令, 执行指令, 然
后更新PC
准备第一个客户程序
2.1
NEMU是需要执行客户程序的程序,NEMU也是程序,程序在执行的时候首先找到入口,
NEMU在运行的时候首先调用 nemu/src/monitor/monitor.c 里面的 init_monitor() 函
数。
int init_monitor(int argc, char *argv[]) {
/* Perform some global initialization. */
/* Parse arguments. */
parse_args(argc, argv);
/* Open the log file. */
init_log(log_file);
/* Load the image to memory. */
long img_size = load_img();
/* Perform ISA dependent initialization. */
init_isa();
/* Compile the regular expressions. */
该函数主要完成一些和monitor相关的初始化工作。
问题一:为什么该函数里都是函数调用,而不是函数体?
答:这里使用函数有助于NEMU的调用结构更加明朗,增加代码的可阅读性,同时这些
函数其实就是接口,所以在实现时候,每个接口在它自己的文件夹下实现相应的内容即
可。
load_img 加载镜像
2.1.1
程序通过 load_img 读入带有内置的客户程序的镜像文件。NEMU 直接将客户镜像读入固定
内存位置 0x10000。同时抽象出 uint8_t isa_default_img[] 和 long
isa_default_img_size 这两个变量作为API来给monitor使用. 通过这两个API, monitor就
可以不关心内置客户程序的具体内容, 只要将它们读入到 IMAGE_START 的内存位置即可.
CPU_state ISA初始化
2.1.2
调用 init_isa() 函数进行ISA相关的操作,主要包括记录物理内存的起始地址、初始化寄
存器。通过调用 reg_test 函数来测试寄存器结构体的实现。
init_regex();
/* Initialize the watchpoint pool. */
init_wp_pool();
/* Initialize devices. */
init_device();
/* Initialize differential testing. */
init_difftest(diff_so_file, img_size);
/* Display welcome message. */
welcome();
return is_batch_mode;
}
1. 寄存器结构:
其中
EAX , EDX , ECX , EBX , EBP , ESI , EDI , ESP 是32位寄存器;
AX , DX , CX , BX , BP , SI , DI , SP 是16位寄存器;
AL , DL , CL , BL , AH , DH , CH , BH 是8位寄存器.
但它们在物理上并不是相互独立的, 例如 EAX 的低16位是 AX , 而 AX 又分成 AH 和 AL ,
鉴于这种共用内存结构,因此选择union结构来模拟寄存器.
2. 寄存器结构代码
代码位于 nemu/src/isa/x86/include/isa/reg.h 中:
typedef struct {
union {
union{
uint32_t _32;
uint16_t _16;
uint8_t _8[2];
} gpr[8];
/* Do NOT change the order of the GPRs' definitions. */
/* In NEMU, rtlreg_t is exactly uint32_t. This makes RTL
instructions
* in PA2 able to directly access these registers.
*/
struct{
rtlreg_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
};
};
vaddr_t pc;
3. 运行 make ISA=x86 run 结果:
问题二:什么是匿名union
答:匿名union就是在结构对象可以直接访问匿名结构体成员变量如: cpu.eax ,代码
相对比较简洁。
问题三: reg_test() 是如何测试你的实现的?
答:是根据寄存器之间的地址关系写出来的,即 EAX 的低16位是 AX , 而 AX 又分成 AH 和
AL 。通过对其中32位寄存器赋值,通过运算得出地位的值与寄存器中的值进行对比来
测试。
运行第一个客户程序
2.2
定义在 nemu/src/monitor/debug/ui.c 中的 ui_mainloop 用户界面主循环,可以在这里
输入很多指令来监控课调试。当命令键入 c 时,循环就调用 cmd_c 函数,里面 cpu_exec 函
数传入的值是-1。
问题四:在 cmd_c() 函数中, 调用 cpu_exec() 的时候传入了参数 -1 , 你知道这是什么意
思吗?
答: cpu_exec 函数的参数是 uint64_t 类型,即64位无符号整数,当传入的值是-1时,
就代表
2的64次方减一,所以其实是最大值,保证函数不断执行。
为了表示程序是否正常结束,当触发 nemu_trap 时,NEMU将会根据这个结束状态参数来设
置NEMU的结束状态, 并根据不同的状态输出不同的结束信息, 包括
HIT GOOD TRAP - 客户程序正确地结束执行
HIT BAD TRAP - 客户程序错误地结束执行
ABORT - 客户程序意外终止, 并未结束执行
问题五:谁来指示程序的结束?
} CPU_state;
命令 格式 使用举例 说明
帮助 help help 打印命令的帮助信息
继续运
行
c c
继续运行被暂停的程序
退出 q q 退出NEMU
单步执
行
si
[N]
si 10
让程序单步执行 N 条指令后暂停执行, 当 N 没有给出
时, 缺省为 1
打印程
序状态
info
SUBCMD
info r
info w
打印寄存器状态 打印监视点信息
表达式
求值
p
EXPR
p $eax
+ 1
求出表达式 EXPR 的值, EXPR 支持的 运算请见调试中
的表达式求值小节
扫描内
存
x N
EXPR
x 10
$esp
求出表达式 EXPR 的值, 将结果作为起始内存 地址, 以
十六进制形式输出连续的 N 个4字节
设置监
视点
w
EXPR
w
*0x2000
当表达式 EXPR 的值发生变化时, 暂停程序执行
删除监
视点
d N d 2 删除序号为 N 的监视点
答:正常程序退出时调用 atexit 登记函数,1个进程可以登记若干个函数,这些函数由
exit 自动调用,这些函数被称为终止处理函数, atexit 函数可以登记这些函数。
exit 调用终止处理函数的顺序和 atexit 登记的顺序相反,如果1个函数被多次登记,
也会被多次调用。因此 main 的返回不是真的结束,而是进入了内核态。
图灵机的实现
2.3
存储器是个在 nemu/src/memory/memory.c 中定义的大数组
PC和通用寄存器都在 nemu/src/isa/$ISA/include/isa/reg.h 中的结构体中定义
加法器在... 嗯, 这部分框架代码有点复杂, 不过它并不影响我们对TRM的理解, 我们还是
在PA2里面再介绍它吧
TRM的工作方式通过 cpu_exec() 和 exec_once() 体现
基础设施:简易调试器
2.4
调试器是监视器很重要的一个功能,要实现的主要功能如下:
cmd_table 解析命令
2.4.1
在用户界面主循环中,主要使用 strtok 来切分指令,即把上表的空格前的字符分割出来,
然后在命令的实现函数里实现后面参数的解析,使用的是 sscanf 函数。对命令的解析完成
后调用 cmd_table[i].handler(args) 来执行相关的处理函数。
static struct {
char *name;
char *description;
int (*handler) (char *);
} cmd_table [] = {
剩余36页未读,继续阅读
资源评论
- sword_three2023-08-26很有帮助,谢谢!
陈熙昊
- 粉丝: 18
- 资源: 320
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功