指令系统

发布时间 2023-10-24 22:52:48作者: echory3

指令格式

指令(又称机器指令)

  • 是指计算机执行某种操作的命令,是计算机运行的最小功能单位。
  • 一台计算机的所有指令的集合构成该计算机的指令系统,也成为指令集
  • 一台计算机只能执行系统中的指令,不能执行其他系统的指令

一条指令就是机器语言的一个语句,它是一组有意义的二进制代码。

一条指令通常要包括操作码字段和地址码字段两部分:

操作码(OP) 地址码(A)
用户要干什么 对谁进行操作

一条指令可能包含1、2、3、4个地址码----》根据地址码的数目不同,可以将指令分为零地址指令、一地址指令、二地址指令……

指令分类

地址指令

零地址指令

  1. 不需要操作数,如空操作、停机、中断等指令
  2. 堆栈计算机,两个操作数隐含存放再栈顶和次栈顶,计算结果压回栈顶

一地址指令

OP A1
  1. 只需要单操作数,如加1、减1、取反、求补等

    OP(A1)-->A1

    完成一条指令需要3次访存:取指-->读A1-->写A1

  2. 需要两个操作数,但其中一个操作数隐含再某个寄存器中(如隐含ACC)

    (ACC)OP(A1)-->ACC

    完成一条质量需要2次访存:取指-->读A1

!A1指某个主存地址,(A1)表示A1所指向的地址中的内容

二地址指令

OP A1(目的操作数) A2(源操作数)

常用于需要两个操作数的算数运算、逻辑运算相关指令

(A1)OP(A2)-->A1

完成一条指令需要访存4次:取值-->读A1-->读A2-->写A1

三地址指令

OP A1 A2 A3(结果)

常用于需要两个操作数的算数运算、逻辑运算相关指令

(A1)OP(A2)-->A3

完成一条指令需要访存4次:取值-->读A1-->读A2-->写A3

四地址指令

OP A1 A2 A3(结果) A4(下址)

(A1)OP(A2)--->A3 A4为下一条将要执行的指令的地址

完成一条指令需要访存4次:取值-->读A1-->读A2-->写A3

正常情况下:取指令后PC + 1

四地址指令:执行指令后,将PC的值修改为A4所指地址

!若指令总长度固定不变,则地址码数量越多,寻址能力越差

指令按字长分类

指令字长--一条指令的总长度

机器字长--CPU进行一次整数运算所能处理的二进制位数(通常与ALU直接相关)

存储字长--一个存储单元中的二进制代码位数(通常与MDR位数相同)

半字长指令、单字长指令、双字长指令 ---指令字长是机器字长的多少倍

指令字长会影响指令所需时间。如双字长指令需要两次访存

定长指令字结构:指令系统中所有指令的长度都相等

变长指令字结构:指令系统中各种指令的长度不等

指令按操作码长度分类

操作码的位数可以直接反映这个系统当中最多可以支持多少条指令

定长操作码:指令系统中所有指令的操作码长度都相同

​ n位--->2^n条指令

控制器的译码电路设计简单,但灵活性低

可变长操作码:指令系统中各指令的操作码长度可变

控制器的译码电路设计复杂,但灵活性高

定长指令字结构 + 可变长操作码 --->扩展操作码指令格式

指令按操作类型分类

  1. 数据传送

    LOAD

    把存储器(源)中的数据放到寄存器(目的)中

    STORE

    把寄存器中的数据放到存储器中

  2. 算数逻辑操作

  3. 移位操作

  4. 转移操作

    无条件转移

    JMP

    条件转移

    JZ:结果为0 JO:结果溢出 JC:结果有进位

    调用和返回

    CALL和RETURN

    陷阱(Trap)与陷阱指令

  5. 输入输出操作

    CPU寄存器与IO端口之间的数据传送(端口即IO接口中的寄存器)

数据传送类(1):进行主存与CPU之间的数据传送

运算类(2、3)

程序控制类(4):改变程序执行的顺序

输入输出类(5):进行CPU与I/O设备之间的数据传送

拓展操作码指令格式

不同地址数的指令使用不同长度的操作码

假设指令长度16位,每个地址码占4位:

三地址指令15条--->将1111留作二地址指令扩展操作码

二地址指令15条--->将11111111留作一地址指令扩展操作码

一地址指令15条--->将111111111111留作零地址指令扩展操作码

零地址指令16条

在设计扩展操作码指令格式的时候,必须注意以下两点:

  1. 不允许短码是长码的前缀,即短操作码不能与长操作码前面部分的代码相同
  2. 各指令的操作码一定不能重复

通常情况下,对使用频率较高的指令,分配较短的操作;对使用频率较低的指令,分配较长的操作码,从而尽可能减少指令译码和分析的时间。

设地址长度为n,上一层留出m种状态,下一层可拓展出m*2^n种状态

操作码是识别指令、了解指令功能和区分操作数地址内容的组成和使用方法等的关键信息。

指令寻址

下一条欲执行指令的地址(始终由PC给出)

每条指令的执行都分为“取指令”、“执行指令”两个阶段

