汇编与技术接口——指令系统漫谈

文章根据北京理工大学李元章等老师所著《汇编语言与技术接口》所写,文章仅作为学习笔记使用,不得进行任何商业用途。转载请说明出处!!

  这篇文章讲解了汇编中常见的寄存器、CPU工作模式、内存管理。建议读本片文章之前,先花一点时间去阅读 “微处理器管理模式(上)”这篇文章,不然本篇文章出现得一些寄存器可能看不懂。下面是链接~
微处理器管理模式(上)

1.数据寻址方式

MOV 目标,源    ;把源操作数传给目标

 1.1 CPU操作数寻址

参与运算的操作数来自CPU内部,包括以下两种寻址方式:
(1)立即寻址方式
操作数直接包含在指令中,紧跟在操作码之后的寻址方式称为立即寻址方式,把该操作数称为立即数,也成为立即数寻址方式。

MOV BL,9    ;执行结果(BL)= 9

9是立即数,它的寻址方式是立即寻址方式。这种寻址方式只能出现在源操作数的位置。除立即寻址外,以下介绍的寻址方式既可以出现在源操作数也可以出现在目标操作数位置

(2)寄存器寻址方式
操作数直接包含在寄存器中,由指令指定寄存器的寻址方式
寄存器可以是通用寄存器,包括8位、16位、32位通用寄存器;也可以是段寄存器,但是目标寄存器不能是CS

MOV BX,AX
MOV ECX,9AH

其中,ECX、BX、AX均为寄存器寻址方式,9AH为立即寻址方式。

  这两种方式在指令执行时,操作数都存储于CPU中。除以上两种寻址方式外,下一节将介绍的寻址方式的操作数都存储于存储器中。

 1.2 存储器操作数寻址

(1)直接寻址方式

MOV EAX,[00404011H]

  [00404011H]是直接寻址方式的一种形式,这里的00404011H用[ ]括起来,它表示一个普通变量的有效地址,而不是操作数本身。

MOV EAX,VAR

   由于汇编中用符号表示地址,所以指令中的源操作数VAR的寻址方式是直接寻址方式。若VAR对应的偏移量是00404011H。执行指令“MOV EAX,VAR”时,CPU从指令中知道VAR的地址为00404011H,再从00404011H中取出一个双字,送到EAX。这里VAR是一个内存操作数,它的地址是直接从指令码中取出的,而不必经过极端或其他操作。

段超越前缀格式为:MOV EBX,ES:MEM
   指令明确表示使用ES所指向的附加数据段中的变量,而不是默认的DS所指向的数据段。

(2)寄存器间接寻址方式
若指令中使用的是BX、SI、EAX、ECX等,则默认操作数在DS段;若使用的是BP、EBP、ESP,则默认操作数在SS段。
   操作数的有效地址在寄存器而操作数本身在存储器中的寻址方式称为寄存器间接寻址

MOV AL,[BX]

地址计算公式:物理地址=段基址*10H+有效地址

[BX]的寻址方式为寄存器间接寻址方式,注意,BX用[ ]括起来,他表示BX寄存器中是有效地址而不是操作数,这也是寄存器间接寻址与寄存器寻址方式在汇编格式的区别

(3)寄存器相对寻址
有效地址EA =(基址<或变址>寄存器)+disp

MOV AL,8[BX]    ;也可以表示为:MOV AL,[BX+8]8是位移量

实模式下,若(DS)=3000H,(BX)=70H ,(30078H)=12H,则物理地址=10H*(DS)+(BX)+8=30078H,该指令的执行结果是(AL)=12H

(4)基址变址寻址方式
有效地址EA=(基址寄存器)+(编址寄存器)

MOV AL,[BX][SI]   /  MOV AL,[BX+SI]
MOV EAX,[EBX][ESI]

(5)相对基址变址寻址方式
有效地址EA=(基址寄存器)+(编址寄存器)+disp

MOV AL,ARY[BX][SI]  / MOV AL,ARY[BX+SI]
MOV EAX,ARY[EBX][ESI]

(6)比例变址寻址方式
这种寻址方式是80386以上的微处理器才提供的

有效地址EA=(基址寄存器)+(编址寄存器)*比例因子+disp

MOV EAX,ARY[EBX][ESI]    ;(DS:[ARY+EBX+ESI]->EAX)
MOV EBX,[EBP+ECX*4+10H]   ;(SS:[EBP+ECX*4+10H]->EBX)

2.数据运算指令

 2.1数传送指令

  2.1.1 通用数据传送指令

