与转移地址有关的寻址方式
寻址方式是用来确定转移及调用(CALL)指令的转向地址。下面以8086/8088的无条件转移指令为例来说明。
JMP 目标
这里的目标有各种寻址方式。这些寻址方式可以被分为段内转移和段间转移两类。段内转移只影响指令指针IP值;段间转移既要影响IP值,也要影响代码段寄存器CS的值。
1.段内直接寻址方式(intrasegment direct addressing)
EA = (IP) + (8位或16位)disp
位移量disp是一个相对于指令指针的带符号数,EA就是要转向的本代码段内指令地址的偏移量。这种寻址方式符合程序的再定位要求。
若位移量是8位的,则称为短转移,可以实现在距离下条指令的+127~-128字节范围之内转移,汇编语言格式为:JMP SHORT LAB 。其中LAB为转向的目标地址的符号表示,在机器指令中,用位移量来表示。
若位移量是16位的,则称为近转移,可以实现在距离下条指令的+32767~-32768(以下简称±32K)字节范围之内转移,汇编语言格式为:JMP LAB 或JMP NEAR PTR LAB。
2.段内间接寻址方式(intrasegment indirect addressing)
转向的有效地址在一个寄存器或内存单元中,该寄存器号或内存地址按上节介绍的与操作数有关的寻址方式(立即寻址方式除外)获得。
例:假设(DS)=2000H,(BX)=1256H,(SI)=528FH,位移量=20A1H,(232F7H)=3280H,(264E5H)=2450H。
JMP BX ----> (IP)=1256H
JMP TABLE[BX]----> (IP)=3280H
JMP [BX][SI] ----> (IP)=2450H
3.段间直接寻址方式(intersegment direct addressing)
指令中直接给出转向的4字节的偏移量和段基址。汇编格式为:JMP FAR PTR LAB 。
执行时偏移量送IP,段基址送CS。
4.段间间接寻址方式(intersegment indirect addressing)
用一个双字内存变量中的低16位取代IP值,高16位取代CS值,从而实现段间转移。
例: JMP DWORD PTR [BX]
式中DWORD PTR [BX]表示BX指向一个双字变量。对于32位的保护模式,其段内转移的目标地址的形成与以上所介绍的16位机相比较没有太大变化,只是偏移量为32位、并把该偏移量送给EIP指令指针寄存器而已。
而段间转移的目标地址采用48位全指针形式,即32位的偏移量和16位的段选择子。
数据传送指令
80X86的指令系统分为:数据传送指令、算术指令、逻辑指令、程序控制指令、处理机控制指令、串操作指令、条件字节设置指令等。
指令可以用大写、小写或大小写字母混合的方式书写。386以上CPU可以支持32位操作数。
数据传送指令可以实现数据、地址、标志的传送。除了目标地址为标志寄存器的传送指令外,本组的其它指令不影响标志。
通用数据传送指令
*MOV传送指令
格式:MOV DST,SRC
功能:SRC(源)→DST(目标)
说明:MOV指令可以实现一个字节、一个字、一个双字的数据传送,但要注意源操作数和目标操作数的数据类型匹配问题。
有几点需要注意:
1)立即数不能作为目标操作数。
2)立即数不能直接送段寄存器。
3)目标寄存器不能是CS,因为随意修改CS会引起不可预料的结果。
4)两个段寄存器间不能直接传送。
5)两个存储单元间不能直接传送。
MOV 指令除了可以实现数据传送外,还可实现地址传送,方法是借助于SEG和OFFSET操作符。
例:设TAB为一条语句的符号地址,则可以有以下指令:
MOV AX, SEG TAB;把TAB的段基址送给AX寄存器
MOV DI, OFFSET TAB;把TAB的偏移量送给DI寄存器
*MOVSX带符号扩展传送指令(Move with Sign Extend)
该指令只有80386以上机器才提供。
格式:MOVSX DST, SRC
功能:SRC→DST, DST空出的位用SRC的符号位填充。
说明:DST必须是16位或32位寄存器操作数。SRC可以是8位或16位的寄存器或存储器操作数,不能是立即数。
例:
MOV DL , 80H
MOVSX AX , DL ; (AX) = 0FF80H
MOVSX EAX , DL ;(EAX) = 0FFFFFF80H
例:
MOV VAR , 56H
MOVSX AX , VAR ;(AX) = 0056H
*MOVZX带零扩展传送指令(Move with Zero
Extend)
该指令只有80386以上机器才提供。
格式:MOVZX DST, SRC
功能:SRC→DST , DST空出的位用0填充。
说明:DST必须是16位或32位寄存器操作数。SRC可以是8位或16位的寄存器或存储器操作数,不能是立即数。
例:
MOV DL , 80H
MOVZX AX , DL ; (AX) = 0080H
MOVZX EAX , DL ;(EAX) = 00000080H
使用MOVSX指令可以方便地实现对带符号数的扩展,使用MOVZX指令可以方便地实现对无符号数的扩展。
堆栈操作指令:堆栈数据的存取原则是“后进先出”。
堆栈主要用于对现场数据的保护与恢复、子程序与中断
服务返回地址的保护与恢复等。
① 进栈指令PUSH (Push onto the stack)
格式:PUSH SRC
功能:先修改堆栈指针使其指向新的栈顶,然后把SRC压入(拷贝)到栈顶单元。
说明: SRC可以是16位或32位(386以上)的寄存器操作数或存储器操作数。在80286以上的机器中,SRC还可以
是立即数。
执行操作:
16位指令:
(SP)<--(SP)-2
((SP)+1,(SP))<--(SRC)
32位指令:
(ESP)<--(ESP)-4
((ESP)+3,(ESP)+2,(ESP)+1,(ESP))<--(SRC)
注意:随着PUSH指令条数的增加,栈中数据也随之增多,堆栈可用空间逐渐减少,若开辟的堆栈空间不够大,最终会导致堆栈溢出。
② 出栈指令POP (Pop from the stack)
格式:POP DST
功能:先把堆栈指针所指向单元的内容弹出(拷贝)到DST, 然后修改堆栈指针以指向新的栈顶。
说明: DST可以是16位或32位(386以上)的寄存器操作数和存储器操作数,也可以是除CS寄存器以外的任何段寄存器。
执行操作:
16位指令:
(DST)<--((SP)+1,(SP))
(SP)<--(SP)+2
32位指令:
(DST)<--((ESP)+3,(ESP)+2,(ESP)+1,(ESP))
(ESP)<--(ESP)+4
注意:随着POP指令条数的增加,SP的值也随之增加,堆栈可用空间逐渐加大,当SP的值已大于初始设置时,则出现堆栈异常
③ 全部16位通用寄存器进栈指令PUSHA (Push All 16 bit general purpose registers)
格式:PUSHA
功能:把8个16位通用寄存器的内容压入堆栈,入栈顺序是AX、CX、DX、BX、SP(PUSHA指令执行前的值)、BP、SI、DI。入栈后SP值被减去16。
说明: 适用于80286以上机器。
④ 全部16位通用寄存器出栈指令POPA (Pop All 16 bit general purpose registers)
格式:POPA
功能:把栈顶的8个字按PUSHA的逆序弹出到8个16位
通用寄存器,即出栈的顺序是DI、SI、BP、SP、BX、DX、CX、AX,于是恢复了这些寄存器在执行PUSHA之前的值。
说明: 适用于80286以上机器。
交换指令XCHG (Exchange)
格式:XCHG OPR1,OPR2
功能:交换两个操作数。
例1.
设:(AX)= 1234H,(BX)= 4567H
则: XCHG AX,BX
执行后(AX)= 4567H,(BX)= 1234H
例2.
设:(BX)= 6F30H,(BP)= 0200H,(SI)= 0046H,
(SS)= 2F00H,(2F246H)= 4154H
则: XCHG BX , [BP+SI]
执行后(BX)= 4154H,(2F246H)= 6F30H
输入输出指令
*输入指令IN (Input)
这组指令只限于使用累加器EAX,AX,或AL传送信息。
格式:IN ACR , PORT
功能:把外设端口(PORT)的内容传送给累加器(ACR)。
说明:可以传送8位、16位、32位,相应的累加器选择AL、AX、EAX。
注意:若端口号在0~255之间,则端口号直接写在指令中;若端口号大于255,则端口号通过DX寄存器间接寻址,即端口号应先放入DX中。
例: IN AL , 61H ; 把61H端口的内容输入到AL
IN AX , 20H ; 把20H端口的内容(字)输入
到AX
例: MOV DX , 3F8H
IN AL , DX ; 把3F8H端口的内容输入到AL
*输出指令OUT (Output)
格式:OUT PORT , ACR
功能:把累加器的内容传送给外设端口。
例:OUT 20H , AX ; 把AX内容输出到20H端口
例: MOV DX , 3F8H
OUT DX , AL ; 把AL的内容输出到3F8H端口
在80X86里,所有I/O端口与CPU之间的通信都由IN和OUT指令来完成。其中IN完成从I/O到CPU的信息传送,而OUT则完成从CPU到I/O的信息传送。
*查表转换指令XLAT
格式:XLAT
功能:通过AL寄存器中的索引值在表中查得表项内容并将之返回到AL中。
例: (BX) = 0040H , (AL) = 0FH , (DS) = F000H
XLAT指令执行后,(AL) = 2CH,即指令把AL中的代码0FH转换为2CH。
由于AL寄存器只有8位,所以表格的长度不能超过256。
地址传送指令
这类指令传送的是操作数的地址,而不是操作数本身。
*传送有效地址指令LEA(Load Effective Address)
格式:LEA REG , SRC
功能:把源操作数的有效地址送给指定的寄存器。
说明:源操作数必须是存储器操作数。
例:
LEA BX , TAB ; 同MOV BX , OFFSET TAB
LEA BX , TAB[SI] ; 把DS : [TAB+SI]单元的偏移量送给BX
MOV指令的执行速度比LEA指令更快。但是,OFFSET只能与简单的符号地址相连,不能和诸如TAB[SI]或[SI]等复杂操作数相连。LEA指令的适用范围更广,本组的其它指令也是为同一目的服务的。
例:
LEA BX , [BX+SI+0F62H]
若指令执行前(BX) = 0400H,(SI) = 003CH,
则指令执行后(BX) = 0400H + 003CH + 0F62H = 139EH
*加载数据段指针指令LDS(Load DS with Pointer)
格式:LDS REG , SRC
功能:把源操作数中的FAR型指针拷贝到DS和指令中指定的通用寄存器。
说明:若REG是16位的,则源操作数必须是32位的,其中低16位送寄存器,高16位送DS;若REG是32位的,则源操作数必须是48位的,其中低32位送寄存器,高16位送DS。目的寄存器REG不允许使用段寄存器。
例: LDS SI , ADDR
若(DS:ADDR)= 78563412H,则执行结果是:
(DS)= 7856H,(SI)= 3412H
*加载附加数据段指针指令LES(Load ES with Pointer)
格式:LES REG , SRC
说明:目的寄存器REG不允许使用段寄存器。
9
加载数据段指针指令LDS(Load DS with Pointer)
格式:LDS REG , SRC
功能:把源操作数中的FAR型指针拷贝到DS和指令中
指定的通用寄存器。
说明:若REG是16位的,则源操作数必须是32位的,其中
低16位送寄存器,高16位送DS;若REG是32位的,则源操
作数必须是48位的,其中低32位送寄存器,高16位送DS。
目的寄存器REG不允许使用段寄存器。
例: LDS SI , ADDR
若(DS:ADDR)= 78563412H,则执行结果是:
(DS)= 7856H,(SI)= 3412H
DS
SI
DS
ADDR 12 H
34 H
56 H
78 H
*加载附加数据段指针指令LES(Load ES with Pointer)
格式:LES REG , SRC
说明:目的寄存器REG不允许使用段寄存器。
*加载FS数据段指针指令LFS(Load FS with Pointer)
格式:LFS REG , SRC
说明:80386以上CPU才支持。目的寄存器REG不允许使用段寄存器。
*加载GS数据段指针指令LGS(Load GS with Pointer)
格式:LGS REG , SRC
说明:80386以上CPU才支持。目的寄存器REG不允许使用段寄存器。
*加载堆栈段指针指令LSS(Load SS with Pointer)
格式:LSS REG , SRC
说明:80386以上CPU才支持。目的寄存器REG不允许使用段寄存器。
用LSS指令装载堆栈指针是简单安全的方法,因为它可以在一个不被中断的操作中同时改变标识堆栈的两个寄存器,即它可以确保在一条指令中使SS和SP都被重置。
标志传送指令
*标志进栈指令PUSHF/PUSHFD(Push Flags or EFlags Register onto the Stack)
格式:PUSHF/PUSHFD
*标志出栈指令POPF/POPFD(Pop Stack into Flags or EFlags Register)
格式:POPF/POPFD
标志:影响FLAGS/EFLAGS中的所有标志。
*标志送AH指令LAHF(Load AH with Flags)
格式:LAHF
*AH送标志寄存器指令SAHF(Store AH into Flags)
格式:SAHF
执行的操作: (FLAGS的低八位) ← (AH)
标志:影响FLAGS中的低8位标志。