8086汇编知识点

8086汇编知识点

基础指令
mov传送指令
mov ax,10h   #(ax)=10h
mov ax,bx
mov ax,ds:[bx+si+5]
add加法指令
add ax,10h   #(ax)=(ax)+10h
add ax,bx
add al,bl
sub减法指令
sub ax,10h   #(ax)=(ax)-10h
sub ax,bx
sub al,bl
push入栈指令
push ax     #sp=sp-2     (ss:sp)=(ax)   栈底数值最高,栈顶数值最低,栈的生长是从高位到低位
push ds
pop出栈指令
pop ds      #(ds)=(ss:sp)    sp=sp+2    先将值转给寄存器,在调整栈指针
pop ax
循环指令
loop指令

循环进行某操作

循环次数通常存放在cx寄存器中

注:汇编源程序中,数据不能以字母开头

例如,mov ax,0ffffh 其中必须在字母之前加零

8086汇编例程:
assume cs:code,ds:data,ss:stack           #定义代码段,数据段,栈段

data segment
	dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends

stack segment
	dw 0,0,0,0,0,0,0,0
stack ends

code segment
start:                                    #将CS:IP指向代码段,否则将从先定义的数据段执行
	mov ax,stack
	mov ss,ax
	mov sp,16
	
	mov ax,data
	mov ds,ax
	
	mov bx,0
	mov cx,8
s:  push [bx]
	add bx,2
	loop s
	
	mov ax,4c00h
	int 21h
	
code ends

end start
内存寻址
[bx+idata]定位方式

mov ax,[5+bx]等价于mov ax,5[bx]

si、di寄存器

si,di与bx功能相近,主要用于作为内存寻址的偏移地址

si、di不能拆分为两个8位寄存器

[bx+si]、[bx+di]

mov ax,[bx][si]

即为(ax)=((ds)*16+(bx)+(si))

[bx+si+idata]、[bx+di+idata]

偏移地址为(bx)+(si)+idata

常用格式如下:

mov ax,[bx+200+si]
mov ax,[200+bx+si]
mov ax,200[bx][si]
mov [bx].200[si]
mov [bx][si].200
and和or指令及其特殊用法
and al,01010101b  #按位与
or  al,01010101b  #按位或
  • and可将数值为0的位对应的位数的值设置为零,1对应的位数的值保持不变
  • or 可将数值为1的位对应的位数的值设置为一,0对应的位数的值保持不变

又由于ASCII码中大小写字母的码值相差32,即00100000b

因此

and al,11011111b
#将小写字母转换为大写字母,若本来为大写,则保持不变
or  al,00100000b
#将大写字母转换为小写字母,若本来为小写,则保持不变

由此可见,使用and和or指令,能够在大小写转换中不必判断字母原来的情况,能够在位的角度轻松完成,这也启发我们在做事的时候应该从多方面思考,也许从另一个角度来看,问题会明了许多。

寻址方式
  1. 直接寻址,[idata]
  2. 寄存器间接寻址,[bx]
  3. 寄存器相对寻址,[bx+idata][bx].idataidata[bx]==[bx][idata]
  4. 基址变址寻址,[bx+si]==[bx][si]
  5. 相对基址变址寻址,[bx+si+idata]==[bx].idata[si]==idata[bx][si]

寄存器bx,si,di,bp可以单独出现

或以特定的组合出现

mov ax,[bx]
mov ax,[si]
mov ax,[di]
mov ax,[bp]
mov ax,[bx+si]
mov ax,[bx+di]
mov ax,[bp+si]
mov ax,[bp+di]
mov ax,[bx+si+idata]
mov ax,[bx+di+idata]
mov ax,[bp+si+idata]
mov ax,[bp+di+idata]

即bx与bp不能同时出现,si与di不能同时出现

[bx]默认段寄存器为ds(数据段)

[bp]默认段寄存器为ss(栈段)

通常情况下,[bx+si+idata]的寻址方式主要用于访问结构体中的数据。bx用于定位结构体,idata用于定位结构体中的某一个数据项,si定位数组项中的某个元素可以用类c语言的书写方式,例如[bx].idata、[bx].idata[si]

指令处理数据的长度
  1. 通过寄存器名指明
  2. 操作符
  3. 栈操作(push、pop均只能进行字操作)
#寄存器名
mov ax,1  #字操作
mov al,1  #字节操作