顺序寻址

(PC) + "1" -->PC

这里的1理解为一个指令字长,实际加的值会因指令长度、编址方式而不同

跳跃寻址

由转移指令指出 JMP

数据寻址

确定本条指令的地址码指明的真实地址

一地址指令

操作码(OP) 寻址特征 形式地址(A)

求出操作码的真正地址,称为有效地址(EA)

二地址指令

操作码(OP) 寻址特征 形式地址(A1) 寻址特征 形式地址(A2)

假设指令字长 = 机器字长 = 存储字长,操作数为3

直接寻址

指令字中的形式地址A就是操作数的真实地址EA,即EA = A

一条指令的执行:取指令访存1次,执行指令访存1次,暂不考虑存结果,共访存2次

间接寻址

指令的地址字段给出的形式地址不是操作数的真正地址,而实操作数有效地址所在的存储单元的地址,也就是操作数地址的地址。

即EA = (A)

一条指令的执行:取指令访存1次,执行指令访存2次,暂不考虑存结果,共访存3次

寄存器寻址

在指令字中直接给出操作数所在的寄存器编号,即EA = Ri,其操作数在由Ri所指向的寄存器内。

一条指令的执行:取指令访存1次,执行指令访存0次,暂不考虑存结果,共访存1次

寄存器间接寻址

寄存器Ri中给出的不是一个操作数,而实操作数所在主存单元的地址,即EA = (Ri)

一条指令的执行:取指令访存1次,执行指令访存1次,暂不考虑存结果,共访存2次

隐含寻址

不是明显的给出操作数的地址,而是在指令中隐含着操作数的地址

立即寻址

形式地址A就是操作数本身,又称立即数,一般采用补码形式。

一地址指令

操作码(OP) # 0……011 (3)

形式地址A就是操作数本身,又称立即数,一般采用补码形式。#表示立即寻址特征

一条指令的执行:取指令访存1次,执行指令访存0次,暂不考虑存结果,共访存1次

偏移寻址

基址寻址

以程序的起始存放地址为起点

EA = (BR) + A

R0在指令中指明,要将哪个通用寄存器作为基址寄存器使用

OS课中的重定位寄存器就是基址寄存器

基址寄存器是面向操作系统的,其内容由操作系统或管理程序确定。在程序执行过程中,基址寄存器的内容不变。形式地址可变。

当采用通用寄存器作为基址寄存器是,可由用户决定哪个寄存器作为基址寄存器,但其内容仍由操作系统决定

变址寻址

程序员自己决定从哪里作为起点

EA = (IX) + A

IX --变址寄存器

其中IX可为编制寄存器(专用),也可用通用寄存器作为变址寄存器

变址寄存器是面向用户的,在程序执行过程中,变址寄存器的内容可由用户改变,形式地址A不变

相对寻址

以PS所指地址作为起点

EA = (PC) + A

A是相对于PC所指地址的位移量,可正可负,补码表示

取出当前指令后,PC会指向下一条指令,相对寻址是相对于下一条指令的偏移

堆栈寻址

操作数放在堆栈中,隐含使用堆栈指针(SP)作为操作数地址

堆栈是存储器(或专用寄存器组)中一块待定的按“后进先出”(LIFO)原则管理的存储区,该存储区中被读/写单元的地址是用一个特定的寄存器给出的,该寄存器称为堆栈指针(SP)

硬堆栈---寄存器

软堆栈---主存

高级语言与机器级代码之间的对应

x86汇编语言指令基础

指令的作用:

  1. 改变程序执行流
  2. 处理数据

MOV 目的操作数d,源操作数s ------>将源操作数s复制到目的操作数d所指的位置中

MOV指令不支持两个操作数都来自主存

MOV eax,ebx 将寄存器ebx的值复制到寄存器eax中
MOV eax,5 将立即数5复制到寄存器eax中
MOV eax,dword ptr [af996h] 将内存地址af996h所指的32bit值赋值到寄存器eax中
MOV byte ptr[af996h],5 将立即数5复制到内存地址af996h所指的一字节中
MOV eax,dword ptr[ebx] 将ebx所指主存地址的32bit复制到eax中
MOV eax, [ebx] 将ebx所指主存地址的32bit复制到eax中,没写就默认32bit
MOV [af996h],5 将立即数5复制到内存地址af996h所指的32bit中,没写就默认32bit
MOV eax,dword ptr[ebx + 8] 将ebx + 8所指主存地址的32bit复制到eax中 + 8 = 偏移8位
MOV eax,dword ptr[af996 - 12h] 将内存地址af996 - 12h所指的32bit值赋值到寄存器eax中

dword ptr --双字,32bit

word ptr --单字,16bit

byte ptr --字节,8bit

x86框架CPU中的寄存器

每个寄存器都是32bit

EAX AX(使用低16位去掉E AH低16位中前8位 AL低16位中后8位)
EBX BX BH BL
ECX CX CH CL
EDX DX DH DL 通用寄存器(X = 未知)
ESI 以下四个只能固定使用32bit
EDI 变址寄存器(I = Index)
EBP 堆栈基指针
ESP 堆栈顶指针

