汇编语言指令集
1.1 概述
1.1.1 指令集体系结构、机器指令和符号指令
计算机技术中,指令是指在某种计算机结构中定义的单个CPU操作,每条指令执行某一个特定的操作,如将两数字求和返回。在该种计算机结构中,CPU所支持的所有指令构成的集合称为指令集。
将指令编码成为二进制格式的序列,称为机器指令。通常CPU只能识别和执行机器指令。而由于在不同计算机中,CPU设计不相同,从而使得相同的代码被编码成不同的机器指令。人们将指令集和指令集编码(即指令集对应的机器指令集)称为CPU的指令集体系结构。
常见的指令集体系结构包括精简指令集计算机(Reduced Instruction Set Computing ,RISC)和复杂指令集计算机(Complex Instruction Set Computing ,CISC)。RISC体系中常见的是IBM公司的Powerpc、Oracle公司的SPARC、ARM公司的ARM等,对应的主要操作系统是Unix以及iOS、Android等移动操作系统。CISC体系中常见的CPU是80x86架构,如Intel公司的Pentium等,AMD公司的Athlon等,对应的主要操作系统是Microsoft windows以及Linux。
早期计算机程序大都直接使用机器指令,后由于其繁琐、易错、可读性较差等诸多弊端,目前在编写汇编语言程序时一般采用统一定义的一套特定助记符和书写格式,把指令表示成字符串形式的序列,也即符号指令。
在指令集体系结构中,每条指令都有其对应的机器指令和符号指令,例如
将指定数值移入特定寄存器:
指令: 1234H -->AX
机器指令: 101110000011010000010010
符号指令: MOV AX,1234H
或将两寄存器中的内容求和,结果返回其中某寄存器:
指令: AX+BX-->AX
机器指令: 0000001111000011
符号指令: ADD AX,BX
1.1.2 符号指令的书写格式
以80x86指令集为例,符号指令书写格式如下:
标号: + 操作码助记符 + 空格+操作数助记符(多操作数之间以“,”隔开) + ;注释
格式说明如下:
(1) 符号指令的核心部分是操作码和操作数。操作码表示指令的功能,操作数即指令的操作对象,分别采用操作码助记符和操作数助记符表示,操作码和操作数之间采用空格符或Tab符隔开。
(2) 依据操作数数量分为单操作数指令和多操作数指令;有两个操作数时,位于“,”左侧的为目标操作数,右侧的为源操作数;多字节操作数在存储器中的存放顺序依据最小端规则,即低位字节存放在低地址单元,高位字节存放在高地址单元(很重要!)。
(3) 标号表示该条指令地质的符号地址。当该条指令作为分支或循环等指令的转移目标或作为程序开始执行的首条语句时,需设置标号,其余情况可忽略。标号和操作码助记符之间需以“:”隔开。
(4) 注释为程序设计过程中对特定信息的解释说明,可忽略。
(5) 一条符号指令对应的机器指令一般由若干字节构成,在存储器中连续存放。指令在存储器中占用的字节数称为指令长度,依其可划分为单字节指令和多字节指令,其中,第一字节所在存储器单元的地址称为指令地址。例如,符号指令“ADD AX,BX”对应的机器指令为0000001111000011,在存储器中占用2B,其指令长度为2B,若首字节单元在存储器的物理地址为12345H,则该指令的物理地址为12345H。
1.2 操作数
1.2.1 通用寄存器中的操作数
指令的操作数存放在寄存器中时称为寄存器操作数。寄存器操作数的字长由寄存器名称决定。如寄存器EAX,其长度为32位,可存储32位字长操作数;当使用AX作为寄存器名称时,只能使用32位寄存器的低16位部分,此时AX是一个16位寄存器,可存储16位字长操作数;类似的,当使用AH作为寄存器名称,只能使用AX的高8位,此时AH是一个8位寄存器;使用AL作为寄存器名称,只能使用AX的低8位,此时AL是一个8位寄存器,AH和AL都可以存储8位字长操作数。
EBX、ECX、EDX的寄存器名称和操作数字长的对应方法与EAX一致,而ESP、EBP、EDI、ESI4个寄存器逻辑结构只有32位和16位字长两种,对应的16位寄存器名称分别为SP、BP、DI、SI。
1.2.2 段寄存器和指令指针寄存器
32位微处理器中共有6个16位段寄存器和1个32位指令指针寄存器。代码段寄存器CS以及指令指针寄存器IP分别存放CPU将要取出的指令的段基址和偏移地址。
1.2.3 标志寄存器
指令的操作对象除了数据外还包括状态。多数情况下,实验标志寄存器中的某些标志位来存储状态。标志位分为;两类:状态标志和控制标志。状态标志用于某些指令操作的前提状态以及指令操作的完成后的结果状态。控制标志可以设定CPU的某些功能,例如中断;或者设定指令的操作功能,例如串操作指令。控制标志值可通过相应指令进行设定。
标志寄存器中的各个标志位都有确定功能,对应如下(前6位为状态标志,其余为控制标志):
1. C标志(进位/借位标志)
2. A标志 (辅助进位/借位标志)
3. S标志(符号标志)
4. Z标志(全零标志)
5. P标志(奇偶标志)
6. O标志(溢出标志)
7. D标志(方向标志)
8. I标志(中断允许标志)
9. T标志(陷阱标志)
10. IOPL标志(I/O特权级标志)
11. NT标志(任务嵌套标志)
12. R标志(恢复标志)
13. VM标志(虚拟标志)
14. AC标志(对准检查标志)
1.3 寻址方式
指令操作数一共有4种存放位置:
(1)操作数作为本条指令的一部分,直接包含在指令中,这种操作数称为立即数。
(2)操作数存放在CPU的11寄存器中,这种操作数称为寄存器操作数。
(3)操作数存放在计算机的存储器中,这种操作数称为存储器操作数或内存操作数。
(4)操作数存放在计算机接口电路的端口中,这种操作数称为I/O端口操作数。
寻址方式就是在指令中,使用特定的助记符或助记符表达式(地址表达式),告知CPU如何计算出操作数的地址,从而正确地存取操作数,以便进行后续的指令操作。一般而言,寻址方式就是指CPU寻找到操作数的方式。对应操作数4种存放位置,有4类寻址方式,分别为:立即寻址、寄存器寻址、存储器操作数寻址、I/O端口操作数寻址。在80486处理器中,仅包含前3类寻址方式,因此只对前3种进行介绍。
1.3.1 立即寻址
立即寻址: 操作数包含在指令中,是指令的一个组成部分,CPU读入该条指令后同时取得了操作数。采用立即寻址方式获得的操作数称为立即数。
使用示例:
MOV AL,10101111B ;指令执行后(AL)=AFH
MOV BX,1234H ;指令执行后(BX)=1234H
MOV CX,0A234H ;指令执行后(CX)=A234H
MOV AH,-2 ;指令执行后(AH)=FEH
MOV BL,'A' ;指令执行后(BL)=41H,指令等同于MOV BL,41H
MOV AX,11*12 ;指令执行后(AX)=0084H,指令等同于MOV AX,132
注意事项:
(1)立即寻址方式常用于为寄存器或内存操作数赋值,并且只能用于源操作数,不可用于目标操作数。
(2)汇编程序在进行汇编时,会将不同进制的立即数一律汇编为等值的二进制数,负数则用其补码形式表示。
1.3.2 寄存器寻址
寄存器寻址: 将操作数存放在寄存器中,寄存器的名称在指令中的操作数中给出。在寄存器中存取操作数,可以获得较快的访问速度。
使用示例:
MOV EAX,12345678H ;指令执行后(EAX)=12345678H,目标操作数采用寄存器寻址,源操作数采用立即寻址
ADD CH,CL ;将CH和CL中的数相加的结果存入CH,两操作数均采用寄存器寻址
INC SI ;将SI中的数加1,操作数采用寄存器寻址
1.3.3存储器操作数寻址
存储器操作数寻址: 也被称为内存操作数寻址,操作数存放在存储器中。
由于程序被装载入存储器中的位置由操作系统在程序载入时决定,在编写程序时无法确定指令中使用的存储单元在程序载入存储器后的物理地址,只能使用逻辑地址来描述指令中用到的存储单元,CPU在分析指令时使用内部的段页式管理部件将指令中的逻辑地址转化为对应的物理地址,再通过总线系统访问实际的物理存储单元。那么根据不同应用场景下,逻辑地址中偏移地址表达式的不同格式,共有5种存储器操作数寻址方式:直接寻址、寄存器间接寻址、基址寻址、变址寻址、基址加变址寻址。
1.3.3.1 直接寻址
直接寻址方式的操作数的逻辑地址有两种书写格式:
1)段寄存器名称:[偏移地址]
使用示例:
ADD AL,DS:[45H] ;取出数据段中偏移地址为0045H的存储单元中的数据与AL中数相加,结果存入AL
MOV AX,ES:[1000H] ;取出数据段中偏移地址为1000H的存储单元中的数据送入AX
2)段寄存器名称:变量名
使用示例:
MOV AX,DS:BUF ;将数据段中名为BUF的存储单元中的数据送入AX,也可写作 MOV AX,BUF
实际应用中,直接寻址适用于存取单个内存操作数。
1.3.3.2 寄存器间接寻址
寄存器间接寻址也称为间接寻址或间址,其逻辑地址书写格式为:
段寄存器名称:[间址寄存器]
偏移地址表达式给出的间址寄存器用于存放操作数的偏移地址。注:仅部分特定寄存器可作为间址寄存器使用,如下:
使用示例:
MOV BX,BUF单元的偏移地址
MOV AH,DS:[BX] ;用BX取出数据段中BUF单元的操作数,将其送入AH
实际应用中,寄存器间接寻址适合用于存取按一定规律连续存放在存储器中的多个数据,如数据表格或数组。在间址寄存器中预先存放初始的存储单元的偏移地址,在存取数据过程中按照一定规律对间址寄存器中的偏移地址进行增量或减量运算,从而实现对多个数据的访问。
1.3.3.3 基址寻址
基址寻址的逻辑地址书写格式为:
段寄存器名称:[基址寄存器+位移量] 或 段寄存器名称:位移量[基址寄存器]
偏移地址表达式由基址寄存器和位移量的和构成。注:仅部分特定寄存器可作为基址寄存器使用,如下:
使用示例:
MOV BX,BUF单元的偏移地址
MOV AH,DS:[BX+3] ;基址寻址取出数据段BUF+3单元的操作数送入AH
实际应用中,基址寻址也适合用于存取按一定规律连续存放在存储器中的多个数据,但由于增加了位移量参数,可以指定在数据表中访问的起始点,使用更加灵活。
1.3.3.4 变址寻址
变址寻址方式的逻辑地址书写格式有两种:
1)有比例因子的变址寻址,逻辑地址书写格式为:
段寄存器名称:[比例因子*变址寄存器+位移量] 或 段寄存器名称:位移量[比例因子*变址寄存器]
偏移地址表达式由“比例因子*变址寄存器+位移量”构成。注:仅部分特定寄存器可作为变址寄存器使用,如下:
MOV EBX,BUF的单元偏移地址
MOV AH,DS:[4*EBX+3] ;变址寻址取出数据段4*EBX+3单元中的操作数送入AH
2)无比例因子的变址寻址,其逻辑地址书写格式为:
段寄存器名称:[变址寄存器+位移量] 或 段寄存器名称:位移量[变址寄存器]
在无比例因子的情形下,能够作为变址寄存器使用的通用寄存器如下:
使用示例:
MOV SI,BUF单元的偏移地址
MOV AH,SS:[SI+3] ;变址寻址取出堆栈段BUF+3单元中的操作数送入AH
实际应用中,变址寻址也适合用于存取按一定规律连续存放在存储器中的多个数据,特别是带比例因子的寻址方式,可以在存取数据时跨越比较大的地址范围。
1.3.3.5 基址加变址寻址
基址加变址寻址方式是基址寻址和变址寻址方式的结合,根据是否带有比例因子,基址加变址寻址方式的逻辑地址也有两种书写格式:
1)有比例因子的基址加变址寻址,逻辑地址书写格式为:
段寄存器名称:[基址寄存器+比例因子*变址寄存器+位移量] 或 段寄存器名称:位移量[基址寄存器] [比例因子*变址寄存器]
2)无比例因子的基址加变址寻址方式,逻辑地址书写格式为:
段寄存器名称:[基址寄存器+变址寄存器+位移量] 或 段寄存器名称:位移量[基址寄存器][变址寄存器]
实际应用中,基址加变址寻址方式由于有基地址和变址地址两个参数,特别适合表示二维下标,对二维数组进行访问。使用了位移量的基址加变址寻址方式,常用于对结构体数据进行访问,此时用基地址定位结构体,用位移量定位结构体中的数据项,用变址地址定位数据项中的每个元素。
1.3.4 寻址方式小结
(1)寻址方式是 CPU 在执行指令时正确地找到操作数的方式。特别注意:寻址方式是针对指令中的操作数,并非针对指令,当指令有多个操作数时,各个操作数可能对应不同的寻址方式。例如:
MOV AX,1234H ;源操作数1234H是立即寻址方式,位于 AX 中的目标操作数是寄存器寻址方式
(2)操作数在指令中时是立即寻址方式。立即寻址方式只能用于源操作数,常用于给目标寄存器或存储器单元赋值。
(3)操作数在寄存器中时是寄存器寻址方式。对比存储器操作数寻址,寄存器寻址方式能够得到较快的数据存取速度。
(4)操作数在存储器单元中时是存储器操作数寻址方式。存储器操作数寻址方式在使用时需要注意两个问题:
①逻辑地址表达式在约定访问逻辑段时出现的可以省略不写段寄存器名称的现象也称为段超越前缀省略。当地址表达式使用的寄存器符合段超越前缀省略的条件时,段寄存器名称可以写出,也可以不写出,但不写出是默认的汇编源程序的书写风格,可以让程序代码简洁。但同时需要注意:在不满足段超越前缀省略的条件时,省略不写段寄存器会使指令出错。
②5种不同的存储器操作数寻址方式有各自的特点和应用场景:直接寻址方式用于访问单个内存操作数;寄仔器间接寻址、基址寻址和变址寻址用于访问具有连续排列规律的多个内存操作数;基址加变址寻址多用于访问二维数据或数据结构体。实际编程甲应该根据程序中的效据结构的特点正确选择相应的寻址方式。
1.4 汇编语言语法
1.4.1 汇编语言语句类型和格式
1.4.2 名字项
1.4.3 操作数项
1.4.4 操作项
1.5 汇编语言基本指令集
1.5.1 传送类指令
1.5.1.1 通用传送指令
1)数据传送指令 MOV
格式:MOV 目标操作数,源操作数
功能:将源操作数送到目标操作数中。源操作数不变。
2)符号扩展传送指令 MOVSX
格式:MOVSX 目标操作数,源操作数
功能:将源操作数向高位扩展,符号位填补,使其与目标操作数字长一致后再传送到目标操作数,源操作数不变。
3)偏移地址传送指令 LEA
格式:LEA 目标操作数,源操作数
功能:将源操作数的偏移地址传送到目标操作数
4)交换指令 XCHG
格式:XCHG 目标操作数,源操作数
功能:完成源操作数和目标操作数之间的数据交换。
5)查表指令 XLAT
格式:XLAT 操作数(字节表的表头变量名)
功能:在数据段中定义一个由若干单字节数构成字节型变量称为字节表,其第一个字节单元的变量名称为标头变量名。
1.5.1.2 堆栈操作指令
1)通用进/出栈指令 PUSH/POP
格式:PUSH/POP 源操作数/目标操作数
功能:将源操作数压入栈/从堆栈中弹出一个字或双字,将其送入目标操作数中。
2)16位标志寄存器进/出栈指令 PUSHF/POPF
格式:PUSHF/POPF
(注:PUSHF和POPF指令的操作数未显式写出,即16位的标志寄存器)
功能:16位标志寄存器与堆栈的进出及相关操作,多用于保护现场和恢复现场。
3)32位标志寄存器进/出栈指令 PUSHFD/POPFD
格式:PUSHFD/POPFD
功能:类似于“PUSHF/POPF“。”
4)16位通用寄存器进/出栈指令 PUSHA/POPA
格式:PUSHA/POPA
功能:隐式操作数,即AX、BX等16位通用寄存器与堆栈相关操作。
5)32位通用寄存器进/出栈指令 PUSHAD/POPAD
格式:PISHAD/POPAD
功能:隐式操作数,即EAX、EBX等32位通用寄存器与堆栈相关操作。
1.5.2 算术运算指令
1.5.2.1 基本四则运算
1)二进制加法指令 ADD
格式:ADD 目标操作数,源操作数
功能:将源操作数和目标操作数求相加,结果送入目标操作数。
2)二进制带进位加法指令 ADC
格式:ADC 目标操作数,源操作数
功能:将源操作数和目标操作数以及当前的C标志的值相加,结果送入目标操作数。
3)二进制数加1指令 INC
格式:INC 目标操作数
功能:目标操作数加1后送入目标操作数。
4)二进制数减法指令 SUB
格式:SUB 目标操作数,源操作数
功能:目标操作数减去源操作数,结果送入目标操作数。
5)二进制数带借位减法指令 SBB
格式:SBB 目标操作数,源操作数
功能:目标操作数减去源操作数,再减去当前C标志的值,结果送入目标操作数。
6)二进制数减1指令 DEC
格式:DEC 目标操作数
功能:目标操作数减1后结果送入目标操作数。
7)二进制数求补指令 NEG
格式:NEG 目标操作数
功能:目标操作数求补(即用零减去目标操作数)后结果送入目标操作数。
8)无符号二进制数乘法指令 MUL
格式:MUL 乘数
功能:将同为无符号数并且字长相等的被乘数与乘数相乘,乘积送入指定寄存器。
9)有符号二进制数乘法指令 IMUL
格式:IMUL 乘数
功能:将同为有符号数并且字长相等的被乘数与乘数相乘,乘积送入指定寄存器。
10)无符号二进制数除法指令 DIV
格式:DIV 除数
功能:将同为无符号数并且字长为除数双倍长度的被除数与除数相除,运算的道德商和余数送入指定寄存器。
11)有符号二进制数除法指令 IDIV
格式:IDIV 除数
功能:将同为有符号数并且字长为除数双倍长度的被除数与除数相除,运算的道德商和余数送入指定寄存器。
12)符号扩展指令 CBW/CWD
格式:CBW/CWD
功能:将字节转换为字/双字。
1.5.2.2 BCD码调整指令
(1)组合BCD码十进制数的算数运算调整指令
1)组合十进制数加法调整指令 DAA
格式:DAA
功能:对存放在AL中的由两个组合BCD码数相加得到的和进行修正,得到正确的结果。
2)组合十进制数减法调整指令 DAS
格式:DAS
功能:对存放在AL中的由两个组合BCD码数相减得到的差进行修正,得到正确的结果。
(2)未组合BCD码十进制数的算术运算调整指令
1)未组合十进制数加法调整指令 AAA
格式:AAA
功能:对存放在AL中的由两个未组合BCD码数相加得到的和进行修正,得到正确的未组合BCD码结果。
2)未组合十进制数减法调整指令 AAS
格式:AAS
功能:对存放在AL中的由两个未组合BCD码数相减得到的差进行修正,得到正确的未组合BCD码结果。
3)未组合十进制数乘法调整指令 AAM
格式:AAM
功能:对存放在AX中的由两个未组合BCD码数相乘得到的积进行修正,得到正确的未组合BCD码结果。
4)未组合十进制数除法调整指令 AAD
格式:AAD
功能:对存放在AX中的由两个未组合BCD码数转换为等值的二进制数存放在AL中,并将AH清零。
1.5.3 转移和调用指令
1.5.3.1 无条件转移指令
1)无条件段内直接转移 JMP
格式:JMP (标号/SHORT标号)
2)无条件段内间接转移 JMP
格式:JMP (寄存器操作数/内存操作数)
3)无条件段间直接转移 JMP
格式:JMP (FAR PTR 标号/标号)
4)无条件段间间接转移 JMP
格式:JMP 内存操作数
1.5.3.2 条件转移指令
条件转移指令格式统一:
条件转移指令助记符(JNC、JNZ、JNS等) 目标地址标号
功能:根据上一条指令设置的标志位情况转移。
循环控制转移指令:
1.5.3.3 子程序调用与返回指令
(1)子程序调用指令
1)段内直接调用指令 CALL
格式:CALL 过程名(子程序名)
2)段内直接调用 CALL
格式:CALL 寄存器操作数/内存操作数
3)段间直接调用指令 CALL
格式:CALL 过程名(子程序名)
4)段间间接调用指令 CALL
格式:CALL 内存操作数
(2)子程序返回指令
1)段内无参数返回指令 RET
格式:RET
2)段间无参数返回指令 RET
格式:RET
3)段内有参数返回指令 RET
格式:RET N(N为偶数)
4)段间有参数返回指令 RET
格式:RET N(N为偶数)
1.5.3.4 软件中断与中断返回指令
1)软件中断指令 INT
格式:INT n(n为8位无符号整数)
功能:调用n型中断服务子程序,其中n称为中断类型码。
2)中断返回指令 IRET
格式:IRET
功能:中断服务子程序中执行的最后一条指令。
1.5.4 逻辑运算和移位指令
(1)逻辑运算指令
1)取反运算指令 NOT
格式:NOT 目标操作数
功能:将目标操作数按位取反,结果送回目标操作数。
2)与运算指令 AND
格式:AND 目标操作数,源操作数
功能:将源、目标操作数进行按位逻辑“与”运算,结果送入目标操作数中。
3)或运算指令 OR
格式:OR 目标操作数
功能:将源、目标操作数进行按位逻辑“或”运算,结果送入目标操作数中。
4)异或运算指令 XOR
格式:XOR 目标操作数,源操作数
功能:将源、目标操作数进行按位逻辑“异或”运算,结果送入目标操作数中。
(2)移位指令
1)开环算术移位指令 SAL/SAR
格式:SAL/SAR( 操作数,移位次数)
功能:最高位重复,适用于计算有符号数乘除。
2)开环逻辑移位指令 SHL/SHR
格式:SHL/SHR (操作数、移位次数)
功能:最高位补零,适用于计算无符号数乘除。
3)不含进位闭环移位指令(也称为循环移位指令) ROL/ROR
格式:ROL/ROR (操作数、移位次数)
功能:移出位进入C标,不再加入循环。
4)含进位的闭环移位指令 RCL/RCR
格式:RCL/RCR (操作数、移位次数)
功能:移出位进入C标,继续补到下一轮末位,继续循环。
(3)测试与位测试指令
1)测试指令 TEST
格式:TEST 目标操作数,源操作数
功能:将目标操作数和源操作数进行按位“与”运算,结果不送入目标操作数中,目标操作数不变,并对相应状态标志位进行设定。
2)位测试指令 BT/BTR/BTS/BTC
格式:
BT 目标操作数,源操作数(注:位测试指令)
BTR 目标操作数,源操作数(注:位测试置0指令)
BTS 目标操作数,源操作数(注:位测试置1指令)
BTC 目标操作数,源操作数(注:位测试取反指令)
功能:将目标操作数中由源操作数指定的位(即测试位)的值送入C标志,源操作数不变。
(4)位扫描指令
1)向前位扫描指令 BSF
格式: BSF 目标操作数,源操作数
功能:从低位向高位(从右到左)扫描源操作数,将遇到的第1个1的位序号记录在目标操作数中。
2)向后位扫描指令 BSR
格式:BSR 目标操作数,源操作数
功能:从高位向低位(从左到右)扫描源操作数,将遇到的第1个1的位序号记录在目标操作数中。
(5)串操作指令
1.5.6 处理机控制指令
1.5.6.1 标志位控制指令
1)进位标志置0指令 CLC
格式:CLC
功能:0–>(C)。
2)进位标志置1指令 STC
格式:STC
功能:1–>(C)。
3)进位标志取反指令 CMC
格式:CMC
功能:/(C)–>(C)。
4)方向标志置0指令 CLD
格式:CLD
功能:0–>(D)。
5)方向标志置1指令 STD
格式:STD
功能:1–>(D)。
6)中断标志置0指令 CLI
格式:CLI
功能:0–>(I)。
7)中断标志置1指令 STI
格式:STI
功能:1–>(I)。
1.5.6.2 其他控制指令
1)空操作指令 NOP
格式:NOP
功能:执行时不进行任何操作,指令长度1字节。
2)停机操作指令 HLT
格式:HLT
功能:执行时使CPU处于暂时停机状态,但不进行任何操作,也不影响标志。
3)等待指令 WAIT
格式:WAIT
功能:执行时可以使CPU处于暂时停机状态,直到外部中断发生,但一旦外部中断结束仍然返回到暂时停机状态。
4)换码指令 ESC
格式:ESC 目标操作数
功能:将指定的内存单元中的内容发送到数据总线上(处理器交权)。
5)封锁指令 LOCK
格式:LOCK
功能:处理器封锁。
(未完,部分内容待续。)