(1)传送指令 MOV
格式:MOV DST,SRC
功能:SRC(源)→DST(目标)
说明:MOV指令可以实现一个字节、一个字 、一个双字的数据传送,
注意:源操作数和目标操作数的数据类型匹配问题,即应同为字节、字或双字型数据,可用PTR进行强制转换。
数据传送规则
– 立即数不能作为目标操作数;
– 立即数不能直接送段寄存器;
– 目标寄存器不能是CS;
– 两个段寄存器间不能直接传送;
– 两个存储单元之间不能直接传送。

 MOV    AL,5 
 MOV    DS,AX 
 MOV    [BX],AX 
 MOV    ES:VAR,12 
 MOV    WORD PTR [BX],10 
 MOV    EAX,EBX 

  “WORD PTR” 它明确指出BX所指向的内存 单元为字型,立即数10被汇编为16位的二进制数。若要生成8位的二进制数,需要用 “BYTE PTR”,这里的类型显式说明是必须的。

这里简要概述以下汇编中的PTR的常见用处,下面的文章将不在做说明:

ptr ->pointer (即指针)的缩写。汇编里面 ptr 是规定的字(即保留字),是用来临时指定类型的。
(可以理解为,ptr是临时的类型转换,相当于C语言中的强制类型转换)

    mov ax,bx  ;是把bx寄存器里的值赋予ax,由于二者都是word型,所以没有必要加“WORD”。   
    mov ax,word ptr [bx]  ;是把内存地址等于“bx寄存器的值”的地方所存放的数据,赋予ax。
    由于只是给出一个内存地址,不知道希望赋予ax的是byte还是word,所以需要用word明确指出!
    
    所以,当两个操作数的宽度不一样时,就要用到ptr。
    也就是说,*p 用汇编表示就是:dword ptr [p],*p是取p所指内存地址处的值。

    总结,即有寄存器时一般不用ptr;没有时一定要用(防止两个操作数的宽度不一样)。
    不管用在什么位置,ptr的作用就是临时指定类型。可以放在ptr前面的类型有:
    byte(字节)、word(字)、dword(双字)、qword(四字)、tbyte(十字节)、far(远类型)和near(近类型)

(2)带符号扩展的数据传送指令 MOVSX( 386以上)
格式:MOVSX DST,SRC
功能:SRC—>DST,DST空出位用SRC的符号位填充
说明:DST必须是16位或32位寄存器操作数,SRC可以是8位或16位寄存器或存储器操作数,但不能是立即数。

(3)带零扩展的数据传送指令 MOVZX (386以上)
格式:MOVZX DST,SRC
功能:SRC—>DST,DST空出位用0填充
说明:DST必须是16位或32位寄存器操作数,SRC可以是8位或16位寄存器或存储器操作数,但不能是立即数。

(4)交换指令 XCHG
格式:XCHG OPR1,OPR2
功能:交换两个操作数。
说明:OPR是操作数,操作数可以是8位、 16位、32位。两个操作数均不能是立即数,可以是寄存器操作数和存储器操作数,并且其中之一必须是寄存器操作数

  2.1.2堆栈操作指令

堆栈数据的存取原则是“LIFO”——后进先出
堆栈段段基址→SS
堆栈栈顶地址→SP/ESP
堆栈用途: 对现场数据的保护与恢复、子程序与中断服务返回地址的保护与恢复等。

(1)进栈指令 PUSH
格式:PUSH SRC
功能: SP = SP - 2
   SS:SP = (SRC)
说明:SRC可以是16位或32位(386以上) 的寄存器操作数或存储器操作数。在80286以 上的机器中,SRC还可以是立即数。若SRC是 16位操作数,则堆栈指针减2;若SRC是32位 操作数,则堆栈指针减4。

(2)出栈指令 POP
格式:POP DST
功能: (DST) = SS:SP
   SP = SP + 2
说明:DST可以是16位或32位(386以 上)的寄存器操作数和存储器操作数,也可 以是除CS寄存器以外的任何段寄存器。若 DST是16位,则堆栈指针加2;若DST是32位 ,则堆栈指针加4。

  2.1.3 输入输出指令

(1)输入指令 IN
格式: IN ACR,PORT
功能:把外设端口(PORT)的内容传送给累加器(ACR)。
说明:可以传送8位、16位、32位,相应的累加器选择AL、AX、EAX。

(2)输出指令 OUT
格式:OUT PORT,ACR
功能:把累加器的内容传送给外设端口。
说明:对累加器和端口号的选择限制,同IN指令。

MOV AL,0 
OUT  61H,AL  ;61H端口← (AL) ;关掉PC扬声器

