2023年10月11日星期三

祭祖04

祭祖04

祭祖04

补遗

过程调用,jal label and jr $ra,以一个叶子过程为示例自行翻阅上篇博客
在这个示例中,$sp 为栈指示器

栈操作和机器字
栈操作在调用中

这里为什么要引入栈?
因为控制权已经转给现在调用的过程,需要保存现场。
例如,$s0在过程中要用到,所以保存。

返回之前需要回复现场,$s0原先的值从栈中取出。

lw和addi搭配实现取出。

过程调用6步。

非叶子过程:
调用者需要保存:
ra,s0,a0等,这在之后call的递归函数中存储变量,同时本次函数还未返回,后续还要执行,用这些寄存器,但现在要给即将call的函数用。所以暂时保存。

例如 n=4时的fact(4),
fact(4)

beq 相等时跳转
slti 无符号数比较小于立即数时置位
更多指令

memory layout

在内存中如何存储程序?
反汇编后可看到程序分为两块,
{数据代码 \begin{cases} 数据 \\ 代码 \end{cases}

运行起来的程序叫做进程(linux),或者叫任务(windows)
无法看懂windows内存?那是因为你少了三幅图和一个工具
为这些程序分配空间,Linux 32位分配4G,高1G为内核空间,低3G的为用户空间。64位可用的虚拟地址空间大小为 2482^{48} 字节,虚拟地址虽然是64bits,但只有低48bits有效,高12bits是第47bit的符号扩展。

虚拟空间

虽然可能用不满但是还是分配固定大小。

程序空间,并非物理空间,这部分第五章讲

reserved 给操作系统用。

数据

{参与数据:无符号数/有符号数(补码编码的形式)不参与数据:在内存中怎么存放?字符形式。 \begin{cases} 参与数据: 无符号数/有符号数(补码编码的形式) \\ 不参与数据:在内存中怎么存放?字符形式。 \end{cases}
如ascii为由7位二进制组成。
95 graphic 33 control
“75” 0x37 0x35

unicode 1-3个字节对所有文字编码。
如中文用两个字节表示
内存中如何存?
存储标准utf-8 utf—16,变长的

UTF-8详解

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
  2. 对于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 rt
  • sb 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

代码

{运算指令数据传送指令控制分支指令 \begin{cases} 运算指令\\ 数据传送指令\\ 控制分支指令 \end{cases}

寻址总结

寻址方式,根据oprand找到操作数,
寻址方式一览
寄存器寻址
基址寻址,base addressing : offset(base)
立即数寻址
pc-相对寻址。如条件转移

无条件呢,直接寻址

作业

第二章4,6,14,26,39,40,41,42
其中在26-1中,可能存在误植s2寄存器为t2,需要手工改题修改。
博主所用教材为第五版

0 评论:

发表评论