#操作符X ptr
mov word ptr ds:[0],1  #字操作
inc byte ptr ds:[0]    #字节操作
乘除指令
div指令

除法指令,除数可以为16位或8位,可以在寄存器或内存单元中。

被除数在AX寄存器或DX和AX寄存器中。

  • 除数为8位,被除数为16位,在ax中存放,运算后al存储商,ah存储余数
  • 除数为16位,被除数为32位,在dx、ax中存放,dx存放高16位,运算后,dx存储商,ax存储余数

注:在debug中插入汇编代码时,插入的数据默认是16进制的,比如mov bl,100就会提示error,这里的100指的是十进制的128

mul指令

乘法指令,两个相乘的数要么均为8位、要么均为16位。

  • 均为8位,一个默认放在AL中,另一个放在8位寄存器(如bl)或内存字节单元中,结果放在AX中
  • 均为16位,一个默认放在AX中,另一个放在16位寄存器或内存字单元中,结果高位放在DX、低位放在AX中
#例子:计算100x10
mov al,100
mov bl,10
mul bl

#例子:计算100x10000
mul ax,100
mov bx,10000
mul bx
dd伪指令、dup指令
  • db(define byte) 定义字节型数据

  • dw(define word) 定义字型数据

  • dd(define double word) 定义双字型(dword)数据

db 3 dup (0)      #相当于db 0,0,0
db 3 dup (0,1,2)  #相当于db 0,1,2,0,1,2,0,1,2

格式如下:
db 重复的次数 dup (重复的字节型数据)
dw 重复的次数 dup (重复的字型数据)
dd 重复的次数 dup (重复的双字型数据)

应用:

#定义一个容量200个字节的栈段
stack segment
	db 200 dup(0)
stack ends
跳转指令
offset操作符

用于取得标号的偏移地址

assume cs:codesg
codesg segment
	s: mov ax,bx
	   mov si,offset s     #将mov ax,bx指令的偏移地址送入si中
	   mov di,offset s0    #将nop的偏移地址送入di中
	   mov ax,cs:[si]
	   mov cs:[di],ax
   s0: nop
       nop
codesg ends
end s
jmp指令

1.转移地址在目标指令中

  • jmp short 标号(段内短转移,范围为-128~127,在机器码中由补码表示)
assume cs:codesg
codesg segment

start: mov ax,0
	   jmp short s
	   add ax,1
	s: inc ax
codesg ends 
end start
  • jmp near ptr 标号(段内近转移,范围为-32768~32767,在机器码中由补码表示)
  • jmp far ptr 标号(段间转移,又称远转移,在机器码中储存了转移位置的CS:IP值)

2.转移地址在寄存器中

  • jmp 16位寄存器 如jmp ax

3.转移地址在内存中

  • jmp word ptr 内存单元地址(段内转移)
mov ax,0123h
mov ds:[0],ax
jmp word ptr ds:[0]
  • jmp dword ptr 内存单元地址(段间转移)
#从内存单元地址处开始的两个字,高地址处为转移的目的段地址,低地址处为转移的目的偏移地址
#(CS)=(内存单元地址+2)
#(IP)=(内存单元地址)

#例如
mov ax,0123h
mov ds:[0],ax
mov word ptr ds:[2]:,0
jmp dword ptr ds:[0]
#执行后,(CS)=0,(IP)=0123h,CS:IP指向0000:0123

注:形如"jmp 2000:0100"的转移指令,是在Debug中使用的汇编指令,汇编编译器无法识别,在源程序中无法使用

jcxz指令

有条件转移指令,所有有条件转移指令都是短转移

Jmp if CX == Zero

  • jcxz 标号 (如果(cx)=0,转移到标号处进行,反之,什么也不做)

jcxz 标号 等价于 if((cx)==0) jmp short 标号;

assume cs:code
code segment
 start: mov ax,2000h
		mov ds,ax
        mov bx,0
      s:mov cl,[bx]
        mov ch,0
        jcxz ok
        inc bx
        jmp short s
     ok:mov dx,bx
        mov ax,4c00h
        int 21h
code ends
end start

注:段内转移、jcxz、loop等转移指令对IP的修改是根据转移目的地址和转移起始地址之间的位移来进行的,这种设计,方便了程序段在内存中的浮动装配