MOV  DX,3F8H 
OUT  DX,AL  ;3F8H端口 ← (AL) ;向COM1端口输出一个字符
  2.1.4 地址传送指令

这类指令传送的是操作数的地址,而不是操作数本身。

(1)传送有效地址指令 LEA
格式:LEA REG,SRC
功能:把源操作数的有效地址送给指定的寄存器。
说明:源操作数必须是存储器操作数

LEA BX,ASC[SI]       ;把DS:[ASC+SI]单元的16位偏移量送给BX

(2)MOV 指令传送地址
  MOV 指令除了可以实现数据传送外, 还可实现地址传送,方法是借助于SEG 和OFFSET操作符。
设TAB为一条语句的符号地址,则可以有 以下指令:

MOV AX,SEG TAB  ;把TAB的段基址送给AX寄存器 
MOV DI,OFFSET TAB ;把TAB的偏移量送给DI寄存器
  2.1.5 标志位传送指令

(1)16位标志进栈指令 PUSHF
格式:PUSHF
功能: 先使堆栈指针寄存器SP-2,然后压入标志寄存器FLAGS的内容到栈顶单元。
SP-2; FLAGS→栈顶单元。

(2)16位标志出栈指令 POPF
格式:POPF
功能:先将堆栈指针所指向的字弹出到FLAGS寄存器,然后使堆栈指针寄存器SP+2

(3)32位标志进栈指令 PUSHFD
格式:PUSHFD
功能:ESP减4;EFLAGS→栈顶。

(4)32位标志出栈指令 POPFD
格式:POPFD

 2.2 算术运算指令

  2.2.1 类型转换指令

  这类指令实际上是把操作数的最高位进行扩展,用于处理带符号数运算的操作数类型匹配问题。这类指令均不影响标志。
  所谓符号扩展,就是将数据的表示大小加倍,数值仍保持不变,即将符号位扩展到同样大小的寄存器空间中去,由两部分构成一个比原值表示大一倍的数。

(1)字节扩展成字指令 CBW
格式:CBW
功能:把AL寄存器中的符号位值扩展到AH中
说明:在8086中CBW指令将AL的最高有效位D7扩展至AH,即:如果AL的最高有效位是0,则AH = 00;AL的最高有效位为1,则AH = FFH。AL不变

例1:AL=88H,执行CBW,AH=FFH
1000 1000
1111 1111 1000 1000

例2:AL=44H,执行CBW,AH=00H
0100 0100
0000 0000 0100 0100

(2)字扩展成双字指令 CWD
格式: CWD
功能:把AX的符号位值扩展到DX中
说明:规则:若AX最高位=1,则执行后DX=FFFFH;若AX最高位=0,则执行后DX=0000H。AX值不变。

(3).双字扩展成四字指令 CDQ
格式:CDQ (386以上)
功能: EAX符号位扩展到EDX中

(4).AX符号位扩展到EAX指令 CWDE
格式: CWDE (386以上)
功能: AX寄存器符号位扩展到EAX高16位

  2.2.2 二进制加法指令

任何一条二进制加、减法指令均适用 于带符号数和无符号数运算。

(1)加法指令 ADD
  格式: ADD DST,SRC
  功能:(DST)+(SRC)→ DST
  说明:对操作数的限定同MOV指令。
  标志:影响OF、SF、ZF、AF、PF、CF标志

(2)带进位加法指令 ADC
  格式: ADC DST,SRC
  功能:(DST)+(SRC)+ CF → DST
  说明: 对操作数的限定同MOV指令,该指令 、适用于多字节或多字的加法运算。
  标志: 影响OF、SF、ZF、AF、PF、CF标志

 ADC  AX,35 ;(AX)= (AX)35+CF

(3)加1指令 INC
  格式:INC DST
  功能:(DST)+1→DST
  标志:除不影响CF标志外,影响其它五个算术运算特征标志。
例.实现+2操作:

 ADD AX,2    ;或者如下
 INC AX 
 INC AX

(4)互换并加法指令 XADD(486以上)
  格式:XADD DST,SRC
  功能: (DST)+(SRC)→TEMP
  (DST)→SRC TEMP→DST
  说明:TEMP是临时变量。该指令执行后,原 DST的内容在SRC中,和在DST中。
  标志:影响OF、SF、ZF、AF、PF、CF。

  2.2.3 二进制减法指令

(1)减法指令 SUB
  格式: SUB DST,SRC
  功能:(DST)-(SRC)→ DST
  标志: 影响OF、SF、ZF、AF、PF、CF标志。
实例:SUB AX,35
   SUB WORD PTR[BX],56

  减法指令执行后若使CF=1,则对无符号数而言发生了溢出。若使OF=1,则对带符号数而言发生了溢出。

