段,位与指令指针寄存器
段,位与指令指针寄存器
RISC-V CSR寄存器(1)CSR简介和CSR指令
1.CSR简介
相关参考文章:
RISC-V教学教案
除去之前介绍的32个通用寄存器之外,还有一类扩展寄存器,称为CSR(control and status register,控制和状态寄存器)。
顾名思义,这类寄存器与控制CPU和表明CPU状态相关。
特权指令除了包括CSR指令外,还有其他的特权指令,这里将介绍6条操作CSR寄存器的CSR指令。
CSR寄存器中有些指定字段行为的定义和缩写,有以下几种[1]:
- WIRI:
Reserved Writes Ignored,Read Ignore Values(保留写入忽略,读取忽略值)
- WPRI:
Reserved Writes Preserve Values, Reads Ignore Values(保留写入保留值,读取忽略值)
- WLRL:
Write/Read Only Legal Values(读写合法值)
- WARL:
Write Any Values, Reads Legal Values(任意写,读合法值)
这里只做介绍,也不多做讨论。
所有的CSR指令都是每次只能对一个CSR寄存器操作,其机器码如图1所示。
可以看到CSR指令类似于I-type指令。
虽然也有12位的立即数域,但是实际上机器码的bit 20-31是用来 索引相应CSR寄存器的地址。
所以理论上,一共可以实现2^12 = 4096位CSR寄存器。
按照惯例,CSR地址的高位(CSR[11:8]/机器码的bit 31-28)用于根据权限级别对CSR的读写可访问性进行编码。
前两位(CSR[11:10]/机器码的bit 31-30)指示该CSR寄存器是可读可写(00,01或10)还是只读(11)。
接下来两位(CSR[9:8]/机器码的bit 29-28)编码表明可以访问该CSR寄存器的最低特权级别 [1]。00 => user CSR; 01 => supervisor CSR; 10 => hypervisor CSR; 11 => machine CSR
CSR的opcode 是111_0011,被称为SYSTEM。
根据不同的funct3,可以确定不同的CSR指令。
图1 CSR指令机器编码 [1]
这6条CSR指令又可以分为两类:
- 一类是寄存器操作:
CSRRW,CSRRS,CSRRC
- 一类是立即数操作:
CSRRWI,CSRRSI,CSRRCI。
对于立即数操作的3个指令,5位的立即数被放在了rs1的位置,被称为uimm[4:0],因为这些立即数是无符号(unsigned immediate)的。
这6条CSR指令的rd与一般指令的目的寄存器没有差别,位于机器码的bit 7-11,共5位的索引。
常用的CSR寄存器可以分为4组,分别为:
- 用户模式(user mode)
- 监控模式(supervisor mode)
- 超级监控模式(hypervisor mode)
- 机器模式(machine mode)。
机器模式是基础的,所有的RISC-V CPU必须实现的模式。
其他三种是可选的。
这里将只会介绍机器模式下的CSR寄存器。
2.CSR指令
2.1.CSRRW
CSRRW(control and status register read and write,读后立即写控制状态寄存器)指令格式为CSRRW rd,csr,rs1。
t = CSRs[csr]; CSRs[csr] = x[rs1]; x[rd] = t 其机器码如图2所示,CSRRW的funct3是001。
该指令是把CSR寄存器中的值读出并赋值到rd寄存器中,再把rs1寄存器中的值写入CSR寄存器。
举例说明:
CSRRW x13,mie,x12将mie寄存器里的值读出并赋值给x13寄存器,再把x12寄存器中的值写进mie寄存器 可以看到,其机器码如图2所示,CSRRW的
opcode为111_0011
funct3为001
mie寄存器索引地址为12’b0011_0000_0100
rs1为 5’b0_1100
rd为 5’b0_1101
所以CSRRW x13,mie,x12对应的机器码为0011_0000_0100_01100_001_01101_1110011,对应的16进制为32’h3046_16f3
图 2 CSRRW机器编码格式 [2]
2.2.CSRRS
CSRRS(control and status register read and set,读后置位控制状态寄存器)指令格式为CSRRS rd,csr,rs1。
t = CSRs[csr]; CSRs[csr] = t | x[rs1]; x[rd] = t 其机器码如图3所示,CSRRS的funct3是010。
该指令是把CSR寄存器中的值读出并赋值到rd寄存器中,且将CSR寄存器中的值和寄存器rs1中的值按位或(bitwise OR)的结果写入CSR寄存器。
指令示例:
CSRRS x13,mie,x12将mie寄存器里面的值读出并赋值给x13寄存器,并将mie寄存器里的值和x12寄存器里的值按位或的结果写入mie寄存器中。
图3 CSRRS机器编码格式 [2]
2.3.CSRRC
CSRRC(control and status register read and clear,读后清除控制状态寄存器)指令格式为CSRRC rd,csr,rs1。
t = CSRs[csr]; CSRs[csr] = t &~x[rs1]; x[rd] = t 其机器码如图4所示,CSRRC的funct3是011。
该指令是把CSR寄存器中的值读出并赋值到rd寄存器中,且将CSR寄存器中的值和寄存器rs1中的值取反后按位与(bitwise AND)的结果写入CSR寄存器。
指令示例:
CSRRC x13,mie,x12将mie寄存器里面的值读出并赋值给x13寄存器,并将mie寄存器里的值和x12寄存器里的值取反后按位与的结果写入mie寄存器中。
图4 CSRRC机器编码格式 [2]
2.4.CSRRWI
CSRRWI(control and status register read and write immediate,立即数读后写控制状态寄存器)指令格式为CSRRWI rd,csr,zimm[4:0]。
x[rd] = CSRs[csr]; CSRs[csr] = zimm 这里的zimm[4:0]表示高位由0(zero)扩展的立即数。
其机器码如图5所示,CSRRWI的funct3是101。
该指令是把CSR寄存器中的值读出并赋值到rd寄存器中,再把五位的零扩展的立即数zimm写入CSR寄存器。
指令示例:
CSRRWI x13,mie,5将mie寄存器里的值读出并赋值给x13寄存器,再把5'b0_0101高位扩展0成32'h0000_0005写进mie寄存器
图5 CSRRWI机器编码格式 [2]
2.5.CSRRSI
CSRRSI(control and status register read and set immediate,立即数读后设置控制状态寄存器)指令格式为CSRRSI rd,csr,zimm[4:0]。
t = CSRs[csr]; CSRs[csr] = t | zimm; x[rd] = t 其机器码如图6所示,CSRRSI的funct3是110。
该指令是把CSR寄存器中的值读出并赋值到rd寄存器中,且将CSR寄存器中的值和五位的零扩展的立即数zimm按位或(bitwise OR)的结果写入CSR寄存器(CSR寄存器的第五位及更高位不变)。
指令示例:
CSRRSI x13,mie,5将mie寄存器里的值读出并赋值给x13寄存器,再把5'b0_0101高位扩展0成32'h0000_0005和mie寄存器里的值按位或写进mie寄存器
图 6 CSRRSI机器编码格式 [2]
2.6.CSRRCI
CSRRCI(control and status register read and clear immediate,立即数读后清除控制状态寄存器)指令格式为CSRRCI rd,csr,zimm[4:0]。
t = CSRs[csr]; CSRs[csr] = t &~zimm; x[rd] = t 其机器码如图7所示,CSRRCI的funct3是111。
该指令是把CSR寄存器中的值读出并赋值到rd寄存器中,且将CSR寄存器中的值和五位的零扩展的立即数zimm取反后按位与(bitwise AND)的结果写入CSR寄存器(CSR寄存器的第五位及更高位不变)。
指令示例:
CSRRCI x13,mie,5将mie寄存器里的值读出并赋值给x13寄存器,再把5'b0_0101高位扩展0成32'h0000_0005,取反后为32'hFFFF_FFFA和mie寄存器里的值按位与写进mie寄存器
图7 CSRRCI机器编码格式 [2]
对于段寄存器/标志位寄存器/指令指针寄存器
对于这几个寄存器我们这里简单的介绍一下,在刚接触这几个寄存器的时候,并不用说非常深入的研究这几个寄存器,等积累到一定后,就很好理解了。
段寄存器
首先帖一下各个段寄存器和对应的含义
- CS:Code Segement,代码段寄存器
- SS:Stack Segment,栈段寄存器
- DS:Data Segment,数据段寄存器
- ES:Extra(Data) Segment,数据段寄存器
- FS:Data Segment,数据段寄存器
- GS:Data Segment,数据段寄存器
这里的用法就是不同的段代表了不同区域,最常见的就是数据段取值ds:[]和栈段取值ss:[],如图下OD中的汇编指令就是从数据段ds:[]中取值。这里重点在哪里呢?其实只要知道汇编指令中ds:[]这些是从那个段里取值就行,常见的如ss:[],ds:[]。这里的难点是fs寄存器,它用于SEH、PEB、TEB这些,不过这些都是之后的内容,大家这里知道就行。
从ds数据段中取值
标志位寄存器
标志位寄存器算是比较难以理解的一个部分了,首先标志位寄存器是4字节大小的寄存器,而它的每个位都包含了不同含义
逆向工程核心原理中标志位寄存器图
OD中列出了几个比较总要的标志位如下(逆向工程师偷师一下别人的资料):
- CF:若算术操作产生的结果在最高有效位(most-significant bit)发生进位或借位则将其置1,反之清零。这个标志指示无符号整型运算的溢出状态,这个标志同样在多倍精度运算(multiple-precision arithmetic)中使用。
- PF:如果结果的最低有效字节(least-significant byte)包含偶数个1位则该位置1,否则清零。
- AF:如果算术操作在结果的第3位发生进位或借位则将该标志置1,否则清零。这个标志在BCD(binary-code decimal)算术运算中被使用。
- ZF:若结果为0则将其置1,反之清零。
- SF:该标志被设置为有符号整型的最高有效位。(0指示结果为正,反之则为负)
- TF:将该位设置为1以允许单步调试模式,清零则禁用该模式。
- DF:这个方向标志(位于EFLAGS寄存器的第10位)控制串指令(MOVS, CMPS, SCAS, LODS以及STOS)。设置DF标志使得串指令自动递减(从高地址向低地址方向处理字符串),清除该标志则使得串指令自动递增。STD以及CLD指令分别用于设置以及清除DF标志。
- OF:如果整型结果是较大的正数或较小的负数,并且无法匹配目的操作数时将该位置1,反之清零。这个标志为带符号整型运算指示溢出状态。
看了上面这些可能会有点懵,我们这里主要就说一下ZF、OF和CF这几个标志位,还是来一个实际例子来看看
#include
<stdio.h>
#include
<Windows.h>
int
main
()
{
int
i =
1
;
if (i ==
1
)
{
unsigned
int
a =
0xFFFFFFF5
;
//
无符号整型最大为0xFFFFFFFF,加0x25溢出
unsigned
int
b =
0x00000025
;
unsigned
int
c = a + b;
int
d =
0x7FFFFFF0
;
//
有符号整型最大为0x7FFFFFFF,加0x25溢出
int
e =
0x00000025
;
int
f = d + e;
}
return
0
;
}
首先就是最简单的1=1的问题了,cmp指令就是“local.2-0x1”,这个汇编指令并不会改变local.2的值,那这里的运算用来做什么呢?其实就类似于if判断,然后这个判断用什么来标识结果呢?其实就是ZF标志位,ZF是当结果位0时置1,这里“local.2-0x1”运算结果为零,所以ZF置1,然后再结合下面的jnz就是完整的一个判断了。而jnz就是ZF=0时才实现跳转,至于jz/jnz这些跳转,我们这里可以暂时不用管,以后会列举出所有的跳转再慢慢对比。
判断设置ZF标志位
然后就是CF和OF,CF是无符号整型溢出置1,OF是有符号整型溢出置1
无符号溢出设置CF标志位
有符号溢出设置OF标志位这里就简单的列举了3个例子,还有其他的大家可以自己写代码来测试一下
指令指针寄存器
所谓的指令指针寄存器就是我们用OD时最常见的eip,它指向的就是我们将要运行的汇编指令,而这里我们知道这个就行。下图就是我们运行完了0096DB63处的mov ebp,esp后,eip就指向了0096DB65
寄存器窗口的eip和汇编代码窗口的eip
参考文献链接
Riscv.org, 2021. [Online]. Available: https://riscv.org/wp-content/uploads/2019/12/riscv-spec-20191213.pdf. [Accessed: 22- Feb- 2021]. [2] D. Patterson and A. Waterman, The RISC-V reader. Berkeley: Strawberry Canyon LLC, 2018.
https://mp.weixin.qq.com/s/-JC9NhGeITuJRS1M33PMsw
blog.csdn.net/jn1158359
https://mp.weixin.qq.com/s/WTIWJQI1jEUE72Pt-W6tqQ