JYY's ICS2020 PA1
开天辟地的篇章
从状态机视角理解程序运行
1 | // PC: instruction | // label: statement |
Q:画出这个程序的状态机
需要更新的状态只包括PC,r1和r0,所以用三元组表示程序的所有状态:
(0, x, x) -> (1, 0, x) -> (2, 0, 0) -> (3, 0, 1) -> (4, 1, 1) -> (2, 1, 1) -> (3, 1, 2) -> (4, 3, 2) -> … -> (2, 4851, 98) -> (3, 4851, 99) -> (4, 4950, 99) -> (2, 4950, 99) -> (3, 4950, 100) -> (4, 5050, 100) -> (5, 5050, 100)
- Thoughts : 如果不是实验中给出了初始的
(0, x, x) -> (1, 0, x) -> (2, 0, 0) -> ..
, 以我的感觉我极有可能会写(0, 1, x) -> (1, 0, 0) -> .. 我的逻辑是在pc0
的时候,r1
赋值为0了, 但是在状态机中表示的是一个瞬间的状态所以在pc0
的时候,r1
还没有被赋值,所以上面的(0, x, x)是对的
RTFSC
函数: getopt()
变量: _IMAGE_START_
: 客户程序的固定内存位置
x86寄存器结构实现:
原题:
1 | * TODO: Re-organize the `CPU_state' structure to match the register │ |
题目很明显需要我们将RTL寄存器与通用寄存器(GPRs)联系起来(很尴尬的是刚开始我并没有看到这段话T_T), 并提示我们使用union来实现。
源代码:
1 | typedef struct { |
那么有了提示思路就很明确, 我们只需要把gpr[]数组跟各个rtlreg共享内存位置即可。
于是我首先是这样构造:
1 | union { |
很明显的,gpr[]数组的跟RTLREG结构体共享同一段地址,我们对gpr[]每个元素的修改也会直接影响到RTLREG的值。
但是,测试不通过
我很奇怪,但是找不到任何问题,在我不知道怎么修改的乱修改之后发现只要把gpr[]数组也改成union联合体就可以:
1 | union { |
从整体看,我并没有找到问题, 两段代码都是对rtlreg和gpr[]数组的内存地址统一,从功能上来看都是相同的。
答案就是, 在第一段代码中gpr[]是一个结构体代码,那么就意味着在结构体中的变量是一段连续内存地址中相互独立的:每个成员占有独立的内存空间, _32, _16, _8[2]都是独立的内存地址, 而这显然不符合寄存器的结构, 在i386手册中,通用寄存器是这么定义的:
那么在第二段代码中_32, _16, _8[2]本质是共享了同一段内存地址,这意味着对其中任一成员的修改都会影响到同一内存位置的其他成员。
一些奇怪的问题:
在上面图片中可以看到,RTLREG的顺序跟我的结构体中的顺序并不相同,但是却可以正常运行, 但是当我按照图片上的顺序修改之后却无法运行。