指令系统
考纲内容
- 指令的基本概念
- 指令格式
- 寻址方式
- 数据的对齐和大/小端存放方式
- CISC和RISC的基本概念
- 高级语言程序与机器级代码之间的对应
编译器、汇编器与链接器的基本概念;选择结构语句的机器级表示
循环结构语句的机器级表示;过程(函数)调用对应的机器级表示
指令系统是表征一台计算机性能的重要因素。应掌握各种寻址方式的特点及有效地址的计算,三种偏移寻址(相对寻址、基址寻址和变址寻址)的计算,CISC和RISC的区别
本章知识点既可能出选择题,有可能结合其他章节出有关指令的综合题。指令格式、机器指令、指令寻址方式与CPU指令执行过程部分紧密相关
思考以下问题:
1、什么是指令?什么是指令系统?为什么要引入指令系统?
2、一般来说指令分为哪些部分?每部分有什么用处?
3、对于一个指令系统来说,寻址方式多和少有什么影响?
指令系统
指令集体系结构
机器指令(指令)是指计算机执行某种操作的命令
一台计算机的**所有指令的集合
构成该机的指令系统**,也称指令集
指令系统是指令集系统结构(ISA)中最核心的部分
,ISA**完整定义了软件和硬件之间的接口
**
ISA主要包括:
- 指令格式,指令寻址方式,操作类型,以及每种操作对应的操作数的相应规定
- 操作数的类型,操作数寻址方式,以及是按大端方式还是小端方式存放
- 程序可访问的寄存器编号、个数和位数,存储空间的大小和编制方式
- 指令执行过程的控制方式等,包括程序计数器、条件码定义等
指令的基本格式
一条指令就是机器语言的一个语句,它是一组有意义的二进制代码
一条指令通常包括**操作码字段和地址码字段
**两部分:
- 操作码指出**
该指令应执行什么操作以及具有何种功能
**
操作码是**识别指令、了解指令功能及区分操作数地址内容等的关键信息
**
例如:指出是算数加运算还是算数减运算,是程序转移还是返回操作 - 地址码给出**
被操作的信息(指令或数据)的地址
**,包括参加运算的一个或多个操作数的地址、运算结果的保存地址、程序的转移地址、被调用子程序的入口地址等
指令字长是指**一条指令所包含的二进制代码的位数
,其取决于操作码的长度、地址码的长度和地址码的个数
**
指令字长与机器字长没有固定的关系。通常把指令长度等于机器字长的指令称为单字长指令,指令长度等于半个机器字长的指令称为半字长指令,指令长度等于两个机器字长的指令称为双字长指令
注:指令长度的不同会导致取指令时间开销的不同,单子长指令只需访存1次就能将指令完整取出;而双字长指令则需访存2次才能完整取数,耗费2个存取周期
在一个指令系统中:
- 若**
所有指令的长度都是相等的
,则称为定长指令字结构**。定字长指令的**执行速度快,控制简单
** - 若**
各种指令的长度随指令功能而异
,则称为变长指令字结构**
因为主存一般是按字节编址的,所以**指令字长通常为字节的整数倍
**
根据指令中操作数地址码的数目不同,可将指令分为以下几种格式:
- 零地址指令
只给出操作码OP,没有显式地址
。有两种可能:
- 不需要操作数的指令,如空操作指令、停机指令、关中断指令等
- 零地址的运算类指令仅用在堆栈计算机中。通常参与运算的两个操作数隐含地从栈顶和次栈顶弹出没送到运算器进行运算,运算结果再隐含地压入堆栈
- 一地址指令
有两种可能,要根据操作码的含义确定:
- 只有目的操作数的单操作数指令,按A1地址读取操作数,进行OP操作后,结果存回原地址
指令含义:OP(A1) -> A1
如操作码含义是加1、减1、求反、求补、位移等 - 隐含约定目的地址的双操作数指令,按指令地址A1可读取源操作数,指令可隐含约定另一个操作数有ACC(累加器)提供,运算结果也将存放再ACC中
指令含义:(ACC)OP(A1) -> ACC
若地址码字段均为主存地址,则完成一条一地址指令需要**3次存访
**(取地址1次,取操作数1次,存结果1次)
- 二地址指令
指令含义:(A1)OP(A2) -> A1
对于常用的算术和逻辑运算指令,往往要求使用两个操作数,需分别给出目的操作数和源操作数的地址,其中目的操作数地址还用于保存本次的运算结果
若地址码字段均为主存地址,则完成一条一地址指令需要**4次存访
**(取地址1次,取操作数2次,存结果1次)
- 三地址指令
指令含义:(A1)OP(A2) -> A3
若地址码字段均为主存地址,则完成一条一地址指令需要**4次存访
**(取地址1次,取操作数2次,存结果1次)
- 四地址指令
指令含义:(A1)OP(A2) -> A3, A4 = 下一条将要执行指令的地址
若地址码字段均为主存地址,则完成一条一地址指令需要**4次存访
**(取地址1次,取操作数2次,存结果1次)
定长操作码指令格式
定长操作码指令**在指令字的最高位部分分配固定的若干位(定长)表示操作码
**,一般n位操作码字段的指令系统最大能够表示 2n 条指令
定长操作码对于简化计算机硬件设计,提高指令译码和识别速度很有利
扩展操作码指令格式
为了**在指令字长有限的前提下仍保持比较丰富的指令种类
,可采取可变长度操作码,即全部指令的操作码字段的位数不固定,且分散地放在指令字的不同位置上
**
显然,这将增加指令译码和分析的难度,使控制器的设计复杂化
最常见的变长操作码方法是扩展操作码,它**使操作码的长度随地址码的减少而增加
**,不同地址数的指令可具有不同长度的操作码,从而在满足需要的前提下,有效地缩短指令字长
扩展操作码的安排方式如下所示:
在设计扩展操作码指令格式时,必须注意以下两点:
- 不允许短码是长码的前缀,即短操作码不能与长操作码的前面部分的代码相同各指令的操作码一定不能重复
- 通常情况下,
对使用频率较高的指令分配较短的操作码,对使用频率较低的指令分配较长的操作码
,从而**尽可能减少指令译码和分析的时间
**
指令的操作类型
设计指令系统时必须考虑应提供哪些操作类型,指令操作类型按功能可分为以下几种:
-
数据传送
寄存器之间的传送(MOV) 从内存单元读取数据到CPU寄存器(LOAD) 从CPU寄存器写数据到内存单元(STORE) 进栈操作(PUSH) 出栈操作(POP) 等
-
算术和逻辑运算
加(ADD) 减(SUB) 乘(MUL) 除(DIV) 加1(INC) 减1(DEC) 与(AND) 或(OR) 取反(NOT) 异或(XOR) 等
-
移位操作
**算术移位、逻辑移位、循环移位
**等 -
转移操作
无条件转移(JMP):在任何情况下都执行转移操作 条件转移(BRANCH):仅在特定条件满足时才执行转移操作,转移条件一般是某个标志位的值,或几个标志位的组合 调用(CALL) 执行调用指令时必须保存下一条指令的地址(返回地址),当子程序执行结束时,根据返回地址返回到主程序继续执行 而转移指令则不返回执行 返回(RET) 陷阱(TRAP) 等
-
输入输出操作
这类指令**用于完成CPU与外部设备交换数据或传送控制命令及状态信息
**
提醒:
1、指令集体系结构(ISA)是软件和硬件之间接口的一个完整定义,包含了基本数据类型、指令集、寄存器、寻址模式、存储体系、中断和异常处理及外部I/O
2、ISA规定了执行每条指令时所需要的操作码、操作数、寻址方式等信息,以及指令的功能和效果
3、控制信号是由控制单元根据ISA生成的,它属于微架构层面的实现细节,而不是ISA层面的抽象定义
4、程序计数器PC存放当前欲执行指令的地址,而指令的地址码字段则保存操作数地址
5、程序控制类指令用于改变程序执行的顺序,并使程序具有测试、分析、判断和循环执行能力
6、指令的地址个数与指令的长度是否固定没有必然联系,即使是单地址指令,也可能由于单地址的寻址方式不同而导致指令长度不同
7、两个CPU可以由不同的时钟,但指令集可以相同;加法器的进位方式设计电路设计,属于计算机的硬件部分,不由ISA规定
指令的寻址方式
寻址方式是指**寻找指令或操作数有效地址的方式
,即确定本条指令的数据地址及下一条待执行指令的地址的方法
**
寻址方式分为**指令寻址
和数据寻址
**两大类
指令寻址和数据寻址
指令寻址:寻找下一条将要执行的指令地址
数据寻址:寻找本条指令的数据地址
- 指令寻址
指令寻址方式有两种:
-
顺序寻址
通过程序计数器PC加1
(1条指令的长度),自动形成下一条指令的地址
注:PC自增的大小与编址方式、指令字长有关 现代计算机通常是按字节编址的,若指令字长为16位,则PC自增为(PC)+2;若指令字长为32位,则PC自增为(PC)+4
-
跳跃寻址
通过转移类指令实现
跳跃是指**由本条指令给出下条指令地址的计算方式
。是否跳跃可能受到状态寄存器的控制
跳跃的方式分为绝对转移**(地址码直接指出转移目标地址
)和相对转移(地址码指出转移目的地址相对于当前PC值的偏移量
)
由于**CPU总是根据PC的内容去主存取指令
的,因此转移指令执行的结果是修改PC值
**,下一条指令仍然通过PC给出
- 数据寻址
数据寻址是指**如何在指令中表示一个操作数的地址,或怎样计算出操作数的地址
**
数据寻址的方式较多,通常在指令字中设置一个**寻址特征字段
,用来指明属于哪种寻址方式
(其位数决定了寻址方式的种类
**)
指令中的**地址码字段并不代表操作数的真实地址
,这种地址称为形式地址(A)**
形式地址结合寻址方式
,可以计算出**操作数在存储器中的真实地址
,这种地址称为有效地址(EA)**
- 若为立即寻址,则**
形式地址的位数
决定了操作数的范围
** - 若为直接寻址,则**
形式地址的位数
决定了可寻址的范围
** - 若为寄存器寻址,则**
形式地址的位数
决定了通用寄存器的最大数量
** - 若为寄存器间接寻址,则**
寄存器的位数
决定了可寻址的范围
**
注:(A)表示地址位A的数值,A既可以是寄存器编号,又可以是内存地址
常见的数据寻址方式
隐含寻址
这种类型的指令**不明显地给出操作数的地址
,而是隐含操作数的地址
**
如:单地址的指令格式就隐含约定第二个操作数由累加器(ACC)提供,指令中只明显指出第一个操作数的地址
即,累加器(ACC)对单地址指令格式来说是隐含寻址
优点:有利于缩短指令字长
缺点:需增加存储操作数或隐含地址的硬件
立即(数)寻址
指令字中的地址字段
指出的不是操作数的地址,而是操作数本身
,也称立即数,采用补码表示
优点:指令在执行阶段不访存,指令执行速度最快
缺点:A的位数限制了立即数的范围
直接寻址
指令字中的形式地址A就是操作数的真实地址EA
,即**EA = A
**
优点:简单,不需要专门设计操作数的地址
,指令在执行阶段仅需访存一次
缺点:A的位数限制了该执行操作数的寻址范围
,操作数的地址不易修改
间接寻址
间接寻址是相对于直接寻址而言的,指令的地址字段
给出的不是操作数的真正地址,而是操作数有效地址所在主存单元的地址
,也就是**操作数地址的地址
,即EA = (A)
**
优点:可扩大寻址范围
(有效地址EA的卫视大于形式地址A的位数);便于编制程序
(用间接寻址可以方便地完成子程序返回)
缺点:指令在执行阶段要多次访存
(一次间接寻址需2次访存);由于**执行速度较慢
**,一般为了扩大寻址范围,通常采用寄存器间接寻址
寄存器寻址
与直接寻址的原理一样,只是把访问主存改为**访问寄存器
,指令的地址字段给出
的是操作数所在寄存器的编号
**,即 EA = Ri,其操作数在由 Ri 所指的寄存器内
优点:指令在**执行阶段不用访存,只访问寄存器,执行速度快
;寄存器数量远小于内存单元数,所以地址码位数较少,指令字长较短
**
缺点:寄存器价格昂贵,CPU的寄存器数量有限
寄存器间接寻址
综合了间接寻址和寄存器寻址各自的特点,指令字中的 Ri 所指寄存器给出的
不是一个操作数,而是操作数所在主存单元的地址
即EA = (Ri)
相比间接寻址,这种方式**即扩大了寻址范围,又减少了访存次数
,在执行阶段仅需访存1次
**
相比寄存器寻址,这种方式**在执行阶段需要访存获得操作数
**(操作数在主存中)
相对寻址
相对寻址是**把PC的内容加上指令格式中的形式地址A
而形成操作数的有效地址
**
即**EA = (PC) + A
。其中A是相对于当前PC值的偏移量
**,可正可负,补码表示。通常A的位数决定操作数的寻址范围
优点:操作数的地址
不是固定的,它随PC指的变化而变化
,且**与指令地址之间总是相差一个固定的偏移量
,因此便于程序浮动
;相对寻址广泛应用于转移指令
**
对于转移指令:JMP A
若指令的地址位X,且占2B,则在取出该指令后,PC的值会增加2,即(PC) = X + 2
这样在执行完该指令后,会自动跳转到X + 2 + A的地址继续执行
基址寻址
基址寻址是指**将基址寄存器(BR)的内容加上指令字中的形式地址A
而形成操作数的有效地址
**
即**EA = (BR) + A
**。其中基址寄存器既可采用专用寄存器,又可指定某个通用寄存器作为基址寄存器
基址寄存器是面向操作系统的
,其内容由操作系统或管理程序确定,主要用于解决程序逻辑空间与存储器物理空间的无关性
在程序执行过程中,基址寄存器的内容不变
(作为基地址),形式地址可变
(作为偏移量)
采用通用寄存器作为基址寄存器时,可由用户决定哪个寄存器作为基址寄存器,但其内容仍由操作系统确定
优点:可以扩大寻址范围
(基址寄存器的位数大于形式地址A的位数);用户不必考虑自己的程序存于主存的具体位置,因此**有利于多道程序设计
,并可用于编制浮动程序
**,但偏移量(形式地址A)的位数较短
变址寻址
变址寻址是指**将变址寄存器(IX)的内容加上指令字中的形式地址A
而形成操作数的有效地址
**
即**EA = (IX) + A
**。其中IX为编制寄存器(专用),也可用通用寄存器作为编制寄存器
变址寄存器时面向用户的
,在程序执行过程中,变址寄存器的内容可由用户改变
(作为偏移量),形式地址A不变
(作为基地址)
优点:可扩大寻址范围
(变址寄存器的位数大于形式地址A的位数);在数组处理过程中,可设定A为数组的首地址,不断改变变址寄存器IX的内容,便可很容易形成数组中任意一个数据的地址,特别**适合编制循环程序
。偏移量
(变址寄存器IX)的位数足以表示整个存储空间
**
变址寻址与基址寻址对比:
变址寻址与基址寻址的有效地址形成过程极为相似
从本质上讲
基址寻址面向系统,主要用于为多道程序或数据分配存储空间,因此基址寄存器的内容通常由操作系统或管理程序确定,在程序的执行过程中其值不可变,而指令字中的A是可变的
变址寻址立足于用户,主要用于处理数组问题,在变址寻址中,变址寄存器的内容由用户设定,在程序执行过程中其值可变,而指令字中的A是不可变的
相对寻址、基址寻址和变址寻址
三种寻址方式非常类似,都将某个寄存器的内容与一个形式地址相加而生成操作数的有效地址
,通常把这三种寻址方式称为偏移寻址
堆栈寻址
堆栈是存储器(或寄存器组)中一块特定的、按**后进先出(LIFO)原则
管理的存储区,该存储区中读/写单元的地址是用一个特定寄存器给出的,该寄存器称为堆栈指针(SP)**
堆栈可分为**硬堆栈和软堆栈
**两种
寄存器堆栈
也称硬堆栈,硬堆栈的成本较高,不适合做大容量的堆栈
从主存中划出一段区域来做堆栈
是最合算且最常用的方法,这种堆栈称为软堆栈
在采用堆栈结构的计算机中,大部分指令表面上都表现为无操作数指令的形式
因为**操作数地址都隐含使用了SP
。因此在读/写堆栈的前后都伴有自动完成对SP的加减操作
**
提醒:
1、采用不同寻址方式的目的是为了缩短指令字长,扩大寻址空间,提高编程的灵活性
2、采用不同寻址方式会提高了指令译码的复杂度
3、程序控制是靠转移指令而非寻址方式实现的
4、为了缩短指令中某个地址段的位数,有效的方法是采取寄存器寻址
5、简化地址结构的基本方法是尽量采用隐含寻址,因为隐含寻址不明显给出操作数地址,而在指令中隐含操作数的地址
6、进、出堆栈对栈顶指针的操作顺序是不同的,进栈时先压入数据,后修改指针,此时栈指针指向栈顶的空单元,所以出栈时先修改指针后弹出数据
7、相对寻址方式中,指令所提供的相对地址实质上是一种以下一条指令在内存中首地址为基准位置的偏移量
8、程序计数器的位数取决于存储器的字数;指令寄存器的位数取决于指令字长
9、采用大端方式,基址寻址,按照有效地址的首地址开始存放机器数字节,大端方式顺序存放,从而可以获取到每一个具体的操作数字节所在地址
程序的机器级代码表示
这部分内容考过几次大题,且都比较难
都和汇编指令息息相关,建议都去学一下汇编指令,前提是你想得高分:传送门1、传送门2
想了解一下的看下面的就足够了
常用汇编指令介绍
- 相关寄存器
以x86处理器为例:x86处理器中由8个32位的通用寄存器,各寄存器及说明如下:
为了向后兼容,EAX、EBX、ECX、EDX的高两位字节和低两位字节可以独立使用
如:EAX的低两位字节称为AX,而AX的高低字节又可分别作为两个8位寄存器,分别为AH和AL
除EBP和ESP外(与堆栈的使用有关),其他几个寄存器的用法是比较灵活的
- 汇编指令格式
汇编格式一般有两种,AT&T格式和Intel格式。由于考试只考察Intel格式,所以这里也只介绍Intel格式:
- Intel格式的指令**
对大小写不敏感
** - Intel格式中,
第一个为目的操作数,第二个为源操作数,方向从右到左
- Intel格式中,寄存器和立即数都**
不需要加前缀
** - 在内存寻址方面,Intel格式使用
[
和]
- Intel格式在操作码后面**
显式的注明
**byte(字节)
、word ptr(字)
、dword ptr(双字)
如上所示为Intel格式的几条不同指令
其中,mov指令用于在内存和寄存器之间或者寄存器之间移动数据;lea指令用于将一个内存地址(而不是其所指的内容)加载到目的寄存器
- 常用指令
汇编指令通常可分为**数据传送指令
、算术和逻辑运算指令
和控制流指令
**
以下用于操作数的标记,分别表示**寄存器
、内存
和常数
**
1、< reg >:表示任意寄存器,若其后带有数字,则指定其位数,如< reg32 >表示32位寄存器(eax、ebx、ecx、edx、esi、edi、esp、ebp
);< reg16 >表示16位寄存器(ax、bx、cx、dx
);< reg8 >表示8位寄存器(ah、al、bh、bl、ch、cl、dh、dl
)
2、< mem >:表示内存地址(如[eax]
、[var + 4]
或dword ptr [eax + ebx]
)
3、< con >:表示8位、16位、32位常数,表示方式和< reg >类似
x86中的机器码长度位1字节,对同一指令的不同用途有多种编码方式
mov ax, <con16> #机器码为B8H
mov al, <con8> #机器码为B0H
mov <reg16>, <reg16>/<mem16> #机器码为89H
mov <reg8>/<mem8>,<reg8> #机器码为8AH
mov <regl6>/<mem16>,<regl6> #机器码为8BH
1、数据传送指令
-
mov指令:
将第二个操作数
(寄存器的内容、内存中的内容或常数值)复制到第一个操作数
(寄存器或内存)mov <req>, <reg> mov <reg>, <mem> mov <mem>, <reg> mov <reg>, <con> mov <mem>, <con> 如: mov eax, ebx # 将ebx值复制到eax mov byte ptr[var], 5 # 将5保存到var值指示的内存地址的一字节中
双操作数指令的两个操作数不能都是内存
,即**mov指令不能用于直接从内存复制到内存
**,若需要在内存之间复制,可先从内存复制到一个寄存器,再从这个寄存器复制到内存 -
push指令:
将操作数压入内存的栈
,常用于函数调用
ESP是栈顶,入栈前先将ESP值减4(栈增长方向与内存地址增长方向相反),然后将操作数压入ESP指示的地址(先减后入栈
)push <reg32> push <mem> push <con32> 如: push eax # 将eax值入栈 push [var] # 将var值指示的内存地址的4字节入栈
-
pop指令:与push指令相反,pop指令执行的是**
出栈工作
**
出栈前先将ESP指示的地址中的内容出栈,然后将ESP值加4(先出栈后减
)如: pop eax # 弹出栈顶元素送到eax pop [ebx] # 弹出栈顶元素送到ebx值指示的内存地址的4字节中
2、算术和逻辑运算指令
-
add/sub指令:
add指令将两个操作数相加
,相加的**结果保存到第一个操作数中
**
sub指令用于两个操作数相减
,相减的**结果保存到第一个操作数中
**add <reg>, <reg> / sub <reg>, <reg> add <reg>, <mem> / sub <reg>, <mem> add <mem>, <reg> / sub <mem>, <reg> add <reg>, <con> / sub <reg>, <con> add <mem>, <con> / sub <mem>, <con> 如: sub eax, 10 # eax <- eax - 10 add byte ptr [var], 10 # 10与var值指示的内存地址的一字节值相加,并将结果保存在var值指示的内存地址的字节中
-
inc/dec指令
inc、dec指令
分别表示将操作数自加1、自减1
inc <reg> / dec <reg> inc <mem> / dec <mem> 如: dec eax # eax值自减1 inc dword ptr [var] # var值指示的内存地址的4字节值自加1
-
imul指令
有符号整数乘法指令
,有两种格式:
两个操作数
,将两个操作数相乘,将**结果保存在第一个操作数
中,第一个操作数必须为寄存器
**
三个操作数
,将**第二个和第三个操作数相乘
,将结果保存在第一个操作数
中,第一个操作数必须为寄存器
**imul <reg32>, <reg32> imul <reg32>, <mem> imul <reg32>, <reg32>, <con> imul <reg32>, <mem>, <con> 如: imul eax, [var] # eax <-eax * [var] imul esi, edi, 25 # esi <- edi * 25
乘法操作**
可能溢出
,则编译器置溢出标志OF=1
,以使CPU调出异常处理程序
** -
idiv指令
有符号整数除法指令
,只有一个操作数
,即除数,被除数则为**edx:eax
中的内容
操作结果有两部分:商和余数,商送到eax,余数送到edx
**idiv <reg32> idiv <mem> 如: idiv ebx idiv dword ptr [var]
-
and/or/xor指令
and、or、xor
指令分别是逻辑与、逻辑或、逻辑异或
操作指令,用于操作数的位操作
,操作**结果放在第一个操作数中
**and <reg>, <reg> / or <reg>, <reg> / xor <reg>, <reg> and <reg>, <mem> / or <reg>, <mem> / xor <reg>, <mem> and <mem>, <reg> / or <mem>, <reg> / xor <mem>, <reg> and <reg>, <con> / or <reg>, <con> / xor <reg>, <con> and <mem>, <con> / or <mem>, <con> / xor <mem>, <con> 如: and eax, 0fH # 将eax中的前28位全部置0,最后4位保持不变 xor edx, edx # 置edx中的内容位0
-
not指令
位翻转指令
,将操作数中的每一位翻转not <reg> not <mem>
-
neg指令
取负指令
neg <reg> neg <mem>
-
shl/shr指令
逻辑位移指令,shl为逻辑左移,shr为逻辑右移,第一个操作数表示被操作数,第二个操作数指示位移的位数shl <reg>, <con8> / shr <reg>, <con8> shl <mem>, <con8> / shr <mem>, <con8> shl <reg>, <cl> / shr <reg>, <cl> shl <mem>, <cl> / shr <mem>, <cl> 如: shl eax, 1 # 将eax值左移1位 shr ebx, cl # 将ebx值右移n位(n为cl中的值)
3、控制流指令
x86处理器维持着一个**指示当前执行指令的指令指针(IP)
,当一条指令执行后,此指针自动指向下一条指令
**
IP寄存器不能直接操作,但可以用控制流指令更新
通常用标签(label)指示程序中的指令地址,在x86汇编代码中,可在任意指令前加入标签
mov esi, [ebp+8]
begin: xor ecx, ecx
mov eax, [esi]
这里begin指示了第二条指令,控制流指令通过标签就可以实现程序指令的跳转
-
jmp指令
jmp指令**控制IP转移到label所指示的地址
**(从label中取出指令执行)jmp <label> 如: jmp begin # 跳转到begin标记的指令执行
-
jcondition指令
条件转移指令
,依据CPU状态字中的一系列条件状态转移
CPU状态字中包括指示最后一个算数运算结果是否为0,运算结果是否为负数等je <label> # 相等转移 jz <label> # 结果为0转移 jne <label> # 不等转移 jg <label> # 大于转移 jge <label> # 大于或等于转移 jl <label> # 小于转移 jle <label> # 小于等于转移 如: cmp eax, ebx jle done # 若eax值<=ebx值,则跳转到done执行,否则执行下一条指令
-
cmp/test指令
cmp指令
的功能相当于sub指令
,用于**比较两个操作数的值
**
test指令
的功能相当于and指令
,对两个操作数进行逐位与运算
与sub和and指令不同的是,这**两类指令都不保存操作结果
,仅根据运算结果设置CPU状态字中的条件码
**cmp <reg>, <reg> / test <reg>, <reg> cmp <reg>, <mem> / test <reg>, <mem> cmp <mem>, <reg> / test <mem>, <reg> cmp <reg>, <con> / test <reg>, <con> cmp和test指令通常和jcondition指令搭配使用 如: cmp dword ptr [var], 10 # 将vat指示的主存地址的4字节内容,与10比较 jne loop # 若相等则继续顺序执行;否则跳转到loop处执行 test eax, eax # 测试eax是否为0 jz xxxx # 为0则设置标志ZF为1,跳转到xxxx处执行
-
call/ret指令
call指令
用于实现子程序(过程、函数等)的调用
ret指令
用于实现子程序(过程、函数等)的返回
call <label> ret
call指令**
保存调用之前的地址信息
(当call指令结束后,返回调用之前的地址),call指令首先将当前执行指令地址入栈
,然后无条件转移到由标签指示的指令
**
ret指令**实现子程序的返回机制
,ret指令弹出栈中保存的指令地址
,然后无条件转移到保存的指令地址执行
**
call和ret是程序(函数)调用中最关键的两条指令
注意:
1、寄存器EAX、ECX、EDX是调用者保存寄存器,当P调用Q时,若Q需要用到这些寄存器,则由P将这些寄存器的内容保存到栈中,并在返回后由P恢复它们的值
2、寄存器EBX、ESI、EDI时被调用者保存寄存器,当P调用Q时,Q必须先将这些寄存器的内容保存在栈中才能使用他们,并在返回P之间先恢复它们的值
3、每个过程都有自己的栈区,称为栈帧,因此,一个栈由若干栈帧组成,寄存器EBP指示栈帧的起始位置。寄存器ESP指示栈顶,栈从高地址向低地址增长。执行过程时,ESP会随着数据的入栈而动态变化,而EBP固定不变
4、无论是无符号数还是有符号数,都以二进制代码形式无差别的存放在计算机内,即使两个有符号数相加,也会导致CF的变动,指示CF值对有符号数运算时没有意义的;同理,两个无符号数相加,也会导致OF和SF的变动,只是OF值和SF值仅对有符号数运算有意义
5、循环体最后会有一条条件转移指令,判断是否跳出循环
6、假设P为调用过程,Q为被调用过程,则所设计的操作为:
过程P将实参存放到Q能访问的地方
过程P将返回地址存放到特定处,并跳转到Q执行
过程Q保存P现场,并为静态局部变量分配空间
执行Q的函数体
过程Q恢复P的现场,并释放局部变量所栈空间
过程Q取出返回地址,并跳转回到过程P执行
CISC和RISC的基本概念
指令系统有大致有两种方向:
- 复杂指令系统计算机(CISC):
增强了原有指令的功能,设置更为复杂的新指令实现软件的硬化
如x86架构的计算机 - 精简指令系统计算机(RISC):
减少指令种类和简化指令功能,提高指令的执行速度
如ARM、MIPS架构的计算机
复杂指令系统计算机(CISC)
特点:
指令系统复杂庞大
,指令数目一般为200条以上- 指令的**
长度不固定
,指令格式多
,寻址方式多
** 可以访存的指令不受限制
- 各种指令**
使用频度相差很大
** - 各种指令**
执行时间相差很大
**,大多数指令需多个时钟周期才能完成 - 控制器大多数**
采用微程序控制
**。有些指令非常复杂,以至于无法采用硬连线控制 难以用优化编译生成高效的目标代码程序
精简指令系统计算机(RISC)
特点:
选取使用频率最高的一些简单指令
,复杂指令的功能由简单指令的组合来实现
指令长度固定
,指令格式种类少
,寻址方式种类少
- 只有
LOAD/STORE(取数/存数)
指令**访存
,其余指令的操作都在寄存器之间进行
** - CPU中**
通用寄存器的数量相当多
** - 一定**
采用指令流水线技术
,大部分指令在一个时钟周期内完成
** - **
以硬布线控制为主
,**不用或少用微程序控制 特别重视编译优化工作,以减少程序执行时间
CISC和RISC的比较
和CISC相比,RISC的优点主要体现在以下几点:
-
RISC更能充分利用VLSI(超大规模集成电路)芯片的面积
CISC采用微程序控制,其控制存储器占CPU芯片面积的50%以上,而RISC采用组合逻辑控制,其硬布线逻辑只占CPU芯片面积的10%左右 -
RISC更能提高运算速度
RISC的指令数、寻址方式和指令格式种类少,又设有多个通用寄存器,采用流水线技术,所以运算速度更快,大多数指令在一个时钟周期内完成 -
RISC便于设计,可降低成本,提高可靠性
RISC指令系统简单,因此机器设计周期短;其逻辑简单,出错概率低,有错也易发现,因此可靠性高
-
RISC有利于编译程序代码优化
RISC指令类型少,寻址方式少,使编译程序容易选择更有效的指令和寻址方式,并适当地调整指令顺序,使得代码执行更高效化
本章小结
什么时指令?什么时指令系统?为什么要引入指令系统
指令:要计算机执行某种操作的命令
指令系统:一台计算机中所有机器指令的集合
引入指令系统后,避免了用户与二进制代码直接接触,使得用户编写程序更为方便
另外,指令系统时表征一台计算机性能的重要因素,它的格式与功能不仅直接影响到机器的硬件结构,而且也直接影响到系统软件,影响到机器的使用范围
一般来说指令分为哪些部分?每部分有什么用处?
一条指令通常包括操作码字段和地址码字段两部分
操作码指出指令中该指令一共执行什么性质的操作和具有何种功能
它是识别指令、了解指令功能与区分操作数地址内容的组成和使用方法等的关键信息
地址码用于给出被操作的信息(指令或数据)的地址
包括参加运算的一个或多个操作数所在的地址、运算结果的保存地址、程序的转移地址、被调用子程序的入口地址等
各常见指令寻址方式的特点和适用情况
立即寻址操作数获取便捷,通常用于给寄存器赋初值
直接寻址相对于立即寻址,缩短了指令长度
间接寻址扩大了寻址范围,便于编址程序,易于完成子程序返回
寄存器寻址的指令字较短,指令执行速度较快
寄存器间接寻址扩大了寻址范围
基址寻址扩大了操作数寻址范围,适用于躲到程序设计,常用于为程序或数据分配存储空间
变址寻址主要用于处理数组问题,适合编制循环程序
相对寻址用于控制程序的执行顺序、转移等
基址寻址和变址寻址的区别:
两种方式有效地址的形成都是 寄存器内容 + 偏移地址
在基址寻址中,程序员操作的时偏移地址,基址寄存器的内容有操作系统控制,在执行过程中时动态调节的
在编制寻址中,程序员操作的时变址寄存器,偏移地址时固定不变的
装入/存储(LOAD/STORE)型指令有什么特点
这种指令在RISC指令系统中较为常见
为了规整指令格式,使指令具有相同的长度,规定只有LOAD/STORE指令才能访问内存
运算指令不能直接访问内存,只能从寄存器取数进行运算,运算的结果也只能送到寄存器