常见的x86汇编指令

常见的算数运算指令

d: destination 目的操作数

s: source 源操作数

!目的操作数不可以是常量

add d,s 计算d + s,结果存入d
sub d,s 计算d - s,结果存入d
mul d,s/imul d,s 无符号数d * s,结果存入d/有符号数
div s/idiv s 无符号数edx:eax/s,商存入eax,余数存入edx/有符号数
取负数 neg d 将d取负数,结果存入d
自增 inc d 将d++,结果存入d
自减 dec d 将d--,结果存入d

进行除法运算时,默认将被除数放在eax与edx中,edx:eax--->进行位拓展,将32位的被除数拓展为64位。高位放在edx,低位放在eax

常见的逻辑运算指令

and d,s
or d,s
not d,s
异或 xor d,s
左移 shl d,s
右移 shr d,s

其他指令

  • 用于实现分支结构、循环结构的指令:cmp、test、jmp、jxxx
  • 用于实现函数调用的指令:push、pop、call、ret
  • 用于实现数据转移的指令:mov

AT&T格式和Intel格式

AT&T格式----->Unix、Linus的常用格式

Intel格式----->Windows的常用格式

选择语句的机器级表达

在x86中pc常被称为ip

无条件转移指令 jmp<地址> #PC无条件转移至<地址>

地址可以是常数(jmp 128)、寄存器(jmp eax)、主存(jmp [999])、标号(jmp NEXT)

mov eax,7
mov ebx,6
jmp NEXT
mov ecx,ebx
NEXT:  //使用__:锚定位置,名字可以自己取
mov ecx,eax

条件转移指令——jxxx

cmp a,b #比较a和b两个值

cmp eax,ebx
jg NEXT

!写汇编语言代码时,一般会以函数名作为“标号”,标注该函数指令的起始地址。

cmp指令的底层原理

cmp a,b————本质上是进行a-b减法运算,并生成标志OF、ZF、CF、SF,存入PSW

循环语句的机器级表达

用条件转移指令实现循环,需要4个部分组成:

  1. 循环前的初始
  2. 是否直接跳过循环
  3. 循环主体
  4. 是否继续循环

用loop指令实现循环

mov ecx,500 #用ecx作为循环计数器,ecx一个特殊功能就是作为循环的计数器,不可以用eax等
LoopTop:
...
loop LopTop #ecx-,若ecx!=0,跳转到LoopTop

loopnz————当ecx!=0 &&ZF==0时,继续循环
loopz————当ecx!=0 &&ZF==1时,继续循环

函数调用机器级表示

函数的栈帧:保存函数大括号定义的局部变量、保存函数调用相关的信息。

函数调用指令: call<函数名>

通常用函数名作为函数起始地址的<标号>

函数返回指令:ret

call指令的作用:

  1. 将IP旧值压栈保存(保存在函数的栈帧顶部)
  2. 设置IP新值,无条件转移至被调用函数的第一条指令

return指令的作用:

从函数的栈帧顶部找到IP旧值,将其出栈并回复IP寄存器

如何访问栈帧

x86系统中,默认4字节为栈的操作单位

push、pop指令实现入栈、出栈操作,x86默认以4字节为单位。指令格式如下:

​ push A //先让esp减4,再将A压入

​ pop B //栈顶元素出栈写入B,再让esp加4

方法一:

push、pop

方法二:

mov指令,结合esp、ebp指针访问栈帧数据

如何切换栈帧

push ebp #保存上一层函数的栈帧基址
mov ebp,esp #设置当前函数的栈帧基址

上面两个指令可以精简为一条指令enter

mov esp,ebp #让esp指向当前栈帧的底部
pop ebp #将esp所值的元素出栈,写入寄存器ebp

上面两个指令可以精简为一条指令leave

!除了main函数之外,其他所有函数的汇编代码结构都一样。

如何传递参数和返回值

栈帧最底部一定时上一层栈帧基址(ebp旧值)

栈帧最顶部一定时返回地址(当前函数的栈帧除外)

通常将局部变量集中存储在栈帧底部区域。——>C语言中越靠前定义的局部变量越靠近栈顶。目的在于栈溢保护基址的编译

通常将调用参数集中存储在栈帧顶部区域。——>参数列表中越靠前的参数越靠近栈顶

gcc编译器将每个栈帧大小设置为16B的整数倍(当前函数的栈帧除外),因此栈帧内可能出现空闲未使用的区域。

CISC和RISC

CICS(复杂指令集):一条指令完成一个复杂的基本功能。--一条指令可以由一个专门的电路来完成

代表:X86架构,主要用于笔记本,台式机

80-20规律:典型程序中80%的语句仅仅使用处理机中20%的指令

有的复杂指令用纯硬件实现很困难——>采用“存储程序”的设计思想,由一个比较通用的电路配合存储部件完成一条指令

RISC(精简指令集):一条指令完成一个基本动作;多条指令组合完成一个复杂的基本功能

代表:ARM架构,主要用于手机、平板等