(2)带借位减法指令 SBB
  格式: SBB DST,SRC
  功能: (DST)-(SRC)-CF → DST
  说明: 除了操作为减外,其它要求同ADC, 该指令适用于多字节或多字的减法运算。 标志:影响OF、SF、ZF、AF、PF、CF

SBB  AX,35 ;(AX)= (AX)35-CF

(3)减1指令 DEC
  格式: DEC DST
  功能:(DST)-1→DST
  说明:使用本指令可以很方便地实现地址指针或循环次数的减1修改。
标志:除不影响CF标志外,影响其它 五个算术运算特征标志。

(4)比较指令 CMP
  格式:CMP DST,SRC
  功能:(DST)-(SRC),影响标志位。
  说明:这条指令执行相减操作后只根据结果设置标志位,并不改变两个操作数的原值,其它要求同SUB。CMP指令常用于比较两个数的大小。
标志:影响OF、SF、ZF、AF、PF、CF标志

(5)求补指令 NEG
  格式: NEG DST
  功能:对目标操作数(含符号位)求反加1,并且把结果送回目标。即:实现0-(DST)→DST
  说明:利用NEG指令可实现求一个数的相反数。 标志:影响OF、SF、ZF、AF、PF、CF标志。其中对CF和OF的影响如下:

  • 对操作数所能表示的最小负数(例若操作数是8 位则为-128)求补,原操作数不变,但OF被置1
  • 当操作数为0时,清0 CF。
  • 对非0操作数求补后,置1 CF。
  2.2.3 二进制乘法指令

(1)无符号乘法指令 MUL
  格式:MUL SRC
  功能:实现两个无符号二进制数乘。
  说明:该指令只含一个源操作数(不能是立即数), 另一个乘数必须事前放在累加器中。可以实现8位、16 位、32位无符号数乘。例如:若操作数是16位的,则与AX中的内容相乘,乘积放在DX:AX这一对寄存器中。具体操作为:

  • 字节型乘法:(AL)×(SRC)8→AX
  • 字型乘法: (AX)×(SRC)16→DX:AX
  • 双字型乘法:(EAX)×(SRC)32→EDX:EAX

  标志:影响CF、OF、SF、ZF、AF、PF,而只有 CF、OF有意义,其它标志不确定。
  对CF和OF的影响是:若乘积的高半部分(例:字节型乘法结果的AH)为0,则对CF和OF清0,否则置 CF和OF为1。

(2)带符号乘法指令 IMUL
  功能:实现两个带符号二进制数乘。
  格式1IMUL SRC
  说明:这种格式的指令除了是实现两个带符号 数相乘且结果为带符号数外,其它与MUL指令相同。 所有的80X86 CPU都支持这种格式。
  标志:影响CF、OF、SF、ZF、AF、PF,而只有CF、OF 有意义,其它标志不确定。
  对CF和OF的影响是:若乘 积的高半部分为低半部分的符号扩展,则对CF和OF 清0,否则置CF和OF为1。

格式2IMUL REG,SRC (286以上)
说明:REG和SRC的长度必须相同,目标操作数 REG必须是16位或32位通用寄存器,源操作数 SRC可以是寄存器或存储器操作数。
具体操作为: (REG)16×(SRC)16→REG16

格式3IMUL REG,imm8 (286以上)
格式4IMUL REG,SRCreg/m ,imm8 (286以上)

  2.2.3 二进制除法指令

(1)无符号除法指令 DIV
  格式:DIV SRC
  功能:实现两个无符号二进制数除法。
  说明:该指令只含一个源操作数,该操作数 作为除数使用,注意它不能是立即数。被除数必须事前放在隐含的寄存器中。可以实现8位、16位、 32位无符号数除。
在这里插入图片描述
(2)带符号除法指令 IDIV
  格式:IDIV SRC
  功能:实现两个带符号二进制数除。
  说明:除了是实现两个带符号数相除且商和余数 均为带符号数、余数符号与被除数相同外,其它与 DIV指令相同。 具体操作同无符号数除法。

 2.3 位运算指令

  2.3.1 逻辑运算指令

  逻辑运算指令见下表。这些指令的操作数可 以是8位、16位、32位,其寻址方式与MOV指令的限制相同。

在这里插入图片描述

AND EAX,0     ;将EAX寄存器清0
XOR AL,20H    ;转换AL中字母的大小写
  2.3.2 位测试指令

  从386开始增加了位测试指令,它们包括BT 、BTS、BTR和BTC。这些指令首先把指定位的值送给CF标志,然后对该位按照指令的要求操作。