函数调用、返回指令
ret和retf指令
  • CPU执行ret指令,进行如下操作:
  1. (IP)=((ss)*16+(sp))
  2. (sp)=(sp)+2
  • CPU执行retf指令,进行如下操作:
  1. (IP)=((ss)*16+(sp))
  2. (sp)=(sp)+2
  3. (CS)=((ss)*16+(sp))
  4. (sp)=(sp)+2

由此可见,ret、retf指令与SS、SP寄存器有关,即与栈段相关联。

ret指令,相当于:

pop IP

retf指令,相当于:

pop IP

pop CS

call指令

CPU执行call指令时,进行两步操作

  1. 将当前的IP或CS:IP压入栈中
  2. 转移

call指令实现转移的方法和jmp指令的原理相同

有如下应用形式

1.根据位移进行转移

形式:call 标号(将当前的IP压入栈,转到标号处执行指令)

相当于进行:

push IP

jmp near ptr 标号

注:call指令不能实现短转移

2.转移的目的地址在指令中

形式:call far ptr 标号(段间转移)

相当于进行:

push CS

push IP

jmp far ptr 标号

3.转移的目的地址在寄存器中

形式:call 16位寄存器

相当于进行:

push IP

jmp 16位寄存器

4.转移的目的地址在内存中

有两种形式

  • call word ptr 内存单元地址,相当于进行

push IP

jmp word ptr 内存单元地址

  • call dword ptr 内存单元地址

push CS

push IP

jmp dword ptr 内存单元地址

由以上应用形式可知,call无法进行短转移,call标号、call16位寄存器、callword大小的内存单元地址时,仅将ip入栈,而call far ptr 标号、call dword ptr 内存单元地址时,先将CS入栈(为栈中高地址)再将IP入栈(为栈中低地址)。这一点无论是在retf时还是在call、jmp时,CS均在高地址,IP均在低地址,与数值在内存中高位存放在高地址、低位存放在低地址类似

call和ret指令配合编写子程序
assume cs:code
code segment
 main:  :
 		:
 		call sub1       ;调用子程序1
 		:
 		:
 		mov ax,4c00h
 		int 21h
 		
 sub1:  :               ;子程序1
 		:
 		call sub2       ;调用子程序2
 		:
 		:
 		ret             ;子程序1返回
 		
 sub2:  :               ;子程序2
 		:
 		:
 		ret             ;子程序2返回
code ends 
end main

IP的栈操作可表示为

push IP  ;保存主程序IP
push IP1 ;保存子程序1IP

pop IP1  ;恢复子程序1IP
pop IP   ;恢复主程序IP

为了避免出现寄存器冲突的可能性,例如在主程序中使用了cx来控制循环,子程序中用cx控制循环时会出现修改cx值导致主程序循环无法按预期进行的问题。我们需要在编写子程序(即函数)时,在子程序的开始将子程序用到的寄存器中的内容压入栈中,在子程序返回前,从栈中恢复寄存器在主程序中的数值。

codesg segment
main:   
		mov cx,4
	s:  :              #主函数中的循环
		:
		call sub
		loop s
		:
		mov ax,4100h
		int 21h
sub:
		push cx       #cx寄存器的值入栈
        mov cx,3
    l:  :             #子函数中的循环
        :
        loop l
        pop cx        #cx寄存器内容出栈
        ret
codesg ends
标志寄存器
结构

flag寄存器:每一位都有专门的含义,为空的位没有任何含义

1514131211109876543210
OFDFIFTFSFZFAFPFCF
各标记位作用

1.ZF标志位

  • 零标志位,zero

记录相关指令执行后,其结果是否为零,如果为0,zf=1,反之,zf=0

2.PF标志位

  • 奇偶标志位

记录相关指令执行后,其结果的所有位中1的个数是否为偶数,如果为偶数,pf=1,反之,pf=0

3.SF标志位

  • 符号标志位,sign

记录相关指令执行后,其结果是否为负,如果为负,sf=1,反之,sf=0

4.CF标志位

  • 进位标志位,carry
mov al,90h
add al,al        ;执行后:(al)=20h,CF=1,记录了最高有效位向更高位的进位值

mov al,91h
sub al,92h       ;执行后:(al)=ffh,CF=1

mov al,91h
sub al,al        ;执行后:(al)=0,CF=0     

将CF设置为0的方法:

sub ax,ax

5.OF标志位

  • 溢出标记位,overflow

记录有符号运算的结果是否发生了溢出,如果发生了溢出,OF=1,反之,OF=0

6.DF标志位

  • 方向标志位,direction

