20145229 《信息安全系统设计基础》第6周学习总结
20145229 《信息安全系统设计基础》第6周学习总结
教材学习内容总结
4.1.1 程序员可见的状态
- Y86程序中的每条指令都会读取或者修改处理器状态的某些部分。这称为程序员可见状态,程序员可以是写程序的人或者产生机器级代码的编译器。要表示处理器保证机器级程序达到程序员可见状态即可。
- Y86有8个寄存器:%eax,%ecx,%edx,%ebx,%esi,%edi,%esp,%ebp,每个寄存器储存一个字。%esp被出栈、入栈、调用和返回指令作为栈指针
- 3个一位条件码:ZF SF和OF,负责保存最近的算术或逻辑指令对程序有影响的信息
- 程序计数器存放正在执行的地址
- 存储器就是一个保存着程序和数据的字节数组。Y86程序用虚拟地址来引用存储器位置。我的理解即为虚拟存储器就好比一个隐形的存储箱,里面存了各种数据和程序,每个数据和程序都有自己隐形地址,而硬件和操作系统就是将这个隐形的地址转换成实际的物理地址,然后我们就可以知道数据保存的真实位置。
- 程序状态的最后部分状态码start表明执行的总体状态,就是程序是否故障或者正常运行。
4.1.2 Y86指令
-
Y86 ISA的指令描述
-
IA32的movl指令根据源和目的分成了4个指令:irmovl,rrmovl,mrmovl和rmmovl。指令器的第一个字母代表源的类型(立即数i,寄存器r,存储器m),第二个字母代表目的的类型(寄存器r,存储器m)
-
存储器传送指令的方式为简单的基址和偏移量形式。在地址计算中不支持第二遍变址寄存器和任何寄存器值的伸缩。在Y86中,不允许从一个存储器地址直接传送到另一个存储器地址,也不允许将立即数传送到存储器。
-
整数操作指令(OPI):addl,subl,andl和xorl。这些指令仅仅对寄存器数据操作,还将设置条件码零,符号和溢出
-
跳转指令(jXX):jmp、jle、jl、je、jne、jge和jg。根据分支指令的类型和条件码的设置选择分支。
-
条件传送指令(cmovXX):cmovle、cmovl、cmove、cmovne、cmovge、cmovg。
-
call指令将返回地址入栈然后调到目的地址。ret指令在调用中返回。
-
pushl和pppl实现入栈和出栈。
-
halt停止指令的执行,导致处理器停止,状态码为HLT。
4.1.3 指令编码
- 每条指令需要1到4个字节不等,一般两个寄存器占用一个字节,存储器则占用四个字节,指令的编码和功能占用一个字节。打个比方,rrmovl指令,它的字节长度是2,其中第一个字节代表了指令rrmovl,第二个字节代表了两个寄存器。
- 有的指令需要附加的寄存器 指示符字节,指定一个或者两个寄存器,字段分别为rA和rB,它们可以用于各种寄存器从而发挥不同的作用。有的字节需要附加的4字节常数字,可以用作irmovl的立即数数据,rmmovl和mrmovl的地址符的偏移量以及分支指令和调用指令的目的地址。所有整数采用小端码编码,当指令按照反汇编格式书写的时候,字节就以相反的顺序出现。举个例子,rmmovl%esp,0x12345(%edx),用16进制表示,这里我思考了很久,然后得到了具体的分析,首先rmmovl由表中得到第一个字节是40,%esp和%edx为4和2,即40和42分别占了2个字节,剩余0x12345,在前面补0成4个字节就是 00 01 23 45,字节以相反的顺序出现就是45 23 01 00,最后合在一起就是40 42 00 01 23 45
4.1.4 Y86异常
对于Y86来说,程序员可见的状态包括状态码stat,它描述程序执行的总体状态,它有四种不同的代码值:
1、AOK,表示程序正常
2、HLT,处理器执行halt指令
3、ADR,遇到非法地址
4、INS,遇到非法指令
4.1.5 Y86
- 这个部分课本上主要是给了一个代码来讲解Y86与IA32的不同以及通过YSA汇编器对代码进行汇编后对代码的解释,主要是给出了汇编中的一些小技巧,比如“·”开头的次为汇编器命令,“·posX”即为汇编器应该从地址X处开始产生代码,“Stack”和“·pos0xX”代表一个提示符,提示从地址X开始,向低地址增长。这一小节的内容帮助了我如何看懂汇编指令。
4.1.6 一些Y86指令的详情
- 需要特别注意的指令组合,当在执行pushl%esp指令时,由于要入栈的寄存器会被同一条指令修改,因此有两种规定:(1)压入%esp的原始值 (2)压入减去4的%esp的值
4.2.1 逻辑门
- 逻辑门有是数字电路的基本计算元素。逻辑门对应的HCL表达式为:AND用&&表示,OR用||表示,NOT用!表示
4.2.2 组合电路和HCL布尔表达式
- 由多个逻辑门组成的计算块称为逻辑电路
- 这一小节的内容不难理解,只是运用与或非进行组合,和之前的离散数学很像,就不多说了
4.2.3 字级的组合电路和HCL整数表达式
- 通过将与或非逻辑门进行更复杂的组合可以实现更多的功能,通过输入字的各位数,用逻辑门来进行对比,确定两个字是否相等
- 通过HCL电路,可以写出相应的情况表达式
[
select_1: expr_1
...
select_k: expr_k
]
4.2.5 存储器和时钟
组合电路从本质讲师不存出任何信息的,为了产生时序电路,需要引入存储设备:时钟寄存器和随机访问存储器。寄存器操作:当时钟信号上升时,寄存器输入上的值成为新的寄存器状态,时钟寄存器的典型应用是PC、条件码寄存器CC以及程序状态stat。它们都有明确的输入,这意味着它们的值其实是某几个值的一个函数。随即访问存储器最典型的例子就是我们的寄存器文件(也就是8个程序寄存器)和随即访问存储器(也就是我们常说的内存)。它们没有明确的输入值,因此不存在函数关系。
寄存器文件一般有两个读端口和一个写端口。每个端口都附带一个地址来标识操作的是哪个寄存器,而对于写端口,还有一个输入数据,对于读端口,则还有一个输出数据。
当srcA或srcB被设成某个寄存器ID时,一段延迟之后,储存在相应程序寄存器的值就会出现在valA或valB上。
向寄存器写入字是由时钟信号控制的,每次时钟上升时,输入valW上的值会被写入输入dstW上的寄存器ID指示灯程序寄存器。
如果在读端口和写端口同时使用一个寄存器ID,就会看到一个从旧值到新值的变化。
对于随即访问存储器来说,与寄存器文件非常相似。不同的是,随即访问存储器只有一个地址输入,一个写的数据输入,一个读的数据输出。如下图
4.3 Y86
4.3.1 将处理组织成阶段
各个阶段以及各阶段内执行的操作:
- 取指:从存储器读取指令字节,地址为程序计数器(pc)的值,从指令中抽取出指令指示符字节的两个四位部分,成为icode(指令代码),和ifun(指令功能)。它还可能取出一个寄存器指示符字节,致命一个或者两个寄存器操作数指示符rA和rB,也可能取出一个四字节常数字valC。下一条指令的地址valP为pc的值加上已取出指令的长度。
- 译码:从寄存器文件读入最多两个操作数,得到valA和/或valB。
- 执行:算数/逻辑单元要么执行指令指明的操作,计算存储器引用的有效地址,要么增加或者减少栈指针,得到的值称为valE。如果有条件码,在这个阶段检验条件码。
- 访存:将数据写入存储器,或从存储器读出数据,读出的值称为valM。
- 写回:最多可以写两个结果到寄存器文件。
- 更新PC:将PC设置成下一条指令的地址。
指令如下:
除了不需要一个寄存器指示符字节之外,跳转指令在取指和译码阶段和其他指令类似,在执行阶段,检查条件码和跳转条件来确定是否需要分支,产生一个一位信号cnd,在更新PC阶段,检查这个标志,如果为1,将PC设为valC(跳转目标),如果为0,将PC设为valP(下一个指令的地址)。
4.3.2 SEQ硬件结构
硬件单元与各个处理阶段相关联:
- 取指:将程序计数器寄存器作为地址,指令存储器读取指令的字节,PC增加器计算valP。
- 译码:寄存器文件有两个读端口A和B,从这个两个端口同时读寄存器值valA和valB。
- 执行:执行阶段会根据指令的类型,将算数/逻辑单元用于不同的目的,对于整数操作,它要执行指令所指定的运算,对于其他指令,它作为一个加法器来计算增加或者减少栈指针,或者极端有效地址,或者只是简单的加0,将一个输入传递到输出。
- 条件码寄存器(CC)有三个条件码位,ALU负责计算条件码的新值,当执行一条跳转指令时,会根据条件码和跳转类型来极端分支信号Cnd。
- 访存:在执行访存操作时,数据存储器读出或者写入一个存储数字,指令和数据存储器访问的是相同的存储器位置,但是用于不同的目的。
- 写回:寄存器文件有两个写端口,端口E用来写ALU计算出来的值,端口M用来写从数据存储器中读出的值。
4.3.3 SEQ的时序
SEQ的实现包括组合逻辑和两种存储器设备:
-
时钟寄存器(程序计数器和条件码寄存器)
-
随机访问存储器(寄存器文件 指令寄存器 数据存储器)
-
组合逻辑不需要任何时序或者控制,只要输入变化了,值就通过逻辑门网络传播,指令存储器单元可以看成是组合逻辑。
-
程序计数器、条件码寄存器、数据存储器和寄存器文件这四个硬件单元通过一个时钟信号来控制,每个时钟周期,程序计数器都会装载新的指令地址,只有在执行整数运算指令时,才装载条件码寄存器,只有在执行rmmovl,pushl,call指令时,才会写数据存储器,寄存器文件的两个写端口允许每个时钟周期更新两个程序寄存器。
-
要控制处理器中活动的时序,只需要寄存器和存储器的时钟控制。
-
Y86指令集的组织原则:处理器从来不需要为了完成一条指令的执行而去读由该指令更新了的状态。
4.3.4 SEQ阶段的实现
HCL描述中使用的常数值:
nop:PC+1
halt:处理器状态被设置为HLT,处理器停止运行
- 取指阶段
以PC作为第一个字节的地址,这个单元一次从存储器读出六个字节。
第一个字节为指令字节,分为两个4位的数,分为控制逻辑块计算指令和功能码。
根据icode值计算出三个一位的信号:
instr_valid:用来发现不合法的指令
need_regids:这个指令包含寄存器指示符字节吗
need_valC:这个指令包括常数字吗
- 译码和写回阶段
译码和写回阶段都要访问寄存器文件。
根据指令代码icode和寄存器指示值rA和rB,可能还会根据执行阶段计算出的Cnd条件信号,产生四个不同的寄存器文件的寄存器ID,寄存器IDsrcA表明该读哪个寄存器以产生valA。 - 执行阶段
这个单元根据alufun信号的设置,对输入aluA和aluB执行ADD SUB AND XOR运算,ALU的输出就是valE信号。
执行阶段还包括条件码寄存器。
标号为cond的硬件单元会根据条件码和功能码来确定是否进行条件分支或者条件数据传送。 - 访存阶段
访存阶段的任务是读或者写程序数据,两个控制块产生存储器地址和存储器输入数据的值。执行读操作时,数据存储器产生值valM。 - 更新PC阶段
新的PC可能是valC valM valP
练习题
4.1
第一行题目中说了这行表示这段目标代码的起始地址是0x100,所以第一行的字节编码为0x100
第二行irmovl $15,%ebx 使用了irmovl指令,irmovl指令的编码为30frB,在这里rB是%ebx,标识符为3,常数15的十六进制表示为00 00 00 0f,反向顺序写就是0f 00 00 00,
所以第二行的字节编码为0x100:30f30f000000
第三行rrmovl %ebx,%ecx 使用了rrmcvl指令,指令的编码是20rArB,这里%ebx,%ecx就是rArB,所以就是2031
第4行rmmovl %ecx,-3(%ebx) 使用了rmmovl指令,指令编码是40rArB,根据表就是4013,-3的原码为0000 0000 0000 0000 0000 0011,取反1111 1111 1111 1111 1111 1100,加1后为1111 1111 1111 1111 1111 1101,就是F F F F F D,反向顺序就是FD FF FF,最后第4行的编码是4013FDFFFF
第5行addl %ebx,%ecx ,使用了addl,编码为60,即为6031
4.2
A.
0x100:30f3fcffffff40630008000000
irmovl $-4,%ebx
rmmovl %esi,0x800(%ebx)
halt
B.
0x200:a06f80080200000030f30a00000090
pushl %esi
call proc
halt
irmovl $10,%ebx
ret
C.
0x300:50540700000010f0b01f
mrmovl 0x7(%esp),%ebp
nop
非法
popl %ecx
4.8
写出信号xor的HCL表达式,xor就是异或,输入为a和b。信号xor和上面定义的eq有什么关系?
bool xor = (a && !b) || (!a && b)
与bool eq = (!a && !b) || (a && b)的区别为:互补
4.10
用HCL表示:用Middle表示中间的数
int Middle3 = [
A<=C && A>=B :A;
A<=B && A>=C :A;
B<=A && B>=C :B;
B<=C && B>=A :B;
1 :C;
];
4.16
根据图4-17中目标代码第9行call处理情况填写具体的处理阶段
- 取指
icode:ifun<-M1[0x023]=8:0
valC<-M4[0x024] = 0x29
valP<-0x028
- 译码
valB<-R[%esp]=128
- 执行
valE<-128-4=124
- 写回
R[%esp]<-124
- 更新PC
PC<-0x029
效果是将%esp设置为124,将0x028(返回地址)存放到该存储器地址
4.17
写出SEQ中实现need_valC的HCL代码
bool need_valC = icode in {IIROMVL,IRMMOVL,IMRMOVL,IJXX,ICALL};
家庭作业
4.48
取指阶段 icode:ifun=M1[PC]=C:0
rA:rB<-M1[PC+1]
valC<-M4[pc+2]
valP<-PC+6
译码阶段 valB<-R[rB]
执行阶段 valE<-valB+valC
SetCC
写回阶段 R[rB]<-valE
实验楼
本周代码托管截图
其他(感悟、思考等,可选)
这次的学习持续了周四到周天4天学习时间,整个给我的感觉就是自己的脑容量不够用,老师本来的要求是弄懂的不用写上去,但是我还是把自己学习的内容都记录上去了,自己的基础没有别人好,当然要比别人更努力一点,我首先从看教材入手,基本上是看一小节的内容然后写一点博客,时间耗费了太久,由于之前的不努力导致现在的吃力,做练习题做了非常久,但是也有非常惊喜的地方,当我花了30分钟算字节算负数的16进制表示取反加一巴拉巴拉的之类的,但是最后算出来了,真的是非常有成就感的事情,第四章的内容大体上是书本的知识吧,学一点东西不认识又得翻以前的内容,这样的学习经历已经很久都没有了,痛并快乐着。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 2/4 | 18/38 | |
第三周 | 500/1000 | 3/7 | 22/60 | |
第四周 | 300/1300 | 2/9 | 30/90 |