格式:

BT DEST,SRC
BTC DEST,SRC
BTR DEST,SRC
BTS DEST,SRC

功能:按照源操作指定的位号,测试目的操作数,当指令执行时,被测试位的状态被复制到进位标志CF。
BT将SRC指定的DEST中一位的数值复制到CF。
BTC将SRC指定的DEST中一位的数值复制到CF,且将DEST中该位取反。
BTR将SRC指定的DEST中一位的数值复制到CF,且将DEST中该位清0。
BTS将SRC指定的DEST中一位的数值复制到CF,且将DEST中该位置1。

  目标可以是16位或32位的寄存器或存储器操作数,源可以是8位的立即数、寄存器存储器或存储器操作数,若是后两种情况,其长度一定要和目标长度相同。若源操作数是立即数,则其值不应超过目标操作数长度。

  2.3.3 位扫描指令

(1)顺向扫描指令 BSF
格式:BSF DST,RSC
功能:从右向左扫描RSC操作数中第一个含1的位,并把扫描到的第一个含1的位号送DST操作数。 若RSC=0,则DST值不确定。

(2)逆向扫描指令 BSR
格式:BSR DST,RSC

  2.3.4 基本移位指令

  这类指令实现对操作数移位,包括 SHL、SAL、SHR和SAR指令。
在这里插入图片描述
PS:例如SHR(右移):指令使目的操作数逻辑右移一位,最高位用 0 填充。最低位复制到进位标志位,而进位标志位中原来的数值被丢弃

  • 第一种是逻辑移位 (logic shift),空出来的位用 0 填充
  • 另一种移位的方法是算术移位 (arithmetic shift),空出来的位用原数据的符号位填充

  可以用逻辑移位指令实现无符号数乘除法运算,(只要移出位不含1):
SHL DST,n执行后是原数的2n倍
SHR DST,n执行后是原数的1/2n
  可以用算术移位指令实现带符号数乘除法运算,只要移位操作不改变符号位: SAL DST,n执行后是原数的2n倍
SAR DST,n执行后是原数的1/2n (只要移出位不含1)

  2.3.5 循环移位指令

这类指令实现循环移位操作,包括ROL 、ROR、RCL、RCR指令。
 在这里插入图片描述
PS:ROL(循环左移)指令把所有位都向左移。最高位复制到进位标志位和最低位。
   RCL(带进位循环左移)指令把每一位都向左移,进位标志位复制到 LSB,而 MSB 复制到进位标志位。(通常,MSB位于二进制数的最左侧,LSB位于二进制数的最右侧)

3.程序控制指令

 3.1 转移指令的寻址方式

  本节讨论的寻址方式是用来确定转移及调用指令的转向地址。即CPU是如何找到下一条指令的。
  无条件转移指令格式:JMP 目标

  其中的目标有各种寻址方式。这些寻址方式可以被分为段内转移段间转移两类。段内转移只影响指令指针IP值;段间转移既要影响IP值,也要影响代码段寄存器CS的值。

PS:下面可能会出现这类格式:

  • NEAR(段内近调用): 调用程序和子程序在同一代码段中,只能被相同代码段的其他程序调用;
  • FAR(段间远调用): 调用程序和子程序不在同一代码段中,可以被相同或不同代码段的程序调用.
  3.1.1 段内直接寻址方式

  转向的有效地址是当前指令指针寄存器的内容和指令中指定的8位、16位位移量之和,该位移量是一个相对于指令指针的带符号数。
在这里插入图片描述
  EA就是要转向的本代码段内指令地址的偏移量。它是通过把IP的当前值加上指令中给出的位移量disp得到的,从而使IP指向下一条要执行的指令,实现段内转移。

  • 若位移量是8位的,则称为短转移,可以实现在距离下条指令的+127~-128字节范围之内转移。其汇编指令格式:JMP SHORT LAB 。在于当前16位的IP值相加时,系统自动把8位位移量扩展成16位,扩展方法是高8位全部用位移量的符号位填充;在于当前32位的IP值相加时,则高24位全部用位移量的符号位填充。
  • 若位移量是16位或32位的,则称为近转移。其汇编指令格式:JMP LAB
    JMP NEAR PTR LAB
  3.1.2 段内间接寻址方式

  转向的有效地址在一个寄存器或内存单元中,该寄存器号或内存地址按上节介绍的与操作数有关的寻址方式(立即寻址方式除外)获得。所得到的有效地址送给IP,于是实现转移。指令格式及举例见下表。
在这里插入图片描述
PS

