祭祖04
补遗
过程调用,jal label and jr $ra
,以一个叶子过程为示例自行翻阅上篇博客
在这个示例中,$sp 为栈指示器
栈操作和机器字
这里为什么要引入栈?
因为控制权已经转给现在调用的过程,需要保存现场。
例如,$s0在过程中要用到,所以保存。
返回之前需要回复现场,$s0原先的值从栈中取出。
lw和addi搭配实现取出。
过程调用6步。
非叶子过程:
调用者需要保存:
ra,s0,a0等,这在之后call的递归函数中存储变量,同时本次函数还未返回,后续还要执行,用这些寄存器,但现在要给即将call的函数用。所以暂时保存。
例如 n=4时的fact(4),
beq 相等时跳转
slti 无符号数比较小于立即数时置位
更多指令
memory layout
在内存中如何存储程序?
反汇编后可看到程序分为两块,
运行起来的程序叫做进程(linux),或者叫任务(windows)
无法看懂windows内存?那是因为你少了三幅图和一个工具
为这些程序分配空间,Linux 32位分配4G,高1G为内核空间,低3G的为用户空间。64位可用的虚拟地址空间大小为 字节,虚拟地址虽然是64bits,但只有低48bits有效,高12bits是第47bit的符号扩展。
虽然可能用不满但是还是分配固定大小。
程序空间,并非物理空间,这部分第五章讲
reserved 给操作系统用。
数据
如ascii为由7位二进制组成。
95 graphic 33 control
“75” 0x37 0x35
unicode 1-3个字节对所有文字编码。
如中文用两个字节表示
内存中如何存?
存储标准utf-8 utf—16,变长的
- 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
- 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
下表总结了编码规则,字母x表示可用编码的位。
Unicode符号范围 | UTF-8编码方式 |
---|---|
(十六进制) | (二进制) |
0000 0000-0000 007F | 0xxxxxxx |
0000 0080-0000 07FF | 110xxxxx 10xxxxxx |
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。
严的 Unicode 是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5。
作者:剑指漠北
链接:https://www.jianshu.com/p/e1c54835a984
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
utf-32 occupy large storage but no need to parser
Bitwise operations
寄存器是32位,怎么存8位的数据
MIPS byte/halfword load/store
- String processing is a common case
lb rt, offset(rs)
lh rt, offset(rs)
Sign extend to 32 bits in rt
rt先放byte的低8位,再根据最高的符号位设置最高位符号位。lbu rt, offset(rs)
lhu rt, offset(rs)
Zero extend to 32 bits in rtsb rt, offset(rs)
sh rt, offset(rs)
Store just rightmost byte/halfword of the reg
赋值
示例:以下c语言所写的不安全strcpy
void strcpy (char x[], char y[])
{
int i;
i = 0;
while ((x[i]=y[i])!='\0')
i += 1;
}
Addresses of x, y in $$a0$, $$a1$
i in $s0
strcpy:
addi $sp, $sp, -4 # adjust stack for 1 item
sw $s0, 0($sp) # save $s0
add $s0, $zero, $zero # i = 0
L1: add $t1, $s0, $a1 # addr of y[i] in $t1
lbu $t2, 0($t1) # $t2 = y[i]
add $t3, $s0, $a0 # addr of x[i] in $t3
sb $t2, 0($t3) # x[i] = y[i]
beq $t2, $zero, L2 # exit loop if y[i] == 0
addi $s0, $s0, 1 # i = i + 1
j L1 # next iteration of loop
L2: lw $s0, 0($sp) # restore saved $s0
addi $sp, $sp, 4 # pop 1 item from stack
jr $ra # and return
赋值样例1
*x = *y // x, y (int*) pointers stored in $s0, $s1
lw $t0,0($s1)
sw 0($s0),$t0
赋值样例2
int x = 5;
*p = *p + x + 10;
// assume $s0 holds p; $s1 is x
addi $s1, $0, 5
lw $t0, 0($s0)
add $t0, $t0, $s1
addi $t0, $t0, 10
sw $t0, 0($s0)
32位常数
Most constants are small
- 16-bit immediate is sufficient
For the occasional 32-bit constant
lui rt, constant
- Copies 16-bit constant to left 16 bits of rt
- Clears right 16 bits of rt to 0
- 这条命令很重要,在设计cpu时需要首先实现
command | 后s0的值 |
---|---|
lui $s0, 61 | 0000 0000 0011 1101 0000 0000 0000 0000 |
ori $s0, $s0, 2304 | 0000 0000 0011 1101 0000 1001 0000 0000 |
代码
寻址总结
寻址方式,根据oprand找到操作数,
寄存器寻址
基址寻址,base addressing : offset(base)
立即数寻址
pc-相对寻址。如条件转移
无条件呢,直接寻址
作业
第二章4,6,14,26,39,40,41,42
其中在26-1中,可能存在误植s2寄存器为t2,需要手工改题修改。
博主所用教材为第五版
0 评论:
发表评论