跳转至

机器语言3

存储型程序概念

程序存储概念

  • 指令以二进制方式被编码
  • 程序存储在存储器中;可以从存储器中读取程序也可以写入程序
    • 存储方式与数据存储完全相同
  • 简化了计算机系统的软件/硬件设计
  • 存储器技术既可以存储数据,也可以存储程序
  • 由于存储在存储器单元中,因此指令和数据都有地址

二进制兼容

  • 程序是以二进制形式发布的
    • 指令集与程序之间是强相关
  • 新机器不仅能运行基于新指令编译产生的新程序,同样也最好能运行老程序
  • 上述特性被称为向后兼容(backward compatible)

把指令当作数看待

如果所有的数据都是以字为单位的,这包括每个寄存器的宽度,lwsw读写主存的单位是字。

由于计算机只能识别0和1,对于指令不能够直接理解,所以就可以将指令也进行编码,编码为与数据宽度相同的字,就像MIPS里所有指令的二进制编码宽度为32位

指令的32位被分为了若干,域就是指某一区域,由于该区域带有特殊含义,所以与其它区域进行区分,分为了若干域,由此不难知道同一个域在不同指令中的含义大体是相同的。

与数据不同的是,指令的32位有域的划分,不同域代表指令的不同信息,而数据32位整体被读取为一个数据信息。

MIPS的3类指令格式

  • I型指令:指令中包含立即数
    • lw/sw的偏移量是立即数;beq/bne同样包含有偏移
    • srl等移位指令:有5位立即数(移位位数),但是不属于I型指令
  • J型指令jjal
    • jr不是J型指令
  • R型指令:所有除上的其它指令,比如srljr

R型指令格式

R型指令的构成

R型指令分为6个域:6 + 5 + 5 + 5 + 5 + 6 = 32

31                                              0
|-------|-------|-------|-------|-------|-------|
|   6   |   5   |   5   |   5   |   5   |   6   |
|-------|-------|-------|-------|-------|-------|

每个域都有一个名字

31                                              0
|-------|-------|-------|-------|-------|-------|
|opcode |  rs   |  rt   |  rd   | shamt | funct |
|-------|-------|-------|-------|-------|-------|

每个域都被视为一个无符号整数 - 5位域表示范围为0~31 - 6位域表示分为为0~63 其中 - opcode代表指令操作,R型指令的opcode固定为0b000000 - functopcode组合,定义指令的具体操作,主要服务于R型指令 - rs指定第一个操作数(source寄存器) - rt指定第二个操作数(target寄存器) - rd指定结果回写的寄存器(destination寄存器)

注意:由于与具体指令相关,有些域是无效的

  • shamt移位指令中的移位位数

    除了移位指令,该域固定为0

I型指令格式

指令的立即数

指的是5位或6位的数字,过短则不认为是立即数

为了使得指令格式更为统一简洁,I型指令格式尽量选择与R型指令靠拢,由于使用了立即数,所以能使用的寄存器就只有2个

I型指令的构成

31                                              0
|-------|-------|-------|-----------------------|
|   6   |   5   |   5   |          16           |
|-------|-------|-------|-----------------------|

域的命名

31                                              0
|-------|-------|-------|-----------------------|
|opcode |  rs   |  rt   |       immediate       |
|-------|-------|-------|-----------------------|

不难发现前3个域与R型指令相同,尤其是opcode

其中 - opcode代表指令操作,I型指令的opcode为非零编码,总共可以编码63条指令(勘误gxpPPT) - rs指定第一个操作数(source寄存器) - rt指定第二个操作数(target寄存器) - immediate无符号或有符号数字 - 无符号:位运算指令(比如and/or/nor)、小于置位指令(比如slti等) - zero_ext()运算前需要进行无符号拓展 - 有符号:分支指令(如beq/bne等)、访存指令(如lw/sw等) - 以word为单位 - sign_ext()位运算前需要进行有符号拓展

lui

Load Upper Immediate(lui)

  • lui reg, imm
  • reg高位写入imm,低16位写入0

ori

  • ori $rd, $rs, imm
  • rs16位与imm进行或运算,利用这个可以将reg16位写入数字

分支指令(B类指令)

beqbne

31                                              0
|-------|-------|-------|-----------------------|
|opcode |  rs   |  rt   |       immediate       |
|-------|-------|-------|-----------------------|

比较rsrt,根据比较结果决定是否转移

并非所有的B类指令的rt域都是寄存器

需要指定要转移的地址

分支指令主要用于构造if-elsewhilefor - 转移范围通常很小(<50指令) - 函数调用和无条件跳转用J型指令 - B类指令的基地址就是PC(即当前这条B类指令的PC值)

PC相对寻址

PC相对寻址:PC为基地址,immediate为偏移(二进制补码) - 基本计算方法:\(PC \leftarrow PC + 偏移\) - 关键是得到偏移值

下一条指令的PC值的计算方法: - 比较结果为假:PC = PC + 4 - 比较结果为真:PC = (PC + 4) + (immediate * 4)

为什么immediate乘以4? 因为存储器是以字节为单位的 指令都是32位长,且指令是字对齐,所以最低2位恒为0 immediate没有必要存储最低2位,所以需要乘4

字对齐意味着存储地址相邻且能被4整除,即地址最低2位为0,半字对齐意味着存储地址相邻且能被2整除,即地址最低1位恒为0

由于immediate为16位有符号数,表示范围为\(-2^{15} —— +2^{15}\) 其量纲为,按照一行C代码对应10条指令,则可转移的C代码块大小为3000行,足够使用。

J型指令格式

I型指令的构成

31    26 25                                     0
|-------|---------------------------------------|
|opcode |             instr_index               |
|-------|---------------------------------------|

可转移范围为\(2^{28}\)即256MB

只有jr可以转移到4GB以内的任意地址,为R型指令

汇编实战

汇编:将汇编程序转化为二进制机器码的过程

每条指令的汇编基本步骤: 1. 表示出指令类型R/I/J 2. 表示出正确的域 3. 用10进制表示各个域的值 4. 把各个域的10进制转换为2进制 5. 用16进制表示整个机器码

反汇编实战

反汇编:反汇编是汇编的逆过程,即将指令二进制代码转换为汇编代码的过程。

反汇编基本步骤: 1. 用2进制表示指令 2. 根据opcode表示出指令类型R/I/J 3. 用10进制表示各个域的值 4. 用标识符表示各域,并添加相应的标号 5. 用汇编格式书写代码 6. 将汇编代码翻译为C