JMP  WORD  PTR  [BX]  
说明:式中WORD  PTR  [BX]表示BX指向一个字型内存单元。
	1.这条指令执行时,先按照操作数寻址方式得到存放转移地址的内存单元:
	10H ×(DS)+(BX)= 20300H
	2.再从该单元中得到转移地址:
	EA=(20300H)= 0500H
	3.于是,(IP)=EA=0500H,下一次便执行CS:500H处的指令,实现了段内间接转移。 
  3.1.3 段间直接寻址方式

  指令中直接给出转向的4字节的偏移量和段基址,只需把它们分别送给IP和CS后即可实现段间转移。指令格式:

JMP  FAR  PTR  LAB 

图(a)适用于16位操作数长度,执行时把偏移量送给IP,段基址送给CS。
图(b)适用于32位操作数长度,执行时把偏移量送给EIP,段选择符送给CS。
在这里插入图片描述

  3.1.4 段间间接寻址方式

  用一个双字内存变量中的低16位取代IP值,高16位取代CS值,从而实现段间转移。该双字变量的地址可以由除立即寻址和寄存器寻址方式以外的其它与数据有关的寻址方式获得。

JMP  DWORD  PTR  [BX]  
设:(DS)= 2000H,(BX)= 0300H
    (IP)= 0100H,(20300H)= 0
    (20301H)= 05H
    (20302H)= 10H
    (20303H)= 60H
	说明:式中DWORD  PTR  [BX]表示BX指向一个双字变量。
	这条指令执行时,先按照与操作数有关的寻址方式得到存放转移地址的内存单元:
10H×(DS)+(BX)= 20300H
再把该单元中的低字送给IP,高字送给CS,即0500H →IP,6010H→CS,
下一次便执行6010:0500H处的指令,实现了段间间接转移。

 3.2 转移指令

  这类指令包括无条件转移指令条件转移指令

(1)无条件转移指令
格式:JMP DST
功能:无条件转移到DST所指向的地址

(2)条件转移指令
  执行这类指令时通过检测由前边指令已设置的标志位确定是否转移,所以它们通常是跟在影响标志的指令之后。这类指令本身并不影响标志。

格式:JCC LABEL
功能:如果条件为真,则转向标号处,否则顺序执行下一条指令。
说明:其中cc为条件,LABEL是要转向的标号。在8086-80286中,该地址应在与当前IP值的-128~+127范围之内,即只能使用与转移地址有关的寻址方式的段内短转移格式,其位移量占用一个字节。

  • 检测单个标志位实现转移的条件转移指令,这组指令根据一个标志位的设置情 况决定是否转移。
    在这里插入图片描述
  • 根据两个带符号数比较结果实现转移的条件转移指令,利用上表中提供的指令,可以实现两个带符号数的比较转移。
    在这里插入图片描述
  • 根据两个无符号数比较结果实现转移的条件转移指令

在这里插入图片描述

  • 测试CX/ECX值为0转移指令。这类指令不同于以上介绍的条件转移指令,因为它们测试的是CX或ECX寄存器的内容是否为0,而不是测试标志位。这类指令只能使用与转移地址有关的寻址方式的段内短转移格式,即位移量只能是8位的。

格式JCXZ LABEL   ;适用于16位操作数
      JECXZ LABEL  ;适用于32位操作数
功能:测试CX(或ECX)寄存器的内容,当CX(或ECX)= 0时则转移,否则顺序执行。
说明:此指令经常用于在循环程序中判断循环计数的情况。

 3.3 循环指令

循环指令可以控制程序的循环。它们的特点是:

  • 用CX或ECX(操作数长度为32位时)作为循环次数计数器。
  • 不影响标志。

(1)循环指令 LOOP
 格式:LOOP LABEL
 功能:(CX)-1→CX,若(CX)≠0,则转向标号处执行循环体,否则顺序执行下一条指令。
 说明:若操作数长度为32位,则其中的CX应为ECX。在LOOP指令前,应先把循环计数的初始值送给CX(或ECX)。
(2)相等循环指令 LOOPE/LOOPZ
(3)不等循环指令 LOOPNE/LOOPNZ

 3.4子程序调用与返回指令

  3.4.1子程序调用指令CALL

格式:CALL DST
功能:调用子程序。执行时先把返回地址压入堆栈,再形成子程序入口地址,最后把控制权交给子程序。
说明:其中DST为子程序名或子程序入口地址,其目标地址的形成与JMP指令有异同。

  • 与JMP指令相同点:
    段内直接/间接调用、段间直接/间接调用。只是不能使用段内直接寻址方式的SHORT格式。指令的执行结果是无条件转到标号处。
  • 与JMP指令不同点:
    CALL转移后要返回,所以要保存返回地址; JMP转移后不再返回,所以不必保存返回地址。

