打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
X86汇编学习小结
生成汇编代码
比如,一个简单的函数:
// hello.cvoid func(){}
如何得到相应的汇编代码呢?
gcc -S hello.c
hello.s
clang -S hello.c
hello.s
gcc -S -masm=intel hello.c
hello.s
cl /FAs /C hello.c
hello.asm
看些结果:
gcc 4.5.2, Ubuntu11.04 X86 默认的汇编
.globl func .type func, @functionfunc: pushl %ebp movl %esp, %ebp popl %ebp retclang 2.8, Ubuntu11.04 X86
.globl func .align 16, 0x90 .type func,@functionfunc: pushl %ebp movl %esp, %ebp popl %ebp ret.Ltmp0: .size func, .Ltmp0-funcgcc 4.5.2, Ubuntu11.04 X86 Intel格式的汇编
.globl func .type func, @functionfunc: push ebp mov ebp, esp pop ebp retcl 16 (即VC10), Windows Xp
_func PROC; 1 : void func(){} push ebp mov ebp, esp pop ebp ret 0_func ENDP顺便看一个Sun Studio 11: C 5.8 compiler,SPARC架构(服务器来自unix-center)
.global func .type func,#functionfunc: save %sp,-96,%sp jmp %i7+8 restore...以及GCC 4.0.1,SPARC架构(服务器来自unix-center)
.global funcfunc: retl ! Result = nop .type func,2 .size func,(.-func)...
这些东西太复杂了,关注点只能限制到X86架构了。先看一下X86下常用的两种汇编有哪些不同。
X86汇编语言 差异
X86 下常用的汇编有 AT&T 与 Intel 两种(fix me?),二者在语法上有一定的差异:
注:本节内容来自http://oss.org.cn,文字和格式进行了重新整理。
前缀/后缀
区别:
Intel语法
AT&T语法
寄存器
加前缀 %
立即数
加前缀 $
十六进制
加后缀h
数字前加 0x
二进制
加后缀b
例子:
Intel语法
AT&T语法
mov eax,8
movl $8,%eax
mov ebx,0ffffh
movl $0xffff,%ebx
int 80h
int $0x80
操作数的方向
二者方向正好相反
Intel语法,第一个是目的操作数,第二个是源操作数。
AT&T中,第一个数是源操作数,第二个数是目的操作数。(更符合阅读习惯哈)
例子:
Intel语法(<==)
AT&T语法(==>)
mov eax,[ecx]
movl (%ecx),%eax
内存单元操作数
在Intel的语法中,基寄存器用“[]”括起来
而在AT&T中,用“()”括起来。
Intel
AT&T
mov eax,[ebx+5]
movl 5(%ebx),%eax
间接寻址方式
Intel的指令格式是segreg:[base+index*scale+disp]
AT&T的格式是%segreg:disp(base,index,scale)
Intel语法
AT&T语法
指令 foo,segreg:[base+index*scale+disp]
指令 %segreg:disp(base,index,scale),foo
mov eax,[ebx+20h]
Movl 0x20(%ebx),%eax
add eax,[ebx+ecx*2h]
Addl (%ebx,%ecx,0x2),%eax
lea eax,[ebx+ecx]
Leal (%ebx,%ecx),%eax
sub eax,[ebx+ecx*4h-20h]
Subl -0x20(%ebx,%ecx,0x4),%eax
操作码的后缀
在AT&T的操作码后加后缀,“l”(long,32位),“w”(word,16位),“b”(byte,8位)
在Intel的语法中,在操作数的前加byte ptr、 word ptr 或 dword ptr
例子:
Intel语法
AT&T语法
Mov al,bl
movb %bl,%al
Mov ax,bx
movw %bx,%ax
Mov eax,ebx
movl %ebx,%eax
Mov eax, dword ptr [ebx]
movl (%ebx),%eax
找个例子看看
hello.c
int func(int i){ return 2 * i;}int main(){ int s = func(255); return 0;}hello.s (gcc4.5.2, x86/ubuntu11.04)
func:
pushl   %ebp
将ebp内容压栈保存
movl    %esp, %ebp
movl    8(%ebp), %eax
注意到立即数255在main中压栈后,先后有IP和本函数内的ebp压栈,故,栈顶+8指向立即数255
addl    %eax, %eax
乘法操作变成了加法,eax存放返回值
popl    %ebp
ebp出栈
ret
函数返回,(IP出栈)
main:
pushl   %ebp
将ebp内容压栈保存,
movl    %esp, %ebp
将栈顶保存到ebp中
subl    $20, %esp
栈顶下移20字节,用来保存局部变量
movl    $255, (%esp)
将立即数255放入栈顶所指位置
call    func
调用函数func,(此时将下条指令地址IP压入栈中)
movl    %eax, -4(%ebp)
将func的返回值放入局部变量中(-4(%ebp)就是变量s的位置)
movl    $0, %eax
0送入eax,准备返回值
leave
leave等价于 movl %ebp,%esp 和 popl %ebp
ret
参考
http://oss.org.cn/kernel-book/ch02/2.6.1.htm
http://bbs.bccn.net/thread-106533-1-1.html
==================================================================================================
X86 汇编语言中CPU上的通用寄存器简要说明
eax, ebx, ecx, edx, esi, edi, ebp, esp等都是X86 汇编语言中CPU上的通用寄存器的名称,是32位的寄存器。如果用C语言来解释,可以把这些寄存器当作变量看待。
比方说:add eax,-2 ;   //可以认为是给变量eax加上-2这样的一个值。
这些32位寄存器有多种用途,但每一个都有“专长”,有各自的特别之处。
EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。
EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址。
ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。
EDX 则总是被用来放整数除法产生的余数。
ESI/EDI 分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.
EBP 是"基址指针"(BASE POINTER), 它最经常被用作高级语言函数调用的"框架指针"(frame pointer). 在破解的时候,经常可以看见一个标准的函数起始代码:
push ebp ; 保存当前ebp
mov ebp,esp ; EBP设为当前堆栈指针
sub esp, xxx ; 预留xxx字节给函数临时变量.
...
这样一来,EBP 构成了该函数的一个框架, 在EBP上方分别是原来的EBP, 返回地址和参数. EBP下方则是临时变量. 函数返回时作 mov esp,ebp/pop ebp/ret 即可.
ESP 专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。 在32位平台上,ESP每次减少4字节。
esp:寄存器存放当前线程的栈顶指针
ebp:寄存器存放当前线程的栈底指针
eip:寄存器存放下一个CPU指令存放的内存地址,当CPU执行完当前的指令后,从EIP寄存器中读取下一条指令的内存地址,然后继续执行。
一般寄存器:AX、BX、CX、DX
AX:累積暫存器,BX:基底暫存器,CX:計數暫存器,DX:資料暫存器
索引暫存器:SI、DI
SI:來源索引暫存器,DI:目的索引暫存器
堆疊、基底暫存器:SP、BP
SP:堆疊指標暫存器,BP:基底指標暫存器
EAX、ECX、EDX、EBX:為ax,bx,cx,dx的延伸,各為32位元
ESI、EDI、ESP、EBP:為si,di,sp,bp的延伸,32位元
栈的基本模型
参数N
↓高地址
参数…
函数参数入栈的顺序与具体的调用方式有关
参数 3
参数 2
参数 1
EIP
返回本次调用后,下一条指令的地址
EBP
保存调用者的EBP,然后EBP指向此时的栈顶。
临时变量1
临时变量2
临时变量3
临时变量…
临时变量5
↓低地址
===========================================================================
80x86指令系统
80x86指令系统,指令按功能可分为以下七个部分。
(1) 数据传送指令。
(2) 算术运算指令。
(3) 逻辑运算指令。
(4) 串操作指令。
(5) 控制转移指令。
(6) 处理器控制指令。
(7) 保护方式指令。
3.3.1数据传送指令
数据传送指令包括:通用数据传送指令、地址传送指令、标志寄存器传送指令、符号扩展指令、扩展传送指令等。
一、通用数据传送指令
1传送指令
传送指令是使用最频繁的指令,格式:MOV DEST,SRC
功能:把一个字节,字或双字从源操作数SRC传送至目的操作数DEST。
传送指令允许的数据流方向见图311。
图 3.11  传送指令数据流
由上图可知,数据允许流动方向为:通用寄存器之间、通用寄存器和存储器之间、通用寄存器和段寄存器之间、段寄存器和存储器之间,另外还允许立即数传送至通用寄存器或存储器。但在上述传送过程中,段寄存器CS的值不能用传送指令改变。
例 3.12CPU内部寄存器之间的数据传送。
MOV AL,DH    ;AL←DH    (8位)
MOV DS,AX    ;DS←AX    (16位)
MOV EAX,ESI   ;EAX←ESI   (32位)
例 3.13CPU内部寄存器和存储器之间的数据传送。
MOV [BX],AX       ;间接寻址     (16位)
MOV EAX,[EBX+ESI]   ;基址变址寻址   (32位)
MOV AL,BLOCK      ;BLOCK为变量名,直接寻址(8位)
例 3.14立即数送通用寄存器、存储器。
MOV EAX,12345678H   ;EAX←12345678H   (32位)
MOV [BX],12H      ;间接寻址      (8位)
MOV AX,1234H;AX←1234H(16位)
使用该指令应注意以下问题:
·源和目的操作数不允许同时为存储器操作数;
·源和目的操作数数据类型必须一致;
·源和目的操作数不允许同时为段寄存器;
·目的操作数不允许为CS和立即数;
·当源操作数为立即数时,目的操作数不允许为段寄存器;
·传送操作不影响标志位。
2扩展传送指令
格式:MOV SX DEST,SRC
MOV ZX DEST,SRC
功能:将源操作数由8位扩展到16位送目的操作数,或由16位扩展到32位送目的操作数。其中MOVSX是按有符号数扩展,MOVZX是按无符号数扩展。无符号数或正数高位扩展为0,负数高位扩展为全“1”。
例 3.15带符号数扩展
MOV BL,80H  ; -128
MOVSX AX,BL  ; 将80H扩展为FF80H后送AX中。
例 3.16无符号数扩展
MOV BL,80H  ; 128
MOVZX AX,BL  ; 将80H扩展为0080H后送AX中。
使用该指令应注意以下问题:
·目的操作数应为16位或32位通用寄存器;
·源操作数长度须小于目的操作数长度,为8位或16位通用寄存器或存储器操作数;
·扩展传送操作不影响标志位。
3交换指令
(1) 格式:XCHG OPR1,OPR2
功能:交换操作数OPR1和OPR2的值,操作数数据类型为字节、字或双字。允许通用寄存器之间,通用寄存器和存储器之间交换数据。
例 3.17
XCHG AX,BX;通用寄存器之间交换数据(16位)
XCHG ESI,EDI;通用寄存器之间交换数据(32位)
XCHG BX,/[SI/];通用寄存器和存储器之间交换数据(16位)
XCHG AL,/[BX/];通用寄存器和存储器之间交换数据(8位)
使用该指令应注意以下问题:
·操作数OPR1和OPR2不允许同为存储器操作数;
·操作数数据类型必须一致;
·交换指令不影响标志位。
如要实现存储器操作数交换,可用如下指令实现:
MOV AL,BLOCK1
XCHG AL,BLOCK2
MOV BLOCK1,AL
(2) 格式:BSWAP REG
功能:将32位通用寄存器中,第1个字节和第4个字节交换,第2个字节和第3个字节交换。
例 3.18
MOV EAX,44332211H
BSWAP EAX;EAX=11223344H
使用该指令应注意以下问题:
·操作数为32位通用寄存器;
·交换指令不影响标志位。
二、堆栈操作指令
1压栈指令
(1) 格式:PUSH SRC
功能:将源操作数压下堆栈,源操作数允许为16位或32位通用寄存器、存储器和立即数以及16位段寄存器。当操作数数据类型为字类型,压栈操作使SP值减2;当数据类型为双字类型,压栈操作使SP值减4。
例 3.19
PUSH AX          ;通用寄存器操作数入栈(16位)
PUSH EBX          ;通用寄存器操作数入栈(32位)
PUSH [SI]         ;存储器操作数入栈(16位)
PUSH DWORD PTR [DI]    ;存储器操作数入栈(32位)
PUSHW 0A123H        ;立即数入栈(16位)
PUSHD 20H         ;立即数入栈(32位)
(2) 格式:PUSHA
PUSHAD
功能:PUSHA将16位通用寄存器压入堆栈,压栈顺序为AX,CX,DX,BX,SP,BP,SI,DI。
PUSHAD将32位通用寄存器压入堆栈,压栈顺序为EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI。
2出栈指令
(1) 格式:POP DEST
功能:从栈顶弹出操作数送入目的操作数。目的操作数允许为16或32位通用寄存器、存储器和16位段寄存器。当操作数数据类型为字类型,出栈操作使SP加2;当操作数数据类型为双字类型,出栈操作使SP加4。
例 3.20
POP AX          ;操作数出栈送寄存器(16位)
POP ECX          ;操作数出栈送寄存器(32位)
POP [BX]         ;操作数出栈送存储器(16位)
POP DWORD PTR [SI]    ;操作数出栈送存储器(32位)
(2) 格式:POPA
POPAD
功能:POPA从堆栈移出16字节数据,并且按顺序存入寄存器DI,SI,BP,SP,BX,DX,CX,AX中。
POPAD从堆栈移出32字节数据,并且按顺序存入寄存器EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX中。
使用堆栈操作指令应注意以下问题。
(1) 目的操作数不允许为CS以及立即数。
(2) 堆栈操作指令不影响标志位。
三、地址传送指令
(1) 格式:LEA REG,MEM
功能:将源操作数的有效地址传送到通用寄存器,操作数REG为16位或32位通用寄存器,源操作数为16位或32位存储器操作数。
例 3.21
LEA BX,BLOCK;将BLOCK的有效地址传送到BX中(16位)
LEA EAX,/[EBX/];将EBX内容(有效地址)传送到EAX中(32位)
(2) 格式LDS(ES,FS,GS,SS)REG,MEM
功能:根据源操作数指定的偏移地址,在数据段中取出段地址和偏移地址分别送指定的段寄存器和指定的通用寄存器。
例 3.22
LES BX,[SI]        ;将32位地址指针分别送ES和BX
LSS EAX,[EDI]       ;将48位地址指针分别送SS和EAX
例 3.23
DATA1  DD buff
LDS BX,DATA1;将buff的32位地址指针分别送DS和BX
地址传送指令对标志位无影响。
四、标志寄存器传送指令
(1) 格式:LAHF
SAHF
功能:LAHF将标志寄存器中低8位送AH中。SAHF将AH中内容送标志寄存器中低8位。
(2) 格式:PUSHF
POPF
功能:PUSHF将标志寄存器低16位内容压入堆栈,SP←SP-2。POPF将当前栈顶一个字传送到标志寄存器低16位中,SP←SP+2。
(3) 格式:PUSHFD
POPFD
功能:PUSHFD将标志寄存器32位内容压入堆栈SP←SP-4。POPFD将当前栈顶一个双字传送到32位标志寄存器中,SP←SP+4。
上述SAHF,POPF,POPFD均影响相应的标志寄存器内容。
五、查表指令
格式:XLAT
功能:将寄存器AL中的内容转换成存储器表格中的对应值。实现直接查表功能。
XLAT指令规定:BX寄存器存放表的首地址,AL寄存器中存放表内偏移量,执行XLAT指令,以段寄存器DS的内容为段基址,有效地址为BX和AL内容之和,取出表中一个字节内容送AL中。
例 3.24内存中有一起始地址为TABLE的编码表,试编程将表中顺序号为4的存储单元内容送寄存器AL。
·MODEL SMALL
·DATA
TABLE      DB 11H,22H,33H,44H,55H 某编码表
·CODE
·STARTUP
MOV AL,4           ;AL←4
MOV BX,OFFSET TABLE     ;BX←TABLE表首地址
XLAT             ;结果在AL中,AL=55H
·EXIT
END
查表指令不影响标志位。
六、符号扩展指令
(1) 格式:CBW
功能:将AL中8位带符号数,进行带符号扩展为16位,送AX中。带符号扩展是指对正数高位扩展为全“0”,对负数高位扩展为全“1”。
例 3.25AL=55H 经CBW扩展后 AX=0055H
AL=A5H 经CBW扩展后 AX=FFA5H
(2) 格式:CWD
功能:将AX中16位带符号数,进行带符号扩展为32位,送DX和AX中。高16位送DX中,低16位送AX中。
(3) 格式:CWDE
功能:将AX中16位带符号数,进行带符号扩展为32位,送EAX中。
(4) 格式:CDQ
功能:将EAX中32位带符号数,进行带符号扩展为64位,送EDX和EAX中。低32位送EAX中,高32位送EDX中。
符号扩展指令对标志位无影响。
3.3.2 算术运算指令
80x86指令包括加、减、乘、除四种基本算术运算操作及十进制算术运算调整指令。二进制加、减法指令,带符号操作数采用补码表示时,无符号数和带符号数据运算可以使用相同的指令。二进制乘、除法指令分带符号数和无符号数运算指令。
一、加法指令
格式:ADDDEST,SRC
ADCDEST,SRC
功能:ADD是将源操作数与目的操作数相加,结果传送到目的操作数。ADC是将源操作数与目的操作数以及CF(低位进位)值相加,结果传送到目的操作数。
源操作数可以是通用寄存器、存储器或立即数。目的操作数可以是通用寄存器或存储器操作数。
ADD,ADC指令影响标志位为OF,SF,ZF,AF,PF,CF。
例 3.26
MOV AX,9876H
ADD AH,AL;AX=0E76H CF=1 SF=0O F=0 ZF=0 AF=0 PF=0
ADC AH,AL;AX=8576H CF=0 SF=1O F=1 ZF=0 AF=1 PF=0
二、减法指令
格式:SUB DEST,SRC
SBB DEST,SRC
功能:SUB将目的操作数减源操作数,结果送目的操作数。SBB将目的操作数减源操作数,还要减CF(低位借位)值,结果送目的操作数。
源操作数可以是通用寄存器、存储器或立即数。目的操作数可以是通用寄存器或存储器操作数。
SUB,SBB指令影响标志位为OF,SF,ZF,AF,PF,CF。
例 3.27
MOV AX, 9966H;AX=9966H
SUB AL, 80H;AL=E6HCF=1SF=1OF=1ZF=0AF=0PF=0
SBB AH, 80H;AH=18HCF=0SF=0OF=0ZF=0AF=0PF=1
三、加1减1指令
格式:INC DEST
DEC DEST
功能:INC指令将目的操作数加1,结果送目的操作数。DEC指令将目的操作数减1,结果送目的操作数。目的操作数为通用寄存器或存储器操作数。
INC,DEC指令影响标志位为OF,SF,ZF,AF,PF。
例 3.28
INC BL;BL←BL+1
INC AX;AX←AX+1
INC WORDPTR [BX];存储器操作数加1
DEC BYTE PTR [SI];存储器操作数减1
DEC EAX;EAX←EAX-1
四、比较指令
(1) 格式:CMP DEST,SRC =============这个是intel格式
功能:目的操作数减源操作数,结果不回送。源操作数为通用寄存器、存储器和立即数。目的操作数为通用寄存器、存储器操作数。
CMP指令影响标志位为OF,SF,ZF,AF,PF,CF。
例 3.29
CMP CX,3
CMP WORD PTR [SI],3
CMP AX,BLOCK
执行比较指令后,对状态标志位影响见表3.2。对于两个数的比较(AX-BX)有以下3种情况。
表 3.2 CMP指令对标志位的影响
· 两个正数比较,使用SF标志位判断。
SF=0,则AX≥BX,若ZF=1,则AX=BX
SF=1,则AX<BX
· 两个无符号数比较,使用CF标志位判断。
CF=0,则AX≥BX,若ZF=1,则AX=BX
CF=1,则AX<BX
· 两个负数比较,使用SF标志位判断。
SF=0,则AX≥BX,若ZF=1,则AX=BX
SF=1,则AX<BX
· 两个异符号数比较。
如果OF=0,仍可用SF标志判断大小。
如果OF=1,说明结果的符号位发生错误,所以
SF=0,则AX<BX
SF=1,则AX>BX
综上所述:两个异号数比较
当OF=0,SF=0,则AX>BX
SF=1,则AX<BX
当OF=1,SF=0,则AX<BX
SF=1,则AX>BX
用逻辑表达式表示为:
若OF∨-SF=0,则AX>BX
若OF∨-SF=1,则AX<BX
(2) 格式:CMPXCHGDEST,REG
功能:目的操作数减源操作数,
如果DEST=SRC,则SRC→DEST。
如果DEST≠SRC,则DEST→ACC(AL,AX,EAX)。
源操作数允许为通用寄存器。目的操作数可以为通用寄存器,存储器操作数。
CMPXCHG影响标志位为OF,SF,ZF,AF,PF,CF。
(3) 格式:CMPXCHG8BMEM
功能:EDX:EAX中值减存储器操作数。
如果EDX:EAX=MEM64,则ECX:EBX→MEM64。
如果EDX:EAX≠MEM64,则MEM64→EDX:EAX。
该指令为64位比较交换指令,影响ZF标志位。
例 3.30  CMPXCHG8BQWORDPTR[EBX]
五、交换相加指令
格式:XADDDEST,REG
功能:目的操作数加源操作数,结果送目的操作数。原目的操作数内容送源操作数。源操作数允许为通用寄存器。目的操作数允许为通用寄存器、存储器操作数。
XADD指令影响标志位为OF,SF,ZF,AF,PF,CF。
六、求补指令
格式:NEGDEST
功能:对目的操作数求补,用零减去目的操作数,结果送目的操作数。目的操作数为通用寄存器、存储器操作数。
NEG指令影响标志位为OF,SF,ZF,AF,PF,CF。
七、乘法指令
(1) 格式:MULSRC
IMULSRC
功能:MUL为无符号数乘法指令,IMUL为带符号数乘法指令。源操作数为通用寄存器或存储器操作数。目的操作数缺省存放在ACC(AL,AX,EAX)中,乘积存AX,DX:AX,EDX:EAX中。
字节乘:ALSRC→AX
字乘:AXSRC→DX∶AX
双字乘:EAXSRC→EDX∶EAX
MUL,IMUL指令执行后,CF=OF=0,表示乘积高位无有效数据;CF=OF=1表示乘积高位含有效数据,对其它标志位无定义。
例 3.31
MUL BL;字节乘
MUL WORD PTR [SI];字乘
IMUL BYTE PTR [DI];字节乘
IMUL DWORD PTR [ECX];双字乘
如果使用IMUL指令,积采用补码形式表示。
(2) 格式:IMULDEST,SRC
功能:将目的操作数乘以源操作数,结果送目的操作数。目的操作数为16位或32位通用寄存器或存储器操作数。源操作数为16位或32位通用寄存器、存储器或立即数。
源操作数和目的操作数数据类型要求一致。乘积仅取和目的操作数相同的位数,高位部分将被舍去,并且CF=OF=1。其它标志位无定义。
(3) 格式:IMUL DEST,SRC1,SRC2
功能:将源操作数SRC1与源操作数SRC2相乘,结果送目的操作数。目的操作数DEST为16位或32位,允许为通用寄存器。源操作数SRC1为16位或32位通用寄存器或存储器操作数。源操作数SRC2允许为立即数。
例 3.32  IMULEAX,[EBX],12H
要求目的操作数和源操作数SRC1类型相同,当乘积超出目的操作数部分,将被舍去,并且使CF=OF=1,在使用这类指令时,需在IMUL指令后加一条判断溢出的指令,溢出时转错误处理执行程序。
八、除法指令
格式:DIV SRC
IDIV SRC
功能:DIV为无符号数除法,IDIV为带符号数除法。源操作数作为除数,为通用寄存器或存储器操作数。被除数缺省在目的操作数AX,DX:AX,EDX:EAX中。
字节除法:AX/SRC商→AL,余数→AH
字除法:DX·AX/SRC商→AX,余数→DX
双字除法:EDX·EAX/SRC商→EAX,余数→EDX
由于被除数必须是除数的双倍字长,一般应使用扩展指令进行高位扩展。当进行无符号数除法时,被除数高位按0扩展为双倍除数字长。当进行有符号数除法时,被除数以补码表示。可使用扩展指令CBW,CWD,CWDE,CDQ进行高位扩展。例如:
MOV AX,BLOCK
CWD;被除数高位扩展
MOV BX,1000H
IDIV BX
对于带符号除法,其商和余数均采用补码形式表示,余数与被除数同符号。当除数为零或商超过了规定数据类型所能表示的范围时,将会出现溢出现象,产生一个中断类型码为“0”的中断。执行除法指令后标志位无定义。
九、BCD算术运算
十进制数在机器中采用BCD码表示,以压缩格式存放,即一个字节存储2位BCD码,BCD加减法是在二进制加减运算的基础上,对其二进制结果进行调整,将结果调整成BCD码表示形式。
(1) 格式:DAA
功能:将存放在AL中的二进制和数,调整为压缩格式的BCD码表示形式。
调整方法:若AL中低4位大于9或标志AF=1(表示低4位向高4位有进位),则
AL+6→AL,1→AF,
若AL中高4位大于9,或标志CF=1,(表示高4位有进位),则
AL+60H→AL,1→CF,
DAA指令一般紧跟在ADD或ADC指令之后使用,影响标志位为SF,ZF,AF,PF,CF。OF无定义。
例 3.33
ADD AL,BL
DAA
(2) 格式:DAS
功能:将存放在AL中的二进制差数,调整为压缩的BCD码表示形式。
调整方法:若AL中低4位大于9或标志AF=1(表示低4位向高位借位),则
AL-6→AL,1→AF
若AL中高4位大于9或标志CF=1(表示高4位向高位借位),则
AL-60H→AL,1→CF
DAS指令一般紧跟在SUB或SBB指令之后使用,影响标志位为SF,ZF,AF,PF,CF。OF无定义。
例 3.34
SUB AL,BL
DAS
十、ASCII算术运算
数字0~9的ASCII码为30H~39H,机器采用一个字节存放一位ASCII码,对于ASCII码的算术运算是在二进制运算基础上进行调整。调整指令有加、减、乘、除四种调整指令。
(1) 格式:AAA
功能:将存放在AL中的二进制和数,调整为ASCII码表示的结果。
调整方法:若AL中低4位小于或等于9,仅AL中高4位清0,AF→CF。若AL中低4位大于9或标志AF=1(进位),则AL+6→AL,AH+1→AH,1→AF,AF→CF,AL中高4位清0。
AAA指令一般紧跟在ADD或ADC指令之后使用,影响标志位为AF,CF。其它标志位无定义。
例 3.35
MOV AX,0036H
ADD,AL,35H
AAA;AX=0101H
(2) 格式:AAS
功能:将存放在AL中的二进制差数,调整为ASCII码表示形式
调整方法:若AL中低4位小于等于9,仅AL中高4位清0,AF→CF。若AL中低4位大于9或标志AF=1,则AL-6→AL,AH-1→AH,1→AF,AF→CF,AL中高4位清0。
AAS指令一般紧跟在SUB,SBB指令之后使用,影响标志位为AF,CF。其它标志位无定义。
例 3.36
MOV AX,0132H
SUB AL,35H
AAS;AX=0007H
(3) 格式:AAM
功能:将存放在AL中的二进制积数,调整为ASCII码表示形式。
调整方法:AL/10商→AH,余数→AL
AAM指令一般紧跟在MUL指令之后使用,影响标志位为SF,ZF,PF。其它标志位无定义。
例 3.37
MOV AL,07H
MOV BL,09H
MUL BL;AX=003FH
AAM;AX=0603H
(4) 格式:AAD
功能:将AX中两位非压缩BCD码(一个字节存放一位BCD码),转换为二进制数的表示形式。
调整方法:AH10+AL→AL0→AH
AAD指令用于二进制除法DIV操作之前,影响的标志位为SF,ZF,PF。其它标志位无定义。
例 3.38
MOV AX,0605H
MOV BL,09H
AAD;AX=0041H
DIV BL;AX=0207H
使用该类指令应注意,加法、减法和乘法调整指令都是紧跟在算术运算指令之后,将二进制的运算结果调整为非压缩BCD码表示形式,而除法调整指令必须放在除法指令之前进行,以避免除法出现错误的结果。
使用算术运算类指令应注意:
·如果没有特别规定,参与运算的两个操作数数据类型必须一致,且只允许一个为存储器操作数;
·如果参与运算的操作数只有一个,且为存储器操作数,必须使用PTR伪指令说明数据类型;
·操作数不允许为段寄存器。
·目的操作数不允许为立即数;
·如果是存储器寻址,则存储器各种寻址方式均可使用。
3.3.3逻辑运算指令
一、逻辑指令
1逻辑与指令
格式:AND DEST,SRC
功能:目的操作数和源操作数按位进行逻辑与运算,结果存目的操作数中。源操作数可以是通用寄存器、存储器或立即数。目的操作数可以是通用寄存器或存储器操作数。
例 3.39
AND AL,BL
AND EBX,ECX
AND [DI],1101H
AND指令常用于将操作数中某位清0(称屏蔽),只须将要清0的位与0,其它不变的位与1即可。
例 3.40  AND AL,0FH;将AL中高4位清0,低4位保持不变。
AND指令影响标志位为SF,ZF,PF,并且使OF=CF=0。
2逻辑或指令
格式:OR DEST,SRC
功能:目的操作数和源操作数按位进行逻辑或运算,结果存目的操作数中。源操作数可以是通用寄存器、存储器或立即数。目的操作数可以是通用寄存器或存储器操作数。
例 3.41
OR AX,BX
OR ECX,[EAX]
OR指令常用于将操作数中某位置1,只须将要置1的位或1,其它不改变的位或0即可。
例 3.42  OR AL,80H;将AL中最高位置1。
OR指令影响标志位为SF,ZF,PF。并且使OF=CF=0。
3逻辑异或指令
格式:XOR DEST,SRC
功能:目的操作数和源操作数按位进行逻辑异或运算,结果送目的操作数。源操作数可以是通用寄存器、存储器或立即数。目的操作数可以是通用寄存器或存储器操作数。
例 3.43
XOR AX,BX
XOR [BX],1010H
XOR指令常用于将操作数中某些位取反,只须将要取反的位异或1,其它不改变的位异或0即可。
例 3.44  XOR AL,OFH;将AL中低4位取反,高4位保持不变。
XOR指令影响标志位为SF,ZF,PF,并且使OF=CF=0。
4逻辑非指令
格式:NOT DEST
功能:对目的操作数按位取反,结果回送目的操作数。目的操作数可以为通用寄存器或存储器。
例 3.45
NOT EAX
NOT BYTE PTR [BX]
NOT指令对标志位无影响。
5测试指令
格式:TEST DEST,SRC
功能:目的操作数和源操作数按位进行逻辑与操作,结果不回送目的操作数。源操作数可以为通用寄存器、存储器或立即数。目的操作数可以为通用寄存器或存储器操作数。
例 3.46
TEST DWORD PTR [BX],80000000H
TEST AL,CL
TEST指令常用于测试操作数中某位是否为1,而且不会影响目的操作数。如果测试某位的状态,对某位进行逻辑与1的运算,其它位逻辑与0,然后判断标志位。运算结果为0,ZF=1,表示被测试位为0;否则ZF=0,表示被测试位为1。
例 3.47  TEST AL,80H;测试AL中最高位
JNZ NEXT;如果最高位为1,转到标志NEXT处。
TEST指令影响标志位为SF,ZF,PF,并且使OF=CF=0。
二、移位指令
移位指令对操作数按某种方式左移或右移,移位位数可以由立即数直接给出,或由CL间接给出。移位指令分一般移位指令和循环移位指令。
1一般移位指令
(1) 算术/逻辑左移指令。
格式:SAL DEST,OPRD
SHL DEST,OPRD
功能:按照操作数OPRD规定的移位位数,对目的操作数进行左移操作,最高位移入CF中。每移动一位,右边补一位0。如图312(a)所示。目的操作数可以为通用寄存器或存储器操作数。
SAL,SHL指令影响标志位OF,SF,ZF,PF,CF。
图 3.12  移位指令示意图
例 3.48
SHL BYTE PTR [DI],2
SAL BX,CL
(2) 算术右移指令。
格式:SAR DEST,OPRD
功能:按照操作数OPRD规定的移位次数,对目的操作数进行右移操作,最低位移至CF中,最高位(即符号位)保持不变。如图312(b)所示。目的操作数可以为通用寄存器或存储器操作数。
SAR指令影响标志位OF,SF,ZF,PF,CF。
例 3.49
SAR AL,5
SAR WORD PTR /[ECX/],CL
(3) 逻辑右移指令。
格式:SHR DEST,SRC
功能:按照操作数OPRD规定的移位位数,对目的操作数进行右移操作,最低位移至CF中。每移动一位,左边补一位0。如图312(c)所示,目的操作数可以为通用寄存器或存储器操作数。
SHR指令影响标志位OF,SF,ZF,PF,CF。
例 3.50
SHR BYTE PTR [SI],3
SHR EDX,CL
算术/逻辑左移,只要结果未超出目的操作数所能表达的范围,每左移一次相当于原数乘2。算术右移只要无溢出,每右移一次相当于原数除以2。
2循环移位指令
格式:ROL DEST,OPRD
ROR DEST,OPRD
RCL DEST,OPRD
RCR DEST,OPRD
功能:循环左移指令ROL,见图313(a)所示,目的操作数左移,每移位一次,其最高位移入最低位,同时最高位也移入进位标志CF。循环右移指令 ROR见图313(b)所示,目的操作数右移,每移位一次,其最低位移入最高位,同时最低位也移入进位标志CF。
带进位循环左移指令RCL,见图313(c)所示,目的操作数左移,每移动一次,其最高位移入进位标志CF,CF移入最低位。带进位循环右移指令RCR,见图313(d)所示,目的操作数右移,每移动一次,其最低位移入进位标志CF,CF移入最高位。
图 3.13  循环移位指令
目的操作数可以为通用寄存器或存储器操作数。循环移位指令影响标志位CF,OF。其它标志位无定义。
例 3.51
ROL AL,CL
ROR BX,5
RCL ECX,3
RCR BYTE PTR [SI],CL
例 3.52  将一个2位数压缩的BCD码转换成二进制数。
·MODEL SMALL
·DATA
BCD DB 01011001B
BIN DB?
CODE
·START UP
MOV AL,BCD
MOV BL,AL
AND BL,0FH
AND AL,0F0H
MOV CL,4
ROR AL,CL
MOV BH,0AH
MUL BH
ADD AL,BL
MOV BIN,AL
·EXIT
END
3双精度移位指令
格式:SHLD DEST,SRC,OPRD
SHRD DEST,SRC,OPRD
功能:对于由目的操作数DEST和源操作数SRC构成的双精度数,按照操作数OPRD给出的移位位数,进行移位。SHLD是对目的操作数进行左移,如 图314(a)所示,SHRD是对目的操作数进行右移,如图314(b)所示。先移出位送标志位CF,另一端空出位由SRC移入DEST中,而SRC 内容保持不变。目的操作数可以是16位或32位通用寄存器或存储器操作数。源操作数SRC允许为16位或32位通用寄存器。操作数OPRD可以为立即数或 CL。目的操作数和源操作数SRC数据类型必须一致。
图 3.14  双精度移位指令
SHLD,SHRD指令常用于位串的快速移位、嵌入和删除等操作,影响标志位为SF,ZF,PF,CF,其它标志位无定义。
三、位操作指令
位操作指令包括位测试和位扫描指令,可以直接对一个二进制位进行测试,设置和扫描。
1位测试和设置指令
格式: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中该位复位。BTS将SRC指定的DEST中一位的数值复制到CF,且将DEST中该位置位。
目的操作数为16位或32位通用寄存器或存储器,源操作数为16位或32位通用寄存器,以及8位立即数,当源操作数为通用寄存器时,必须同目的操作数类型一致。源操作数SRC以两种方式给出目的操作数的位号,即
· SRC为8位立即数,以二进制形式直接给出要操作的位号;
· SRC为通用寄存器,如果DEST为通用寄存器,则SRC中二进制值直接给出要操作的位号。如果DEST为存储器操作数,通用寄存器SRC为带符号整数, SRC的值除以DEST的长度所得到的商作为DEST的相对偏移量,余数直接作为要操作的位号。DEST的有效地址为DEST给出的偏移地址和DEST相 对偏移量之和。
BT,BTC,BTR,BTS指令影响CF标志位,其它标志位无定义。
例 3.53
MOV AX,1234H
MOV ECX,5
BT AX,CX       ;CF=1AX=1234H
BTC AX,5       ;CF=1;AX=1214H
BTS AX,CX;      ;CF=0AX=1234H
BTR EAX,ECX      ;CF=1EAX=00001214H
例 3.54
·MODEL SMALL
·586
·DATA
DATA1 DW 1234H,5678H
·CODE
·START UP
BTC DATA1,3;CF=0(DATA1)=123CH
MOV CX,20
BTR DATA1,CX;CF=1[DATA+2]=5668H
·EXIT
END
2位扫描指令
格式:BSFDEST,SRC
BSRDEST,SRC
功能:BSF从低位开始扫描源操作数,若所有位都是0,则ZF=0,否则ZF=1。并且将第一个出现1的位号存入目的操作数。BSR从高位开始扫描源操作数,若所有位都是0,则ZF=0,否则ZF=1。并且将第一个出现1的位号存入目的操作数。
源操作数可以为16位32位通用寄存器或存储器。目的操作数为16位或32位通用寄存器。源操作数和目的操作数类型必须一致。
BSF,BSR指令影响ZF标志位,其它标志位无定义。
例 3.55
MOV EBX,0F333EE00H
BSR EAX,EBX;ZF=1EAX=0000001FH=31
BSF EDX,EBX;ZF=1EDX=00000009H
3进位标志指令
(1) 格式:CLC。功能:清除进位标志。
(2) 格式:STC。功能:设置进位标志。
(3) 格式:CMC。功能:进位标志取反。
4条件设置字节指令
条件设置指令用于根据条件设置某一状态字节或标志字节,见表33。
格式:SETcondDEST
功能:测试条件(cond)若为真,则将目的操作数置01H,否则置00H。目的操作数允许为8位通用寄存器或8位存储器操作数。
条件cond与条件转移指令中的条件相同,共分三类。
(1) 以标志位状态为条件可以测试的标志位为ZF,SF,OF,CF,PF。
(2) 以两个无符号数比较为条件条件为高于、高于等于、低于、低于等于。
(3) 以两个带符号数比较为条件条件为大于、大于等于、小于、小于等于。
SET指令不影响标志位。
使用逻辑运算类指令应注意:
· 如果没有特别规定,参与运算的两个操作数类型必须一致,且只允许一个为存储器操作数;
· 如果参与运算的操作数只有一个,且为存储器操作数,必须使用PTR伪指令说明其数据类型;
· 操作数不允许为段寄存器;
· 目的操作数不允许为立即数;
· 如果是存储器寻址,则前面介绍的各种存储器寻址方式均可使用。
表 3.3  条件设置字节指令
3.3.4控制转移类指令
计算机执行程序一般是顺序地逐条执行指令。但经常须要根据不同条件做不同的处理,有时需要跳过几条指令,有时需要重复执行某段程序,或者转移到另一个程序段去执行。用于控制程序流程的指令包括转移、循环、过程调用和中断调用。
一、转移指令
1无条件转移指令
格式:JMP TARGET
功能:使程序无条件地转移到指令规定的目的地址TARGET去执行指令。转移分为短转移、段内转移(近程转移)和段间转移(远程转移)。
(1) 段内直接转移:
格式:JMP SHORT TARGET;短转移
JMP NEAR PTR TARGET;近程转移
功能:采用相对寻址将当前IP值(即JMP指令下一条指令的地址)与JMP指令中给出的偏移量之和送IP中。段内短转移(SHORT)指令偏移量为8 位,允许转移偏移值的范围为-128~+127。段内近程转移(NEAR)指令在16位指令模式下,偏移量为16位,允许转移偏移值范围为-215~+ 215-1。在32位指令模式下,偏移值范围为-231~+231-1。
例 3.56
JMP NEXT
NEXT:MOV AL,BL
本例为无条件转移到本段内,标号为NEXT的地址去执行指令,汇编程序可以确定目的地址与JMP指令的距离。
(2) 段内间接转移:
格式:JMP REG
JMP NEAR PTR [REG]
功能:段内间接转移,其中JMP REG指令地址在通用寄存器中,将其内容直接送IP实现程序转移。JMP NEAR PTR [REG]指令地址在存储器中,默认段寄存器根据参与寻址的通用寄存器来确定,将指定存储单元的字取出直接送IP实现程序转移。在16位指令模式,转移偏 移值范围为
。在32位指令模式,转移偏移值范围为
例 3.57 设DS=1000HEBX=00002000H。
JMP BX          ;将2000H送IP
JMP NEAR PTR [BX]     ;将地址1000∶2000单元存放的一个字送IP
JMP NEAR PTR [EBX]    ;将段选择符为1000H,偏移地址为00002000H单元存放的双字送EIP。
(3) 段间直接转移:
格式:JMP FAR PTR TARGET
功能:段间直接转移,FAR PTR说明标号TARGET具有远程属性。将指令中由TARGET指定的段值送CS,偏移地址送IP。
例 3.58 JMP FAR PTR NEXT。
在16位指令模式下,段基地送CS,偏移地址为16位,转移偏移值范围
;在32位指令模式下,代码段选择符送CS,偏移地址为32位,转移偏移值范围为
(4) 段间间接转移:
格式:JMP FAR PTR [Reg]
功能:段间间接转移,由FAR PTR [Reg]指定的存储器操作数作为转移地址。
在16位指令模式下,存储器操作数为32位,包括16位段基址和16位偏移地址。
例 3.59
JMP FAR PTR [BX]      ;数据段双字存储单元低字内容送IP
;数据段双字存储单元高字内容送CS
在32位指令模式下,存储器操作数包括16位选择符。
例 3.60  JMP FAR PTR [EAX]
指令中包含指向目标地址指针的门描述符或TSS描述符的指针,其所指的存储器操作数中仅选择符部分有效,指示调用门、任务门或TSS描述符起作用,而偏移部分不起作用。
2条件转移指令
该类指令是根据上一条指令对标志寄存器中标志位的影响来决定程序执行的流程,若满足指令规定的条件,则程序转移;否则程序顺序执行。
条件转移指令的转移范围为段内短转移或段内近程转移,不允许段间转移。段内短转移(short)的转移偏移值范围为-128~+127。段内近程转移,在16位指令模式下转移偏移值范围为
,在32位指令模式下转移偏移值范围为
条件转移指令包括四类:单标志位条件转移;无符号数比较条件转移;带符号数比较条件转移;测试CX条件转移。
格式:Jcc TARGET
功能:若测试条件‘CC’为真,则转移到目标地址TARGET处执行程序。否则顺序执行。
(1) 单标志位条件转移指令,见表34。
例 3.61 JZ NEXT;若标志ZF=1则转移到标号NEXT处执行。
(2) 无符号数比较条件转移,见表35。
例 3.62 JA NEXT;无符号数A与B比较,若A>B则转移到标号NEXT处执行程序
表 3.4 单标志位条件转移指令
表 3.5 无符号数比较条件转移指令
表 3.6 带符号数比较条件转移指令
例 3.63  JG NEXT;带符号数A与B比较,若A>B则转移到标号NEXT。
(4) 测试CX条件转移,见表37。
表 3.7 测试CX条件转移指令
例 3.64 JCXZ TARGET;CX=0转移到标号TARGET处。
JECXZ TARGET;ECX=0转移到标号TARGET处。
条件转移指令一般紧跟在CMP或TEST指令之后,判断执行CMP或TEST指令对标志位的影响来决定是否转移。
例 3.65 符号函数
假设x为某值且存放在寄存器AL中,试编程将求出的函数值f(x)存放在AH中。
·MODEL TINY
·CODE
·STARTUP
CMPAL,0
JGE BIG
MOV AL,0FFH
JMP DONE
BIG: JE DONE
MOV AL,1
DONE:MOV AH,AL
·EXIT
END
例 3.66 编程实现把BX寄存器内的二进制数用十六进制数的形式在屏幕上显示出来。
·MODEL TINY
·CODE
·STARTUP
MOV CH,4
AGAIN: MOV CL,4
ROL BX,CL
MOV AL,BL
ANDAL,0FH
OR AL,30H
CMP AL,3AH
JB NEXT
ADD AL,07H
NEXT: MOV DL,AL;DL←要显示的ASCII码
MOV AH,2;显示
INT 21H
DECCH
JNZ AGAIN
·EXIT
END
二、循环控制指令
这类指令用(E)CX计数器中的内容控制循环次数,先将循环计数值存放在(E)CX中,每循环一次(E)CX内容减1,直到(E)CX为0时循环结束。
格式:LOOPcc TARGET
功能:将(E)CX内容减1,不影响标志位,若(E)CX不等于0,且测试条件‘CC’成立,则转移到目标地址TARGET处执行程序。转移范围为-128~+127。如表38所示。
表3.8 循环控制指令
例 3.67 计算
·MODEL TINY
·CODE
·STARTUP
XOR EAX,EAX
MOV EDX,1
MOV ECX,1000
SUM:  ADD EAX,EDX
INC EDX
LOOPD SUM
·EXIT
END
例 3.68 找出以ARRAY为首地址的100个字数组中的第一个非0项,送AX寄存器中。
·MODELSMALL
·DATA
ARRAYDW 0,0,0,0,1010H,…;(100个字)
·CODE
·STARTUP
MOV CX,64H
LEA BX,ARRAY
MOV SI,0FFFEH
ZERO: INC SI
INC SI
CMP WORD PTR [BX+SI],0
LOOPZ ZERO
MOV AX,[BX+SI]
·EXIT
END
关于过程调用和返回指令将在子程序一节中介绍。
3.3.5串操作指令
80x86提供处理字符串的操作。串指连续存放在存储器中的一些数据字节、字或双字。串操作允许程序对连续存放大的数据块进行操作。
串操作通常以DS:(E)SI来寻址源串,以ES:(E)DI来寻址目的串,对于源串允许段超越。(E)SI或(E)DI这两个地址指针在每次串操作 后,都自动进行修改,以指向串中下一个串元素。地址指针修改是增量还是减量由方向标志来规定。当DF=0,(E)SI及(E)DI的修改为增量;当DF= 1,(E)SI及(E)DI的修改为减量。根据串元素类型不同,地址指针增减量也不同,在串操作时,字节类型SI,DI加、减1;字类型SI,DI加、减 2;双字类型ESI,EDI加、减4。如果需要连续进行串操作,通常加重复前缀。重复前缀可以和任何串操作指令组合,形成复合指令,见表39。
一、重复前缀指令
表 3.9 重复前缀指令
二、方向标志指令
格式:CLD/STD
功能:CLD为清除方向标志,即将DF置‘0’。STD为设置方向标志,即将DF置‘1’。
三、串传送指令
基本格式:[REP]MOVS DESTS, SRCS
[REP] MOVSB/MOVSW/MOVSD
功能:将DS:(E)SI规定的源串元素复制到ES:(E)DI规定的目的串单元中,见表310。
表 3.10 MOVS指令
该指令对标志位无影响。
如果加重复前缀REP,则可以实现连续存放的数据块的传送,直到(E)CX=0为止。
在16位指令模式下,使用SI,DI,CX寄存器;在32位指令模式下,使用ESI,EDI,ECX寄存器。
例 3.69
·MODEL SMALL
·DATA
SRC  DB 1,2,3,…(100个字节)
DEST DB 100DUP(?)
·CODE
·STARTUP
MOV AX,@DATA
MOV ES,AX
MOV CX,100
LEA SI,SRC
LEA DI,DEST
CLD
REP MOVSB
·EXIT
END
该程序将起始地址为SRC的100个字节内容传送到起始地址为DEST的存储单元。
四、串比较指令
基本格式:[REPE/Z] [REPNZ/NE] CMPS DESTS, SRCS
[REPE/Z] [REPNZ/NE] CMPSB/CMPSW/CMPSD
功能:由DS:(E)SI规定的源串元素减去ES:(E)DI指出的目的串元素,结果不回送,仅影响标志位CF,AF,PF,OF,ZF,SF。当源 串元素与目的串元素值相同时,ZF=1;否则ZF=0。每执行一次串比较指令,根据DF的值和串元素数据类型自动修改(E)SI和(E)DI。
在串比较指令前加重复前缀REPE/Z,则表示重复比较两个字符串,若两个字符串的元素相同则比较到(E)CX=0为止,否则结束比较。在串比较指令 前加重复前缀REPNE/NZ,则表示若两个字符串元素不相同时,重复比较直到(E)CX=0为止,否则结束比较。
例 3.70 编程实现两个串元素比较,如相同则将全“1”送SUT单元,否则全“0”送SUT单元。
·MODEL SMALL
·DATA
DEST DB ‘A B C D E F G H’
SRC  DB ‘A B C E F F F E’
SUT  DB?
·CODE
·STARTUP
MOV AX,@DATA
MOV ES,AX
MOV CX,8
LEA SI,DEST
LEA DI,SRC
CLD
REPE CMPSB
JZ EQUL;ZF=1;CX=0
MOV BH,0;CX≠0,ZF=0
JMP DONE
EQUL: MOV BH,0FFH
DONE: MOV SUT,BH
·EXIT
END
五、串扫描指令
格式①: [REPE/Z] [REPNE/NZ] SCAS DESTS
格式②: [REPE/Z] [REPNE/NZ] SCASB/SCASW/SCASD
功能:由AL,AX或EAX的内容减去ES:(E)DI规定的目的串元素,结果不回送,仅影响标志位CF,AF,PF,SF,OF,ZF。当AL, AX或EAX的值与目的串元素值相同时,ZF=1;否则ZF=0。每执行一次串扫描指令,根据DF的值和串元素数据类型自动修改(E)DI。
在串扫描指令前加重复前缀REPE/Z,则表示目的串元素值和累加器值相同时重复扫描,直到CX/ECX=0为止,否则结束扫描。若加重复前缀 REPNE/NZ,则表示当目的串元素值与累加器值不相等时,重复扫描直到CX/ECX=0时为止,否则结束扫描。
该指令影响标志位为CF,AF,PF,SF,OF,ZF。
例 3.71 在内存DEST开始的6个单元寻找字符‘C’,如找到将字符‘C’的地址送ADDR单元,否则0送ADDR单元。
·MODEL SMALL
·DATA
DEST DB ‘A B C D E F’
ADDR DW?;存“C”的地址,所以设置为字类型
·CODE
·STARTUP
MOV AX,@DATA
MOV ES,AX
MOV CX,6
LEA DI,DEST
MOV AL,‘C’
CLD
REPNE SCASB
JZ EQUL
MOV DI,0
JMP DONE
EQUL: DEC DI
DONE: MOV ADDR,DI
·EXIT
END
六、 串装入指令
格式:LODS SRCS
LODSB/LODSW/LODSD
功能:将DS:SI/ESI所指的源串元素装入累加器(AL,AX,EAX)中,每装入一次都按照DF值以及串元素类型自动修改地址指针SI/ESI,该指令一般不须加重复前缀,并且不影响标志位。
七、 串存储指令
格式:[REP] STOS DESTS
[REP] STOSB/STOSW/STOSD
功能:将累加器/[AL,AX,EAX/]中值存入ES:DI/EDI所指的目的串存储单元中,每传递一次,都按DF值以及串元素类型自动修改地址指 针DI/EDI。若加重复前缀REP,则表示将累加器的值连续送目的串存储单元,直到CX/ECX=0时为止。
该指令不影响标志位。
3.3.6输入/输出指令
一、 输入指令
格式:IN DEST, SRC
功能:根据源操作数SRC给出的端口地址,将操作数从指定端口传送到目的操作数DEST处,其中DEST为AL,AX或EAX,端口地址SRC可以直接形式给出8位端口地址,或由DX寄存器以间接形式给出。
例 3.72
IN AL,10H
IN AX,20H
IN EAX,30H
IN AL,DX
IN AX,DX
IN EAX,DX
二、 输出指令
格式OUT DEST, SRC
功能:将源操作数SRC送到目的操作数DEST所指定的端口。其中源操作数SRC为AL,AX或EAX,目的操作数可以8位端口地址方式直接给出或以DX寄存器间接方式给出。
使用输入、输出指令应注意:
· 直接寻址方式端口地址为8位,共有0~255个端口地址;
· 间接寻址方式,只能用DX作为地址寄存器,寻址范围为64K字节;
· 每个I/O地址对应的端口的数据长度为8位,传送8位数据占用一个端口地址,传送16位数据占用2个端口地址,传送32位数据占用4个端口地址。
三、 串输入指令
格式:[REP] INS DESTS, DX
[REP] INSB/INSW/INSD
功能:根据DX给出的端口地址,从外设读入数据送入以ES:DI/EDI为地址的目的串存储单元中,每输入一次,均根据DF的值和串元素类型自动修改 DI/EDI的值。若加重复前缀REP,则表示连续从外设输入串元素存入目的串存储单元中,直到CX/ECX=0为止。
例 3.73 从端口地址为1000H处取数存入内存BLOCK单元。
·MODEL SMALL
·DATA
BLOCKDB?
·CODE
·STARTUP
MOV AX,@DATA
MOV ES,AX
CLD
LEA DI,BLOCK
MOV DX,1000H
INS BLOCK,DX
·EXIT
END
四、串输出指令
格式:[REP] OUTS DX,SRCS
[REP] OUTSB/OUTSW/OUTSD
功能:将DS:SI/ESI所指的源串元素,按照DX寄存器指定的端口地址送往外设,每输出一次,均根据DF的值和串元素类型自动修改SI/ESI的值,若加重复前缀REP,则表示连续向外设输出串元素,直到CX/ECX=0时为止。
例 3.74 将内存BLOCK为首地址的100个字符送往端口地址为2000H的外设。
·MODEL SMALL
·DATA
BLOCKDB ‘A,B,…’(100个字符)
·CODE
·STARTUP
CLD
LEA SI,BLOCK
MOV CX,100
MOV DX,2000H
REP OUTSB
·EXIT
END
在使用带重复前缀的串输入输出指令时,必须考虑端口的数据准备或接收状态。
所有输入输出指令均不影响标志位。
3.3.7处理器控制
一、 总线封锁前缀
格式:LOCK指令
功能:LOCK为指令前缀,可以使LOCK引脚变成逻辑0,在LOCK引脚有效期间,禁止外部总线上的其它处理器存取带有LOCK前缀指令的存储器操作数。
可加LOCK前缀的指令:
(1) ADD/SUB/ADC/SBB/OR/XOR/AND Mem, Reg/imm;
(2) NOT/NEG/INC/NEC Mem;
(3) XCHG Reg, Mem或XCHG Mem, Reg;
(4) BT/BTS/BRT/BTC Mem, Reg/imm。
Mem为存储器操作数,Reg为通用寄存器,imm为立即数。
二、空操作
格式:NOP
功能:空操作,除使IP/EIP增1外,不做任何工作。该指令不影响标志位。
三、处理器等待指令
格式:WAIT
功能:检查BUSY引脚状态,等待协处理器完成当前工作。
四、处理器暂停指令
格式:HLT
功能:暂停程序的执行。当产生一个外部中断或非屏蔽中断时,才继续执行下一条指令。
3.3.8中断指令与DOS功能调用
一、中断指令
在实模式下,中断矢量以4个字节存放在中断矢量表中,中断矢量表为1k字节(00000H~003FFH),中断矢量表允许存放256个中断矢量,每 个中断矢量包含一个中断服务程序地址(段值和16位偏移地址),中断矢量地址指针由中断类型码乘以4得到。
在保护模式下,用中断描述符表代替中断矢量表,每个中断由8个字节的中断描述符来说明,中断描述符表允许256个中断描述符,每个中断描述符包含一个中断服务地址(段选择符、32位偏移地址、访问权限等)。中断描述符地址指针由中断类型码乘以8得到。
中断指令格式:INT n
功能:产生中断类型码为n的软中断,该指令包含中断操作码和中断类型码两部分,中断类型码n为8位,取值范围为0~255(00H~FFH)。
软中断执行过程:
· 将标志寄存器FLAGS(或EFLAGS)压入堆栈;
· 清除TF和IF标志位;
· CS,IP/EIP压入堆栈;
· 实模式下,n×4获取中断矢量表地址指针;保护模式下,n×8获取中断描述符表地址指针;
· 根据地址指针,从中断矢量表或中断描述符表中取出中断服务程序地址送IP/EIP和CS中,控制程序转移去执行中断服务程序。
中断返回指令格式:IRET/IRETD
功能:该指令实现在中断服务程序结束后,返回到主程序中断断点处,继续执行主程序。
中断返回执行过程:
· IRET指令弹出堆栈中数据送IP,CS,FLAGS;
· IRETD指令弹出堆栈中数据送EIP,CS,EFLAGS。
其它中断类指令如表311所示。
表 3.11 中断类指令
二、DOS功能调用
系统功能调用是MS—DOS为程序员编写汇编语言源程序提供的一组子程序,包括设备管理、文件管理和目录管理等。
DOS规定使用软中断指令INT 21H作为进入各功能子程序的总入口,再为每个功能调用规定一个功能号,引用功能号即可进入相应的子程序入口。DOS系统功能调用的使用方法归纳如下:
(1) 传送入口参数到指定的寄存器中;
(2) 把要调用功能的功能号送入AH寄存器中;
(3) 用INT 21H指令转入子程序入口;
(4) 相应的子程序运行结束后,可以按照规定取得出口参数。
常用系统功能调用简介。
1键盘输入单字符
这是1号系统功能调用,其调用格式为
MOV AH,1
INT 21H
该功能调用无入口参数。其功能为系统等待键盘输入,如是Ctrol-Break键则退出;否则将键入字符的ASCII码送入AL寄存器中,并且通过显示器显示该字符。
2键盘输入字符串
这是0AH号系统功能调用,其功能为将键盘输入的字符串写入内存单元中。因此,首先在内存中定义一个缓冲区,缓冲区第一个字节存放规定字符串的最大字 节数,第二个字节由系统送入实际键入的字符数,从第三个字节开始用于存放键入的字符串,最后通过键入回车键来表示字符串的结束。如果实际键入的字符数未达 到最大规定数,其缓冲区的空余区间填0;如果实际键入数超过缓冲区的容量,则超出的字符自动丢失,而且响铃警告。注意,回车键值也存于缓冲区中。
例 3.75 使用格式举例。
·MODEL SMALL
·DATA
BUF  DB 20
DB?
DB 20 DUP(?)
·CODE
·STARTUP
MOV DX,OFFSET BUF
MOV AH,0AH
INT 21H
·EXIT
END
该程序在BUF为首地址的缓冲区定义了20个字符串字节的缓冲区,并且将缓冲区首地址送入DX中,调用0AH号子程序,系统等待用户键入字符串,每键 入一个字符,其相应的ASCII码将被写入缓冲区中,直到键入回车键,由系统输入实际键入字符数,送入缓冲区第二个字节中。
3输出单字符
这是2号系统功能调用,其使用格式为:
MOV DL,‘A’
MOV AH,2
INT 21H
执行2号系统功能调用,将置入DL寄存器中的字符(以ASCII码形式表示)通过显示器显示出来(或从打印机输出)。
4输出字符串
这是9号系统功能调用,其功能是将指定的内存缓冲区中的字符串从显示器显示输出(或从打印机输出),缓冲区中的字符串以字符‘$’作为结束标志。
例 3.76使用格式举例。
·MODEL SMALL
·DATA
BUF DB ‘Thank you $’
·CODE
·STARTUP
MOV DX,OFFSET BUF
MOV AH,9
INT 21H
·EXIT
END
5返回操作系统
这是4CH号系统功能调用,使用格式为
MOV AH,4CH
INT 21H
在用户程序结束处插入此调用,则返回到DOS操作系统,显示器显示系统提示符。
习题与思考题
1数据寻址方式有哪几种?
216位指令模式下和32位指令模式下的存储器寻址方式各有哪几种寻址方式?并比较它们相似与不同之处。
3程序地址寻址方式有哪几种?
4什么是堆栈地址寻址方式?
5指令编码格式是由哪几部分组成的?各部分的含义是什么?
6 80x86的指令格式由哪几部分组成?
7 80x86指令系统按其功能可分为几部分?
8数据传送指令包括哪些类型?
9堆栈的含义是什么?80x86所用的堆栈有什么特点?
10堆栈操作指令有哪几种?
11 XLAT指令在使用时有哪些规定?
12符号扩展指令在什么情况下使用?
13十进制算术运算调整指令在什么情况下使用?它们都是跟在哪些指令的后面?
14哪些指令采用隐含寻址?
15使用算术运算类指令应注意哪些问题?
16逻辑运算指令有几种?
17测试指令和比较指令在使用时有什么不同?
18算术移位指令和逻辑移位指令有什么不同?
19控制转移类指令的作用是什么?有哪几种?
20什么叫串?串操作指令有哪些?串前缀在什么情况下使用?
21输入/输出指令起什么作用?寻址方式有哪些?
22设DS=2000H,SS=3000H,BP=0200H,SI=4000H,BUF=1000H,EAX=00001000H,EBX= 00002000H,假设按16位实模式操作,确定下列每条指令访问内存的物理地址,并且指出源操作数及目的操作数的寻址方式。
(1) MOV AL,[1234H](2) MOV EDX,[BX]
(3) MOV CL,[BX+100H](4) MOV [SI],EBX
(5) MOV AH,BUF[BX+SI](6) MOV EAX,[BP+1234H]
(7) MOV [EAX+EBX],DH
23试指出下列指令中的错误。
(1) MOV [BX],[SI](2) MOV AH,DX
(3) INC [BX](4) MOV DS,SS
(5) XCHG AX,2000H(6) MOV AX,[BX+DX]
(7) XCHG [SP],ES(8) ADD [AX],BX
(9) MOV AX,DI+SI(10) INAL,BX
24指出下列算术逻辑指令执行后标志CF,ZF,SF,PF,OF和AF的状态。
MOV AL,80H
DEC AL
ADD AL,10H
SUB AL,10H
MOV AL,3AH
AND AL,0F0H
OR AL,0F0H
XOR AL,0F0H
25使AX寄存器清0有多种方式,试写出这多条指令。
26写出把首地址为BUF的字节缓冲区中第5个字节数送AL寄存器的指令,要求使用以下几种寻址方式:
(1) 寄存器间接寻址;
(2) 寄存器相对寻址;
(3) 基址变址寻址。
27试分别使用数据传送指令、交换指令和堆栈操作指令,实现将首地址为BLOCK的内存单元中两个数据字交换。BLOCK变量定义如下:
BLOCK DW 10H,20H
28设一个字节数据X存放在AL寄存器中,试说明下列程序的功能。
XOR AH,AH
SAL AX,1
MOV BX,AX
MOV CL,2
SAL AX,CL
ADD AX,BX
29试编程实现:
(1) AL寄存器的低4位清0;
(2) BL寄存器的低4位置1;
(3) CL寄存器的低4位取反;
(4) 测试DL寄存器的最低2位是否为0,若是将0送入AL寄存器;否则将1送AL寄存器。
30试编程统计在AX寄存器中有多少个1,并将结果送DL寄存器中。
31试编程统计在内存BLOCK单元开始按字节存放的100个带符号数中有多少负数,并将结果存放在DL寄存器中。
================================================================
80X86寄存器介绍
32位CPU所含有的寄存器有:
4个数据寄存器(EAX、EBX、ECX和EDX)
2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP)
6个段寄存器(ES、CS、SS、DS、FS和GS)
1个指令指针寄存器(EIP) 1个标志寄存器(EFlags)
1、数据寄存器
数据寄存器主要用来保存操作数和运算结果等信息,从而节省读取操作数所需占用总线和访问存储器的时间。
32位CPU有4个32位的通用寄存器EAX、EBX、ECX和EDX。对低16位数据的存取,不会影响高16位的数据。这些
低16位寄存器分别命名为:AX、BX、CX和DX,它和先前的CPU中的寄存器相一致。
4个16位寄存器又可分割成8个独立的8位寄存器(AX:AH-AL、BX:BH-BL、CX:CH-CL、DX:DH-DL),每个寄
存器都有自己的名称,可独立存取。程序员可利用数据寄存器的这种“可分可合”的特性,灵活地处理字/字
节的信息。
AX和AL通常称为累加器(Accumulator):可用于乘、除、输入/输出等操作(在乘除指令中指定用来存放操作数)
BX称为基地址寄存器(Base Register):在计算存储器地址时,可作为基址寄存器使用。
CX称为计数寄存器(Count Register):用来保存计数值,如在移位指令、循环指令和串处理指令中用作隐含的计数器(当移多位时,要用CL来指明移位的位数)。DX在作双字长运算时,可把DX和AX组合在一起存放一个双字长数,DX用来存放高16位数据。此外,对某些I/O操作,DX可用来存放I/O的端口地址。
DX称为数据寄存器(Data Register)。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。
在16位CPU中,AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址,但在32位CPU中,其32位
寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果,而且也可作为指针寄存器,
所以,这些32位寄存器更具有通用性。
2、变址寄存器
32位CPU有2个32位通用寄存器ESI和EDI。其低16位对应先前CPU中的SI和DI,对低16位数据的存取,不影响
高16位的数据。
寄存器ESI、EDI、SI和DI称为变址寄存器(Index Register),它们主要用于存放存储单元在段内的偏移量,
用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。
变址寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。
它们可作一般的存储器指针使用。在字符串操作指令的执行过程中,对它们有特定的要求,而且还具有特
殊的功能。
3、指针寄存器
32位CPU有2个32位通用寄存器EBP和ESP。其低16位对应先前CPU中的SBP和SP,对低16位数据的存取,不影
响高16位的数据。
寄存器EBP、ESP、BP和SP称为指针寄存器(Pointer Register),主要用于存放堆栈内存储单元的偏移量,
用它们可实现多种存储器操作数的寻址方式,为以不同的地址形式访问存储单元提供方便。
指针寄存器不可分割成8位寄存器。作为通用寄存器,也可存储算术逻辑运算的操作数和运算结果。
它们主要用于访问堆栈内的存储单元,并且规定:
BP为基指针(Base Pointer)寄存器,用它可直接存取堆栈中的数据;
SP为堆栈指针(Stack Pointer)寄存器,用它只可访问栈顶。
4、段寄存器
段寄存器是根据内存分段的管理模式而设置的。内存单元的物理地址由段寄存器的值和一个偏移量组合而成
的,这样可用两个较少位数的值组合成一个可访问较大物理空间的内存地址。
CPU内部的段寄存器:
CS——代码段寄存器(Code Segment Register),其值为代码段的段值;
DS——数据段寄存器(Data Segment Register),其值为数据段的段值;
ES——附加段寄存器(Extra Segment Register),其值为附加数据段的段值;
SS——堆栈段寄存器(Stack Segment Register),其值为堆栈段的段值;
FS——附加段寄存器(Extra Segment Register),其值为附加数据段的段值;
GS——附加段寄存器(Extra Segment Register),其值为附加数据段的段值。
在16位CPU系统中,它只有4个段寄存器,所以,程序在任何时刻至多有4个正在使用的段可直接访问;在32位
微机系统中,它有6个段寄存器,所以,在此环境下开发的程序最多可同时访问6个段。
32位CPU有两个不同的工作方式:实方式和保护方式。在每种方式下,段寄存器的作用是不同的。有关规定简
单描述如下:
实方式: 前4个段寄存器CS、DS、ES和SS与先前CPU中的所对应的段寄存器的含义完全一致,内存单元的逻辑
地址仍为“段值:偏移量”的形式。为访问某内存段内的数据,必须使用该段寄存器和存储单元的偏移量。
保护方式: 在此方式下,情况要复杂得多,装入段寄存器的不再是段值,而是称为“选择子”(Selector)的某个值。。
5、指令指针寄存器
32位CPU把指令指针扩展到32位,并记作EIP,EIP的低16位与先前CPU中的IP作用相同。
指令指针EIP、IP(Instruction Pointer)是存放下次将要执行的指令在代码段的偏移量。在具有预取指令功
能的系统中,下次要执行的指令通常已被预取到指令队列中,除非发生转移情况。所以,在理解它们的功能
时,不考虑存在指令队列的情况。
在实方式下,由于每个段的最大范围为64K,所以,EIP中的高16位肯定都为0,此时,相当于只用其低16位
的IP来反映程序中指令的执行次序。
6、标志寄存器
一、运算结果标志位
1、进位标志CF(Carry Flag)
进位标志CF主要用来反映运算是否产生进位或借位。如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。
使用该标志位的情况有:多字(字节)数的加减运算,无符号数的大小比较运算,移位操作,字(字节)之间移位,专门改变CF值的指令等。
2、奇偶标志PF(Parity Flag)
奇偶标志PF用于反映运算结果中“1”的个数的奇偶性。如果“1”的个数为偶数,则PF的值为1,否则其值为0。
利用PF可进行奇偶校验检查,或产生奇偶校验位。在数据传送过程中,为了提供传送的可靠性,如果采用奇偶校验的方法,就可使用该标志位。
3、辅助进位标志AF(Auxiliary Carry Flag)
在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0:
(1)、在字操作时,发生低字节向高字节进位或借位时;
(2)、在字节操作时,发生低4位向高4位进位或借位时。
对以上6个运算结果标志位,在一般编程情况下,标志位CF、ZF、SF和OF的使用频率较高,而标志位PF和AF的使用频率较低。
4、零标志ZF(Zero Flag)
零标志ZF用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。
5、符号标志SF(Sign Flag)
符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。在微机系统中,有符号数采用补码表示法,所以,SF也就反映运算结果的正负号。运算结果为正数时,SF的值为0,否则其值为1。
6、溢出标志OF(Overflow Flag)
溢出标志OF用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。
“溢出”和“进位”是两个不同含义的概念,不要混淆。如果不太清楚的话,请查阅《计算机组成原理》课程中的有关章节。
二、状态控制标志位
状态控制标志位是用来控制CPU操作的,它们要通过专门的指令才能使之发生改变。
1、追踪标志TF(Trap Flag)
当追踪标志TF被置为1时,CPU进入单步执行方式,即每执行一条指令,产生一个单步中断请求。这种方式主要用于程序的调试。
指令系统中没有专门的指令来改变标志位TF的值,但程序员可用其它办法来改变其值。
2、中断允许标志IF(Interrupt-enable Flag)
中断允许标志IF是用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志为何值,CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求,以及CPU内部产生的中断请求。具体规定如下:
(1)、当IF=1时,CPU可以响应CPU外部的可屏蔽中断发出的中断请求;
(2)、当IF=0时,CPU不响应CPU外部的可屏蔽中断发出的中断请求。
CPU的指令系统中也有专门的指令来改变标志位IF的值。
3、方向标志DF(Direction Flag)
方向标志DF用来决定在串操作指令执行时有关指针寄存器发生调整的方向。具体规定在第5.2.11节——字符串操作指令——中给出。在微机的指令系统中,还提供了专门的指令来改变标志位DF的值。
三、32位标志寄存器增加的标志位
1、I/O特权标志IOPL(I/O Privilege Level)
I/O特权标志用两位二进制位来表示,也称为I/O特权级字段。该字段指定了要求执行I/O指令的特权级。如果当前的特权级别在数值上小于等于IOPL的值,那么,该I/O指令可执行,否则将发生一个保护异常。
2、嵌套任务标志NT(Nested Task)
嵌套任务标志NT用来控制中断返回指令IRET的执行。具体规定如下:
(1)、当NT=0,用堆栈中保存的值恢复EFLAGS、CS和EIP,执行常规的中断返回操作;
(2)、当NT=1,通过任务转换实现中断返回。
3、重启动标志RF(Restart Flag)
重启动标志RF用来控制是否接受调试故障。规定:RF=0时,表示“接受”调试故障,否则拒绝之。在成功执行完一条指令后,处理机把RF置为0,当接受到一个非调试故障时,处理机就把它置为1,中国自学编程网整理发布!。
4、虚拟8086方式标志VM(Virtual 8086 Mode)
如果该标志的值为1,则表示处理机处于虚拟的8086方式下的工作状态,否则,处理机处于一般保护方式下的工作状态。
===================================================
虽然jmp指令提供了控制转移,但是它不允许进行任何复杂的判断。80x86条件跳转指令提供了这种判断。条件跳转指令是创建循环和实现其他条件执行语句,如if…endif的基本要素。
条件跳转指令检查一个或多个标志位,判断它们是否匹配某个特殊条件(就像setcc指令):如果标志匹配成功,该指令就将控制转移到目标位置;如果匹配失败,CPU忽略该条件跳转指令而继续执行下一条指令。一些条件跳转指令只是简单测试符号位(sign)、进位位(carry)、溢出位(overflow)、零标志(zero)位的设置。例如,在执行一条sh1指令后,您需要测试进位标志,来判断sh1是否从操作数的高地址位移出一位。类似地,也可以在一条test指令后测试零标志位,来判断指定的位是否为1。大多数情况,在cmp指令之后执行条件跳转指令。cmp指令设置标志位,以便判断小于、大于、等于等情况。
条件跳转指令形式如下:
Jcc label;
其中,Jcc中的“cc”,必须用表示测试条件类型的字符序列替换。这些字符和setcc指令使用的一样。例如,“js”表示根据符号(sign)标志是否被置位来决定是否跳转。一个典型的js指令如下:
js ValueIsNegative ;
在这个示例中,如果符号(sign)标志被置位,则js指令将控制转移到ValueIsNegative语句标号处;如果符号标志清零,则将控制直接转移给js指令后的指令。
与无条件jmp指令不同,条件跳转指令不提供间接跳转的形式。惟一允许的形式是跳转到程序中某一标号处。条件跳转指令有一个限制:目标标号的位置必须在跳转指令本身附近32768字节范围内,这通常对应着8000~32000条机器指令。一般情况下不会超过这种限制。
注意:Intel文档为许多条件跳转指令定义了多种替代名或指令别名。表7-1、7-2和7-3列出了每个指令所有的别名。这些表格也列出了表示相反分支的指令。很快您将明白这些相反分支指令的作用。
表7-1 测试标志位的JCC指令
指 令
描 述
条 件
别 名
相 反 指 令
JC
如果进位位被置位则跳转
进位标志=1
JB,JNAE
JNC
JNC
如果进位位没有置位则跳转
进位标志=0
JNB,JAE
JC
JZ
如果0标志被置位则跳转
0标志=1
JE
JNZ
JNZ
如果0标志没有置位则跳转
0标志=0
JNE
JZ
(续表)
指 令
描 述
条 件
别 名
相反指令
JS
如果符号位被置位则跳转
符号标志=1
JNS
JNS
如果符号位没有被置位则跳转
符号标志=0
JS
JO
如果溢出标志置位则跳转
溢出标志=1
JNO
JNO
如果溢出标志没有置位则跳转
溢出标志=0
JO
JP
如果奇偶校验位被置位则跳转
奇偶校验标志=1
JPE
JNP
JPE
如果奇偶校验位为偶校验则跳转
奇偶校验标志=1
JP
JPO
JNP
如果奇偶校验位没有被置位则跳转
奇偶校验标志=0
JPO
JP
JPO
如果奇偶校验位为奇校验则跳转
奇偶校验标志=0
JNP
JPE
表7-2 使用无符号数比较的JCC指令
指 令
描 述
条 件
别 名
相反指令
JA
如果超过(>)则跳转
进位标志=0,0标志=0
JNBE
JNA
JNBE
如果不低于或等于(不 <=)则跳转
进位标志=0,0标志=0
JA
JBE
JAE
如果超过或等于(>=)则跳转
进位标志=0
JNC,JNB
JNAE
JNB
如果不低于则跳转(不 <)
进位标志=0
JNC,JAE
JB
JB
如果低于(<)则跳转
进位标志=1
JC,JNAE
JNB
JNAE
如果不超过或等于(不>=)则跳转
进位标志=1
JC,JB
JAE
JBE
如果低于或等于(<=)则跳转
进位标志=1或0标志=1
JNA
JNBE
JNA
如果不超过(不>)则跳转
进位标志=1或0标志=1
JBE
JA
JE
如果相等(=)则跳转
0标志=1
JZ
JNE
JNE
如果不相等(<>)则跳转
0标志=0
JNZ
JE
表7-3 使用有符号数比较的JCC指令
指 令
描 述
条 件
别 名
相反指令
JG
如果大于(>)则跳转
符号标志=溢出标志或0标志=0
JNLE
JNG
JNLE
如果小于或等于(<=)则跳转
符号标志=溢出标志或0标志=0
JG
JLE
JGE
如果大于或等于(>=)则跳转
符号标志=溢出标志
JNL
JGE
JNL
如果不小于(不<)则跳转
符号标志=溢出标志
JGE
JL
JL
如果小于(<)则跳转
符号标志<>溢出标志
JNGE
JNL
JNGE
如果大于或等于(>=)跳转
符号标志<>溢出标志
JL
JGE
JLE
如果小于或等于(<=)跳转
符号标志<>溢出标志或0标志=1
JNG
JNLE
JNG
如果不大于(不>)则跳转
符号标志<>溢出标志或0标志=1
JLE
JG
JE
如果等于(=)则跳转
0标志=1
JZ
JNE
JNE
如果不等于(<>)则跳转
0标志=0
JNZ
JE
接下来将对“相反指令”一列进行简单的说明。在许多情况下,需要产生与某条分支指令条件相反的分支(在本章后面会给出示例),即相反分支。除了两个例外,都可以按下面的简单规则(后面统称为N/No N规则)产生相反分支:
● 如果Jcc的第二个字母不是“n”,则在“j”后面插入一个“n”。例如:je对应为jne,jl对应为jnl。
● 如果Jcc的第二个字母是“n”,则去掉指令中的“n”。例如:jng对应为jg,jne对应为je。
不遵循这两条规则的两个例外是jpe(奇偶位为偶跳转)和jpo(奇偶位为奇跳转)。这两个例外并不会导致什么问题,因为:(a)很少需要测试奇偶标志;(b)可以使用别名jp和jnp替代jpe和jpo。而“N/No N”规则对jp和jnp是适用的。
虽然jge是jl的相反指令,但是建议使用jnl作为jl的相反指令。因为很容易误认为“大于是小于的相反”,从而把jg当作jl的相反指令。您可以坚持使用“N/No N”规则以避免这种混淆。
80x86条件跳转指令提供了这样的能力:根据判断条件将程序流分支到两条路径中的某一条。例如,要实现:如果BX等于CX,则寄存器AX的值加1。可以使用下面的代码来完成该功能:
cmp(bx,cx );
jne SkipStmts;
inc(ax );
SkipStmts:
其中的诀窍是使用相反分支指令来跳过在条件满足的情况下需要执行的指令。请坚持使用前面介绍的“N/no N”规则来选择相反分支指令。
使用条件跳转指令还可以实现循环。例如,下面的代码序列实现了从用户输入读入一串字符,并将字符存储到一组连续的单元中,直到用户输入回车键。
mov(0,edi );
RdLnLoop:
stdin.getc(); //Read a character into the AL register.
mov(al,Input [edi])); //Store away the character.
inc(edi ); //Move on to the next character.
cmp(al,stdio.cr ); //See if the user pressed Enter.
jne RdLnLoop;
与setcc指令类似,条件跳转指令分为两类—— 测试特殊处理器标志位的条件跳转指令(例如jz、jc、jno)和测试某些条件(小于、大于等)的条件跳转指令。当测试某个条件时,条件跳转指令通常紧跟在一个cmp指令之后。cmp指令设置标志位后,如果是无符号数比较,使用ja、jae、jb、jbe、je或jne等指令测试这些标志来判断是否小于、小于等于、等于、不等于、大于或大于等于;如果是有符号数比较,则使用jl、jle、je、jne、jg、jge指令。
条件跳转指令测试标志位,但不影响标志位。
=========================
jnz(jump if not zero flag set) 和 jne(jump if not equal) 有相同的功效。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
x86汇编指令详解
lea指令与mov指令
MUL、IMUL、DIV
七种寻址方式(立即寻址、寄存器寻址)
80386ASM程序设计基础(二)
FASM 第二章 - 2.1 x86 体系指令 - xuyibo.org
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服