在串传送指令中,控制每次操作后si、di的增减

  1. df=0 每次操作后si、di递增
  2. df=1 每次操作后si、di递减

详情见串传送指令

pushf和popf指令
  • pushf:将标志寄存器的值压栈
  • popf :从栈中弹出数据,送入标志寄存器中
带进位的加减指令
adc指令

带进位的加法指令,利用了cf位上记录的进位值

adc ax,bx    #等价于(ax)=(ax)+(bx)+CF

#可以将add指令转换为add、adc指令的组合
add ax,bx
#即为
add al,bl
adc ah,bx

应用:

#计算1EF000H+201000H,结果存放在ax(高16位)、bx(低16位)中
mov ax,001EH
mov bx,0F000H
add bx,1000H   ;低16位
adc ax,0020H   ;高16位,加上进位值
sbb指令

带借位的减法指令,利用了cf位上记录的借位值

sbb ax,bx   #等价于(ax)=(ax)-(bx)-CF

用法与adc类似

条件转移指令
cmp指令

比较指令,cmp的功能相当于减法指令,不过不保存结果

根据相关标志位的值可以看出比较结果

对于无符号数

无符号ax与bx大小比较标志位情况
(ax)=(bx)zf=1
(ax)!=(bx)zf=0
(ax)<(bx)cf=1
(ax)>=(bx)cf=0
(ax)>(bx)cf=0 && zf=0
(ax)<=(bx)cf=1 || zf=1

总结:相等于否决定zf,相减为负与否决定cf

对于有符号数

标记位值实际结果的正负
sf=1,of=0无溢出,结果为负
sf=1,of=1有溢出,结果为非负
sf=0,of=0无溢出,结果为非负
sf=0,of=1有溢出,结果为负
条件转移指令

条件转移指令通常配合cmp使用,通过检测标志寄存器,来决定是否修改IP

利用无符号数、有符号数(这里的结果为负或非负取决于上表中的sf、of值)比较结果的条件转移指令

指令含义无符号比较检测的相关标记位有符号比较检测的相关标记位
je等于则转移zf=1zf=1
jne不等于则转移zf=0zf=0
jb低于则转移cf=1结果为负
jnb不低于则转移cf=0结果为非负
ja高于则转移cf=0 && zf=0结果为非负&&zf=0
jna不高于则转移cf=1 || zf=1结果为负||zf=1
  • e: equal
  • b: below
  • a: above

注:当条件转移指令不与cmp指令配合使用时,将根据标志寄存器当前的状态来决定是否转移

串传送指令
movsb、movsw指令
#将ds:si指向的内存单元中的字节送入es:di中,然后根据df的值将si和di递增或递减
movsb       ;类似于mov es:[di],byte ptr ds:[si] 并无该指令!

#将ds:si指向的内存单元中的字送入es:di中,然后根据df的值将si和di递增2或递减2
movsw       ;类似于mov es:[di],word ptr ds:[si] 并无该指令!
rep指令

rep指令的作用是根据cx的值,重复执行后面的串传送指令

rep movsb
#等价于
s:movsb
loop s

rep movsw
#等价于
s:movsw
loop s
cld指令、std指令
  • cld指令,将标志寄存器的df位置0

  • std指令,将标志寄存器的df位置1

           | 结果为非负                 |
    

| ja | 高于则转移 | cf=0 && zf=0 | 结果为非负&&zf=0 |
| jna | 不高于则转移 | cf=1 || zf=1 | 结果为负||zf=1 |

  • e: equal
  • b: below
  • a: above

注:当条件转移指令不与cmp指令配合使用时,将根据标志寄存器当前的状态来决定是否转移

串传送指令
movsb、movsw指令
#将ds:si指向的内存单元中的字节送入es:di中,然后根据df的值将si和di递增或递减
movsb       ;类似于mov es:[di],byte ptr ds:[si] 并无该指令!

#将ds:si指向的内存单元中的字送入es:di中,然后根据df的值将si和di递增2或递减2
movsw       ;类似于mov es:[di],word ptr ds:[si] 并无该指令!
rep指令

rep指令的作用是根据cx的值,重复执行后面的串传送指令

rep movsb
#等价于
s:movsb
loop s

rep movsw
#等价于
s:movsw
loop s
cld指令、std指令
  • cld指令,将标志寄存器的df位置0
  • std指令,将标志寄存器的df位置1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值