(1)段内调用
  这类调用指令实现同一段内的子程序调用,它只改变IP值,不改变CS值
  执行操作

  • 把返回地址(CALL之后的那条指令地址的偏移量部分(当前IP值))压入堆栈。
  • 根据与转移地址有关的寻址方式形成子程序入口地址的IP值。
  • 把控制无条件转向子程序,即执行CS:IP处的指令。

段内直接调用
  格式:CALL A
  或: CALL NEAR PTR A
  功能:调用A子程序。执行时先把返回地址压入堆栈,再使IP=(IP)+disp16,最后把控制权交给子程序。

段内间接调用
  格式:CALL REG/M
  功能:调用子程序。执行时先把返回地址压入堆栈,再把指令指定的16位通用寄存器或内存单元的内容送给IP,最后把控制权交给子程序。

(2)段间调用
  这类调用指令可以实现段间调用(FAR型调用),执行时即要改变IP值,也要改变CS值。

段间直接调用
  格式:CALL FAR PTR PROCEDURE
  功能:调用PROCEDURE子程序。执行时先把返回地址(当前IP值和当前CS值)压入堆栈,再把指令中的偏移量部分送给IP,段基址部分送给CS,最后把控制权交给子程序。

段间间接调用
  格式:CALL M
  功能:调用子程序。执行时先把返回地址(当前IP值和当前CS值)压入堆栈,再把M的低字送给IP,高字送给CS,最后把控制权交给子程序。

  3.4.2子程序返回指令

  执行这组指令可以返回到被调用处。有两条返回指令,它们都不影响标志。以下介绍8086/8088的子程序调用指令。

返回指令 RET
  格式:RET
  功能:按照CALL指令入栈的逆序,从栈顶弹出返回地址(弹出一个字到IP,若子程序是FAR型还需再弹出一个字到CS),然后返回到主程序继续执行。
无论子程序是NEAR型还是FAR型,返回指令的汇编格式总是用RET表示。但经汇编后会产生不同的机器码。在DEBUG中,段间返回指令被反汇编成RETF。

带立即数的返回指令
  格式:RET imm16
  功能:按照CALL指令入栈的逆序,从栈顶弹出返回地址(弹出一个字到IP,若子程序是FAR型还需再弹出一个字到CS),返回到主程序,并修改栈顶指针SP=(SP)+imm16。
  :其中imm16是16位的立即数,设通过堆栈给子程序传递了n个字型参数,则imm16=2n。

修改堆栈指针是为了废除堆栈中主程序传递给子程序的参数。

 3.5中断调用与返回指令

  中断就是使计算机暂时挂起正在执行的进程而转去处理某种事件,处理完后再恢复执行原进程的过程。
  对某事件的处理实际上就是去执行一段例行程序,该程序被称为中断处理例行程序或中断处理子程序,简称为中断子程序。

  1. 中断向量
      中断向量就是中断处理子程序的入口地址。在PC机中规定中断处理子程序为FAR型,所以每个中断向量占用4个字节,其中低两个字节为中断向量的偏移量部分,高两个字节为中断向量的段基址部分。
  2. 中断类型号
      IBM PC机共支持256种中断,相应编号为0~255,把这些编号称为中断类型号。
  3. 中断向量表
      256种中断有256个中断向量。把这些中断向量按照中断类型号由小到大的顺序排列,形成中断向量表。
      表长为4×256= 1024字节,该表从内存的0000:0000地址开始存放,从内存最低端开始存放。

中断调用指令 INT
  在8086/8088中,中断分为内中断(或称软中断)和外中断(或称硬中断),本节只介绍内中断的中断调用指令。
  格式:INT n ;n为中断类型号
  功能:中断当前正在执行的程序,把当前的FLAGS、CS、IP值依次压入堆栈(保护断点),并从中断向量表的4n处取出n类中断向量。其中(4n)→IP,(4n+2)→CS,转去执行中断处理子程序。

中断返回指令 IRET
  格式:IRET
  功能:从栈顶弹出三个字分别送入IP、CS、FLAGS寄存器,把控制返回到原断点继续执行。

4.处理机控制指令

  这组指令可以控制处理机状态以及对某些标志位进行操作。

 4.1 标志操作指令

  这组指令可以直接对CF、DF和IF标志位进行操作,它们只影响本指令所涉及的标志。
在这里插入图片描述

 4.2 常用处理机控制指令

  这组指令可以控制处理机状态,它们均不影响标志,见下表。
在这里插入图片描述

