Risc-V学习日记07
Day15
//发现作业涉及的知识是下一个视频里的md
exercise_5_1
b3 05 95 00
00 95 05 b3(小端序)
计算器(程序员):9505b3
00 95 05 b3
00000000-10010101-00000101-10110011
查看OP:
[b3]1-01100-11
为ADD 0000000 rs2 rs1 000 rd 0110011
0000000|0-1001|0101-0|000|0101-1|01100|11
funct7:0000000
funct3:000
rs2:01001
9
rs1:01010
10
rd:01011
11
ADD x11,x10,x9
ADDI(ADD Immediate)
语法
ADDI RD, RS1, IMM
例子
addi x5, x6, 1
x5 = x6 + 1
编码格式:
I-type
RV32I Base Instruction Set:
imm[11:0] rs1 000 rd 0010011
opcode (7): 0010011(OP-IMM)
立即数可以表达的数值范围:
由于imm[11:0]只占12bit表达范围有限
由于会被"符号扩展"为一个32位的数
#[-2^11 ,+2^11),即[-2048, 2047)
要赋值一个大数 (32 位) 怎么办
先引入一个新的命令先设置高20位,存放在rs1
构造高20位命令
LUI再加上剩余12位
然后复用现有的ADDI命令补上剩余的低12位即可
例子
利用 LUI + ADDI 来为寄存器加载一个大数
0x12345678
lui x1,0x12345 #x1=0x12345000
addi x1,x1,0x678 #x1=0x12345678
*** 0x12345FFF
***错误方法
lui x1, 0x12345 # x1 = 0x12345000
addi x1, x1, "0xFFF" # x1 = 0x12345FFF
***"0xFFF"为一个负数得不出应有的结果
解决方法:
解决方法一(太过复杂):
借一位:lui x1, 0x12346 # x1 = 0x12346000
addi x1, x1, -1 # x1 = 0x12345FFF
此时答案才为正确
解决方法二(正解):
伪指令:
LI:
语法
LI RD, IMM
例子
li x5, 0x12345678
x5 = 0x12345678
LI (Load Immediate)是一个伪指令(pseudoinstruction)
汇编器会根据 IMM 的实际情况自动生成正确的真实指令(instruction)
SUBI
并没有提供SUBI指令,可以用+(-1)实现[RS1=-1]
LUI (Load Upper Immediate)
语法
LUI RD, IMM
例子
lui x5, 0x12345
x5 = 0x12345 << 12
左移12位,右边空出12位填0
相当于12345-0000-0000-0000-0000
编码格式:
U-type
RV32I Base Instruction Set:
imm[31:12] rd 0110111
opcode (7):0110111
作用:
LUI 指令会构造一个 32 bits 的立即数
这个立即数的高 20 位对应指令中的 imm[31:12]
低 12 位清零
这个立即数作为结果存放在 RD 中
基于算术运算指令实现的其他伪指令
NEG
语法:
NEG RD, RS
等价指令:
SUB RD, x0, RS
x0写不了只能读出0
x0-RS=RD
RD=0-RS
指令描述:
对 RS 中的值取反并将结果存放在RD 中
例子:
neg x5, x6
MV
语法
MV RD, RS
等价指令
ADDI RD, RS, 0
RD=RS1+0
指令描述
将 RS 中的值拷贝到 RD 中
例子
mv x5, x6
NOP
语法
NOP
等价指令
ADDI x0, x0, 0
x0=x0+0
指令描述
什么也不做
例子
nop
exercise_asm/code/li
伪指令LI:
作用:
***替代lui实现复杂的赋值操作
语法
LI RD, IMM
例子
li x5, 0x12345678
x5 = 0x12345678
LI (Load Immediate)是一个伪指令(pseudoinstruction)
汇编器会根据 IMM 的实际情况自动生成正确的真实指令(instruction)
{
.text # Define beginning of text section
.global _start # Define entry _start
_start:
# imm is in the range of [-2,048, +2,047]
li x5, 0x80
addi x5, x0, 0x80
# imm is NOT in the range of [-2,048, +2,047]
# and the most-significant-bit of "lower-12" is 0
li x6, 0x12345001
lui x6, 0x12345
addi x6, x6, 0x001
# imm is NOT in the range of [-2,048, +2,047]
# and the most-significant-bit of "lower-12" is 1
li x7, 0x12345FFF
lui x7, 0x12346
addi x7, x7, -1
stop:
j stop # Infinite loop to stop execution
.end # End of file
}
AUIPC
语法
AUIPC RD, IMM
例子
auipc x5, 0x12345
x5 = 0x12345 << 12 + PC
左移十二位和PC相加
相对值变化了相对于PC[若是LUI则是相对于0]
效果:
表达范围更宽了
对比:
AUIPC:
将 20 位立即数(imm)左移 12 位,得到一个 32 位的数(offset),低 12 位补零:
offset = imm << 12
将当前 PC 的值与 offset 相加,得到目标地址:
Target_address = PC_current + offset
由于 offset 是一个 32 位的数,因此 AUIPC 可以覆盖的地址范围是
PC_current 所在的整个 32 位地址空间
换句话说,AUIPC 可以表示目标地址相对于当前 PC 的任意偏移量,从而拥有更广泛的表达范围。
LUI(Load Upper Immediate)指令
只是将一个 20 位的立即数加载到目标寄存器的高位
低位补零。这意味着 LUI 只能表示一个 20 位的常数,且低 12 位始终为零
它不能像 AUIPC 一样根据当前 PC 动态地计算目标地址。
编码格式:
U-type
RV32I Base Instruction Set:
imm[31:12] rd 0010111
opcode (7):0010111
作用:
和 LUI 指令类似,AUIPC 指令也会构造一个 32bits 的立即数
这个立即数的高 20 位对应指令中的 imm,低 12 位清零
***但和 LUI 不同的是,AUIPC 会先将这个立即数和 PC 值相加
将相加后的结果存放在 RD 中
由来:
LI构造出来的地址是一个绝对值
例子:
动态库(Dynamic Link Library,简称为DLL)
解释:
是一种计算机程序库(或称为共享库)
它包含了一系列可被多个程序共享和重用的代码、数据和资源。
与静态库(Static Library)不同,动态库在程序运行时动态加载到内存,并且可以在不同的程序间共享,从而节省系统资源和内存空间。
动态链接:
解释:
在编译时,程序并不将动态库的代码和数据嵌入到可执行文件中,而是在程序运行时动态加载。
这意味着多个程序可以共享同一个动态库,从而减少了重复的内存占用。
示例:
假设数学函数库的大小为100KB,"Program A"和"Program B"的大小分别为200KB和300KB
地址:
编译动态库: 首先,我们将"MathLibrary.dll"编译为一个动态库,其中包含一些数学函数的实现,例如"add"函数和"subtract"函数。
编译程序: 接下来,我们编译"Program",它调用了"MathLibrary.dll"中的数学函数。
加载过程: 当我们运行"Program"时,操作系统的动态链接器将加载"MathLibrary.dll"到进程的地址空间中。此时,会发生以下变化:
a. 加载地址: 动态链接器决定将"MathLibrary.dll"加载到进程的某个空闲地址空间中。这个加载地址通常是在运行时[动态分配]的,因此每次加载的位置可能不同。
b. 重定位:在"MathLibrary.dll"被加载到进程的地址空间后,动态链接器需要处理库内部的重定位问题。这是因为在编译时,"MathLibrary.dll"的代码和数据是按照编译时的加载地址进行的,
但在运行时,它被加载到了不同的地址空间。[因此,动态链接器会根据实际加载地址,对库内的地址引用进行重定位,使得代码和数据正确地映射到新的地址]。
符号解析: 一旦重定位完成,"Program"中的函数调用将会被解析为正确的地址,以便正确地调用"MathLibrary.dll"中的数学函数
优点节省空间:
静态链接:
1.静态链接时,每个程序都会包含数学函数库的副本,因此它们在运行时不会共享代码。
2.当我们编译"Program A"和"Program B"时,编译器将数学函数库的代码嵌入到这两个程序的可执行文件中
3.总共占用了100KB + 200KB + 300KB = 600KB
动态链接:
1.动态链接时,我们将数学函数库单独编译成一个动态库文件
2.当编译"Program A"时,它只包含调用数学函数库的函数名称和引用,而不会包含实际的数学函数库代码
3."Program A"在运行时,操作系统的动态链接器会加载MathLibrary.dll,并将其中的代码和数据加载到内存中
4.当编译"Program B"时,它也只包含数学函数库的引用,而不会包含实际的数学函数库代码
5."Program B"在运行时,同样的动态链接器会检测到MathLibrary.dll已经加载过了,所以不会重新加载,而是直接共享已加载的代码和数据
6.总共只占用了100KB + 200KB + 100KB = 400KB
LA (Load Address)LA是一个伪指令(pseudo-instruction)
语法
LA RD, LABEL
例子
la x5, foo
作用:
常用于加载一个函数或者变量的地址
解释:
具体编程时给出需要加载的 label,
编译器会根据实际情况利用 auipc 和其他指令自动生成正确的指令序列
代码:
{
.text # Define beginning of text section
.global _start # Define entry _start
_start:
la x5, _start # x5 = _start,
#x5是最终目标赋值寄存器,_start[label理解为地址]{自动分配}
#效果:将地址_start赋值给x5
jr x5
#跳转到x5,由于此时x5的地址为_start,重新执行_start,_start会一直循环执行
stop:
j stop # Infinite loop to stop execution
exit:
.end # End of file
}