5.块操作指令

  利用块操作指令可以直接处理两个存储器操作数,方便地处理字符串或数据块(批量处理)。
常用的块操作指令
在这里插入图片描述
:块操作指令中,指令后面的B、W、D代表操作数的大小,分别代表字节、字、双字的内存操作数。

源操作数与目标操作数
在这里插入图片描述

 5.1 块指令的特点

指令格式
  块指令可以显式地带有操作数,也可以使用隐含格式。例如块传送指令MOVS,可以有以下几种格式:
  显式:MOVS DST, SRC
  隐式:MOVSB   ;字节传送
     MOVSW   ;字传送
     MOVSD   ;双字传送
经常使用隐含格式。操作数时应先建立地址指针。

操作数
  块指令可以处理寄存器操作数存储器操作数
  若为寄存器操作数只能放在累加器中;
  对于存储器操作数应先建立地址指针:若为源操作数,则必须把源串首地址放入SI寄存器,缺省情况寻址DS所指向的段,允许使用段超越前缀;若为目标操作数,则必须把目标串首地址放入ES:DI寄存器,不允许使用段超越前缀。

地址指针的修改
  块指令执行后系统自动修改地址指针SI(ESI)、DI(EDI)。若为字节型操作其修改量为1,若为字型操作其修改量为2,若为双字型操作其修改量为4。

方向标志
  方向标志DF决定地址指针的增减方向。
  DF=0,则地址指针增量;
  DF=1,则地址指针减量。
  可以用CLD和STD指令复位和置位DF。

重复前缀
  块指令前可以加重复前缀REPE/REPZ、 REP或REPNE/REPNZ,使后跟的串指令重复执行。重复次数应事先初始化在计数器CX中。

(1)重复前缀 REP
  若(CX)=0,则结束重复,顺序执行下一条指令。
  若(CX)≠0,则执行后跟的串操作指令,然后修改计数器(CX)-1→CX,继续重复上述操作。
  若地址长度为32位的,则使用ECX。

(2)相等重复前缀 REPE/REPZ
  REPE/REPZ可以用在比较类块操作指令之前,当比较相等且重复次数未到时重复执行后跟的串指令。其执行的操作为:
  若(CX)=0(计数到)或ZF=0(不相等),则结束重复,顺序执行下一条指令。否则执行后跟的块操作指令,修改计数器(CX)-1→CX。继续重复上述操作。
  若地址长度为32位的,则使用ECX。

(3)不等重复前缀 REPNE/REPNZ

 5.2 块指令

  1. 块传送指令 MOVS

  显式格式:MOVS DSTm,SRCm
  隐含格式:MOVSB MOVSW MOVSD
  功能:源→目标,即([SI])→ES:[DI],且自动修改SI、DI指针。主要将DS:SI地址的数据复制到ES:DI地址中。
  标志:不影响标志位。

在MOVS操作结束后,(E)SI与(E)DI寄存器会自动的增加或者减少,而依据则是根据EFLAGS寄存器中的DF标志位来判断增加还是减少。

  • 如果DF标志位为0,则(E)SI与(E)DI寄存器则自增
  • 如果DF标志位为1,则(E)SI与(E)DI寄存器则自减
  1. 取块指令 LODS

  显式格式:LODS SRCm
  隐含格式:LODSB LODSW LODSD
  功能:源→累加器,即([SI]) →AL(或AX、EAX),且自动修改SI指针。
  说明:若DF=0,则LODSB(或LODSW、LODSD)使SI加1(或2、4);若DF=1,则LODSB(或LODSW、LODSD)使SI减1(或2、4)。若地址长度是32位的,则SI相应为ESI。
  标志:不影响标志位。

  1. 存块指令 STOS

  显式格式:STOS DSTm
  隐含格式:STOSB STOSW STOSD
  功能:累加器→目标,即(AL(或AX、EAX)) →ES:[DI],且自动修改DI指针。
  说明:若DF=0,则STOSB(或STOSW、STOSD)使DI加1(或2、4);若DF=1,则STOSB(或STOSW、STOSD)使DI减1(或2、4)。若地址长度是32位的,则DI相应为EDI。
  标志:不影响标志位。

  1. 块输入指令 INS
    显式格式:INS DSTm,DX
    隐含格式:INSB INSW INSD

  2. 块输出指令 OUTS
    显式格式:OUTS DX,SRCm

  3. 块比较指令 CMPS
    显式格式:CMPS DSTm,SRCm

  4. 块扫描指令 SCAS
    显式格式:SCAS DSTm

发布了36 篇原创文章 · 获赞 65 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43275558/article/details/105486225
今日推荐