16位汇编笔记7-11

8 篇文章 0 订阅

16位汇编笔记7-11

7.定位内存地址

7.1 and & or

and将操作对象相应位设为0;
or将操作对象相应位设为1;

将al的第0位设为0
and al,11111110B
将al的第0位设为1
or al,00000001B

大写变小写
and al,11011111B
小写变大写
or al,00100000B

7.3 字符数据

assume cs:code, ds:data

data segment
	db 'unix'
data ends

code segment
start:	
	mov al,'a'
	
	mov ax,4c00h
    int 21h
code ends
end start

mov al,'a'相当于mov al,61H

7.5 [bx+idata]

[bx+idata]表示一个内存单元,偏移地址为(bx)+idata.

也可以写为:

[idata+bx]

idata[bx]

[bx].idata

2000:1000 BE 00 06 00 00 ...
mov	ax,2000H
mov ds,ax
mov bx,1000H
mov ax,[bx]  ; (ax)=00BEH
mov cx,[bx+1]   ;(cx)=0600H
add cx,[bx+2]   ;(cx)=0606H
将第一个字符串转为大写,第二个转为小写。
assume cs:code, ds:data
data segment
	db	"Basic"
	db	"MiNix"
data ends

code segment
start:
    mov ax,data
	mov ds,ax
	
	mov bx,0
	mov cx,5
s:	mov al,[bx]
	and al,11011111B
	mov [bx],al
	inc bx
	loop s
	
	mov bx,5
	mov cx,5
s0:	mov al,[bx]
	or  al,00100000B
	mov [bx],al
	inc	bx
	loop s0
code ends
end start
使用[bx+idata]
	mov ax,data
	mov ds,ax
	mov bx,0

	mov cx,5
s:	mov al,[bx]
	and	al,11011111B
	mov [bx],al
	mov al,[bx+5]
	or 	al,00100000B
	mov	[bx+5],al
	inc bx
	loop s
或者下面这样
	mov ax,data
	mov ds,ax
	mov bx,0
	
	mov cx,5
s:	mov al,0[bx]
	and	al,11011111B
	mov 0[bx],al
	mov al,5[bx]
	or 	al,00100000B
	mov	5[bx],al
	inc bx
	loop s
	
c语言:a[i],b[i]
汇编: 0[bx],5[bx]

[bx+idata]为高级语言实现数组提供了便利机制。

7.8 [bx+si]和[bx+di]

si,dibx功能相近,但si,di不能分成两个8位寄存器使用。以si为例。

[bx+si]
[si+5]
5[si]

7.9 [bx+si+idata]和[bx+di+idata]

mov ax,[bx+si+5]为例,可以写成

mov ax,[bx+5+si]
mov ax,[5+bx+si]
mov ax,5[bx][si]
mov ax,[bx].5[si]
mov ax,[bx][si].5
struct Person{
    int age
    char name[10];
}
如果有一个Person类型位于ds:0,name偏移为04h
mov bx,04h
[bx].0[si]则可以访问name的每个字节

7.10 应用

[idata][bx+si+idata]的演化:

[idata]–>[bx]–>[bx+idata]–>[bx+si]–>[bx+si+idata]

把每个单词的首字母改为大写
assume cs:code,ds:data

data segment
	db "1. file         "
	db "2. edit         "
	db "3. search       "
	db "4. view         "
	db "5. options      "
	db "6. help         "
data ends

code segment
start:
	mov ax,data
	mov ds,ax
	mov bx,0
	
	mov cx,6
s:
	mov al,[bx+3]
	and al,11011111B
	mov [bx+3],al
	add bx,16
	loop s
	
	mov ax,4c00h
	int 21h`
code ends
end start
把每个单词改为大写
assume cs:code,ds:data

data segment
	db "mac             "
	db "ibm             "
	db "dos             "
	db "win             "
data ends

code segment
start:
	
	mov ax,data
	mov ds,ax
	
	mov ax,0020h
	mov ss,ax
	mov sp,10h
	;如果cx不利用栈存放当前值,外层loop指令cx为0-1==fffff,进入死循环。
	
	mov bx,0
	mov cx,4    ; 4 rows
s0:
	mov si,0
	
	push cx
	mov cx,3	;3 columns/letters
s1:
	mov al,[bx+si]
	and al,11011111B
	mov [bx+si],al

	inc si
	loop s1
	
	add bx,10h
	pop cx
	loop s0
	
	mov ax,4c00h
	int 21h
code ends
end start


上面的程序如果是修改这样的数据:
data segment
	db "1. mac          "
	db "2. ibm          "
	db "3. dos          "
	db "4. win          "
data ends
则要使用相对基址加变址寻址方式:
mov al,[bx+3+si]
and al,11011111B
mov [bx+3+si],al

8 数据处理的两个基本问题

8.1 bx,bp,si,di

[]中,只能有这四个寄存器,而且有四种组合:[bx/bp+si/di]

不存在[ax],[bx+bp],[si+di]这种用法。

[]中使用bp,若指令没有显性给出段地址,则段地址默认在ss中,不使用bp则默认ds

8.2 数据位置

数据处理有3类:

  • 读取
  • 写入
  • 运算

数据可以出现在3个地方:

  • cpu内部
  • 内存
  • 端口
指令执行前数据位置
mov bx,[0]内存,ds:0
mov bx,axcpu内部,ax
mov ax,1cpu内部,指令缓冲器

汇编有3个概念表达数据位置:

  • 立即数/常数,idata,执行前在指令缓冲器中
  • 寄存器
  • 段地址SA和偏移地址EA,段地址可默认,可显性

8.3寻址方式

再次强调,有效地址存在si,di,bx,bp中,前三个的段地址默认为ds,bp的段地址默认为ss。

寻址方式名称常用格式
mov ax, idata立即寻址
mov ax,[0]直接寻址
mov ds,ax寄存器寻址
mov ax,[si]寄存器间接寻址
mov ax, [di + idata]寄存器相对寻址结构体:[bx].idata
数组:idata[si]
二维数组:[bx][idata]
mov ax,[bx+si]基址变址寻址二维数组:[bx][si]
mov ax,[bx+si+idata]相对基址变址寻址结构中的数组项:[bx].idata[si]
二维数组:idata[bx][si]

8.4 处理数据长度

寄存器使用al,ah等,则是字节操作,否则是字操作。

没有寄存器名时,用操作符[byte|word] ptr指明内存单元长度

eg.

mov word ptr ds:[0],1

mov byte ptr ds:[0],1

特殊的,push只进行字操作。

assume	cs:codesg

codesg segment
	db 0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh
start:	
	mov ax,codesg
	mov ds,ax
	mov byte ptr ds:[0],0fh
	mov word ptr ds:[2],0fh
	
	mov ax,4c00H       
	int 21H
		
codesg	ends              
end start   

8.5 除法指令div

指令格式:

  • `div reg``
  • ``div 内存单元`

需要注意:

  1. 除数:有8位和16位,在reg内存单元中。
  2. 被除数:默认在ax,或,ax和dx中。若除数为8位,则被除数位16位,默认在ax中;若除数为16位,则被除数为32位(dd类型),在ax中放低16位,dx中放高16位.
  3. 结果:若除数为8位,则al存储商,ah存储余数;若除数为16位,则ax存放商,dx存储余数。
除数(小)被除数(大)结果(低商高余)
8位byte16位wordaxax
16位word32位dworddx,axdx,ax
div byte ptr ds:[0]
含义
(al) = (ax) / ( (ds)*16 + 0 )的商
(ah) = (ax) / ( (ds)*16 + 0 )的余数

div word ptr es:[0]
含义
(ax) = [(dx)*10000H + (ax)] / ((es)*16 + 0)的商
(dx) = [(dx)*10000H + (ax)] / ((es)*16 + 0)的余数

8.6 伪指令dd

dd:define double word

data segment
	db 1    ;01H 		@ data:0,1 byte
	dw 1	;0001H		@ data:1,1 word
	dd 1	;0000 0001H	@ data:3,2 word
data ends

8.7 dup

db,dw,dd一样,由编译器识别处理。并与这些数据定义伪指令配合使用,进行数据的重复。

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 2 dup('ab','AB')  ;db,'abABabAB'

dw,dd用法相同。

9 转移指令

分类:

  • 无条件转移指令,如jmp
  • 条件转移指令
  • 循环指令,如loop
  • 过程,相当于函数
  • 中断

9.1 操作符offset

是由编译器处理的伪指令,功能是取得标号的偏移地址。

start:
	mov ax,offset start  ; mov ax,0    occupy 3 bytes
s:
	mov ax,offset s   ;mov ax,3
把s的一条指令复制到s0
s:
	mov ax,bx    ; occupy 2 bytes
	mov si,offset s
	mov di,offset s0
	mov ax,cs:[si]
	mov cs:[di],ax
s0:
	nop		;occupy 1 byte
	nop

9.2 jmp

jmp:无条件转移指令,可修改ip或同时修改csip的指令。

需要两种信息:

  • 转移的目的地址
  • 转移的距离(段间转移,段内短转移,段内近转移)

9.2.1 依据位移转移的jmp

jmp short 标号,段内短转移,可越过-128~127个字节。它的功能是实现(ip)=(ip)+8位位移

mov ax,0
jmp short s
inc ax
s:inc ax

立即数操作,机器码中会包含这个数。但jmp 标号机器码中不会出现标号偏移地址,而是转移的距离。

jmp的机器码为EB

转移距离:标号地址-jmp下一指令地址

jmp near ptr 标号 ,段内近转移,它的功能是实现(ip)=(ip)+16位位移,可越过-32768~32767个字节

9.2.2 目的地址在指令中的jmp

jmp far ptr 标号,实现段间转移,又称远转移。

(cs)=标号所在段的段地址,(ip)=标号所在段中的偏移地址。

mov ax,0
jmp far ptr s     ; EA 0B01 BD0B
db 256 dup(0)
s:add ax,1		;0BBD:010B

远转移的jmp机器码为EA。

9.2.3 转移地址在寄存器中的jmp

jmp reg,即(ip)=(reg),功能是实现ip = (16位寄存器)

9.2.4 转移地址在内存中的jmp

jmp word ptr 内存单元地址,段内转移,内存单元中的字存放目的偏移地址。

内存单元地址可用任一寻址方式给出。

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)=0000,(ip)=0123h

9.7 jcxz

jcxz(jump if cx zero):有条件转移指令,格式:jcxz 标号

所有有条件转移指令都是短转移,也包含转移位移,ip修改范围为-128~127个字节。

if((cx)==0) jmp short 标号

利用jcxz,在内存2000h段查找第一个值为0的字节,找到后把它的偏移地址存到dx中。
assume cs:codesg
codesg segment
start:
	mov ax,2000h
	mov ds,ax
	mov bx,0
s:
	______
	______
	______
	______
	jmp short s
ok:
	mov dx,bx
	
	mov ax,4c00h
	int 21h
codeseg ends
end start

答:
mov cl,[bx]
mov ch,0
jcxz ok
inc bx

9.8 loop

循环指令:loop 标号

所有循环指令只进行短转移,含转移位移,ip修改范围为-128~127个字节。

(cx)--;

if ((cx)!=0) jmp short 标号;

还是上一题
assume cs:codesg
codesg segment
start:
	mov ax,2000h
	mov ds,ax
	mov bx,0
s:
	mov cl,[bx]
	mov ch,0
	______
	inc bx
	jmp short s
ok:
	dec bx
	mov dx,bx
	mov ax,4c00h
	int 21h
codeseg ends
end start

答:
inc cx

9.9 根据位移进行转移的意义

jmp short 标号

jmp near ptr 标号

jcxz 标号

loop 标号

根据位移进行转移,方便程序不断封装和调用;如果机器码为目的地址,而目标指令不在该处,程序就会出错。

9.10 编译器对转移位移超界的检测

位移太大,编译时会显示jump destination too far:by X bytes(s)x为超界字节数。

assume cs:codesg
codesg segment
	mov ax,4c00h
	int 21h
start:
	mov ax,0
	
s:
	nop		;will become EBF6 , which means jmp 0000 here
	nop
	
	mov di,offset s
	mov si,offset s2
	mov ax,cs:[si]
	mov cs:[di],ax
s0:
	jmp short s	;EBF6
s1:
	mov ax,0
	int 21h
	mov ax,0
s2:
	jmp short s1	;EBF6,which means  jmp short s1  here
	nop
	
codesg ends
end start

颜色

B8000H-BFFFFH共32kB的空间为80*25彩色字符模式的显示缓冲区。这里的数据会显示在屏幕上,可显示25行,每行80个字。显示缓冲区分为8页,每页4kB。

一个字符占2个字节,分别存放ascii码和属性。

属性字节格式:

76543210
闪烁背景(RGB)高亮前景(RGB)

一屏4000个字节,通常b8000h-b8f9fh的4000个字节会显示出来。

assume cs:codesg,ds:datasg,ss:stacksg

datasg segment
	db "welcome to masm!"	;index:si
	db 00000010B,00100100B,01110001B	;index:bx
datasg ends

stacksg segment
	db 16 dup(0)
stacksg ends

codesg segment
start:
	mov ax,datasg
	mov ds,ax
	mov ax,stacksg
	mov ss,ax
	mov sp,10h
	
	mov ax,0b872h	;screen buffer segment address
	mov es,ax
	xor bx,bx		;screen buffer offset address
	
	mov cx,3	;3 strings
s0:
	push cx
	push ax
	push bx
	
	mov si,0	;datasg index
	
	mov di,0	;ax character index
	mov cx,10h
s1:
	mov al,ds:[si]
	mov es:[di],al
	inc si
	add di,2
	
	loop s1
	
	
	mov di,1	;ax attribute index
	pop bx
	mov al,ds:10h[bx]
	inc bx
	
	mov cx,10h
s2:
	mov es:[di],al
	add di,2
	loop s2
	
	
	pop ax
	add ax,0ah	;the next string
	pop cx
	loop s0
	
	mov ax,4c00h
	int 21h
	
codesg ends
end start

10 call和ret

callret都是转移指令,都修改ip,或同时修改csip

10.1 ret和retf

ret用栈中的数据修改ip,实现近转移。相当于pop ip.

  1. (ip) = ((ss)*16 + (sp))
  2. (sp) = (sp) + 2

retf用栈中的数据修改csip,实现远转移。相当于pop ip ;pop cs.

  1. (ip) = ((ss)*16 + (sp))
  2. (sp) = (sp) + 2
  3. (cs) = ((ss)*16 + (sp))
  4. (sp) = (sp) + 2

两个指令都没有参数.

10.2 call

call不能实现短转移。转移原理和jmp相同,

10.2.1 依据位移转移

call 标号

操作:

  1. (sp)=(sp)-2 ((ss)*16+(sp))=(ip)
  2. (ip)=(ip)+16位位移

相当于push ip; jmp near ptr 标号


10.2.2 目的地址在指令中

call far ptr 标号,可实现段间转移。

操作:

  1. (sp)=(sp)-2 ((ss)*16+(sp))=(cs)
  2. (sp)=(sp)-2 ((ss)*16+(sp))=(ip)
  3. (cs)=标号段地址 (ip)=标号在段中偏移地址

相当于push cs; push ip; jmp far ptr 标号


10.2.3 转移地址在寄存器中

call 16位reg

操作:

  1. (sp)=(sp)-2 ((ss)*16+(sp))=(ip)
  2. (ip)=(16位reg)

相当于push ip; jmp 16位reg


10.2.4 转移地址在内存中

有两种格式:

call word ptr 内存单元地址

相当于push ip; jmp word ptr 内存单元地址

call dword ptr 内存单元地址

相当于push cs; push ip; jmp dword ptr 内存单元地址

mov sp,10h
mov ax,0123h
mov [0],ax
mov word ptr [2],0
call dword ptr [0]
执行后,(cs)=0,(ip)=0123h,(sp)=0ch
所以,仍然是段地址在高位,偏移地址在地位。

10.7 call与ret配合

计算2的(cx)次方
assume cs:code
code segment
  start: mov ax,1
  		mov cx,3
  		call s
  		mov bx,ax
  		mov ax,4c00h
  		int 21h
  	 s:  add ax,ax
  	 	loop s
  	 	ret
code ends
end start

10.8 mul

mul regmul 内存单元

注意:

  • 两个相乘的数,位数应相同(8或16)。若都是8位,一个默认在al中,另一个在8位reg或内存字节单元中;如果是16位,一个默认在ax中,另一个在16位reg或内存字单元中。
  • 结果:8位乘法,结果默认在ax中;16位乘法,默认高位在dx中,低位在ax中。

mul byte ptr ds:[0],即(ax)=(al)*((ds)*16+0)

mul word ptr [bx+si+8],即(ax)存放(ax) * ((ds)*16 + (bx) + (si) + 8)的低16位,(dx)存放高16位。

10.9 模块化程序设计

10.10 参数结果传递

用寄存器存储参数和结果是最常用的方法。写子程序时要有详细说明。

; calc n*n*n, n is stored by bx
; cube(bx)
; return dx,ax

assume cs:codesg,ds:datasg

datasg segment
	dw 1,2,3,4,5,6,7,8
	dd 0,0,0,0,0,0,0,0
datasg ends

codesg segment
start:
	mov ax,datasg
	mov ds,ax
	mov si,0
	mov di,16
	
	mov cx,8
s:
	mov bx,[si]
	call cube
	mov [di],ax
	mov [di].2,dx
	add si,2
	add di,4
	loop s

	mov ax,4c00h
	int 21h

cube:
	mov ax,bx
	mul bx
	mul bx
	ret

codesg ends
end start

10.11 批量数据的传递

对于多个参数,我们可以将数据放到内存中,然后把这段内存的首地址存在寄存器中,传递给子程序。

返回结果同理。

将data段的字符串转为大写
assume cs:codesg,ds:datasg

datasg segment
	db "conversation"
datasg ends


codesg segment
start:
	
	mov ax,datasg
	mov ds,ax
	xor si,si
	
	mov cx,12
	call capital
	
	mov ax,4c00h
	int 21h

capital:
	and byte ptr [si],11011111B
	inc si
	loop capital
	ret

codesg ends
end start

传递参数还有一种通用方法是使用栈。

3种传参方法:

  • 寄存器
  • 内存
将data段以0结尾的字符串转为大写
因为用0来检测结尾,所以不需要设置cx
assume cs:codesg,ds:datasg

datasg segment
	db "linux",0
	db "windows",0
datasg ends


codesg segment
start:
	
	mov ax,datasg
	mov ds,ax
	xor si,si
	
	mov cx,2
s:
	push cx
	call capital
	inc si
	pop cx
	loop s
	
	
	mov ax,4c00h
	int 21h

capital:
	mov cl,[si]
	mov ch,0
	jcxz ok
	and byte ptr [si],11011111B
	inc si
	jmp short capital
ok:	ret

codesg ends
end start

实验十

show_str子程序

功能:在指定位置用指定颜色显示一个用0结尾的字符串

参数:(dh)为行号,取值范围0-24(dl)为列号,取值范围0-79

返回:无

举例:在第8行第3列,绿色显示data段字符串

assume cs:codesg,ds:datasg

datasg segment
	db "welcome to masm!",0
datasg ends

codesg segment
start:
	mov ax,datasg
	mov ds,ax
	mov si,0
	
	mov dh,8
	mov dl,3
	mov cl,00000010B
	mov ch,0
	call show_str
	
	mov ax,4c00h
	int 21h
show_str:
	mov ax,0b800h
	mov es,ax
	
	dec dh
	mov al,160	;bytes per row
	mul dh
	mov di,ax	
	
	dec dl
	mov al,2	;bytes per character
	mul dl
	add di,ax	;  es:di is the screen buffer 
	
	mov bl,cl	;mov the color to bx
	mov ch,0
s:
	mov cl,[si]
	jcxz ok	; 0?

	mov es:[di],cl		;copy the character		
	mov es:[di+1],bl	;copy the color
	add di,2
	
	inc si
	jmp short s
	
ok:	ret

codesg ends
end start

divdw除法溢出

做除法时,如果结果的商大于alax能存储的最大值,会引发cpu的一个内部错误:除法溢出。

功能:进行不会溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。

参数:dx存储dword高16位,ax存储低16位;cx存储除数。

返回:dx存储结果的高16位,ax存储低16位;cx存储余数。

公式:dx|ax / cx = int(dx / cx) * 10000H + [rem(dx / cx) * 10000H + ax] / cx,可以自己写个十进制除法体会一下.

举例:

mov ax,4240H
mov dx,000fH
mov cx,0ah
call divdw
结果:(dx)=0001h,(ax)=86a0h,(cx)=0
assume cs:codesg,ss:stacksg

stacksg segment
	dw 8 dup(0)
stacksg ends

codesg segment
start:
	mov ax,stacksg
	mov ss,ax
	mov sp,10h
	
	mov ax,4240H
	mov dx,000fH
	mov cx,0ah
	call divdw
	
	mov ax,4c00h
	int 21h

divdw:
	push ax		;push lower 16 bits
	mov ax,dx
	xor dx,dx
	div cx		;handle higher 16 bits
	
	mov bx,ax	;int(dx / cx) 
	
	pop ax
	div cx		;handle lower 16 bits
	
	mov cx,dx	;the final remainder
	mov dx,bx
	
	ret
	
codesg ends
end start

dtoc数值显示

功能:将word型数据转变为十进制数的字符串,以0结尾。

参数:ax存储word数据,ds:si指向字符串存放位置的首地址。

返回:无

思路是连续除以10d取余,直到商为0。本程序会调用showstr

assume cs:codesg,ds:datasg,ss:stacksg

datasg segment
	db 10 dup(0)
datasg ends

stacksg segment
	dw 8 dup(0)
stacksg ends

codesg segment
start:
	mov ax,stacksg
	mov ss,ax
	mov sp,10h

	mov ax,datasg
	mov ds,ax
	xor di,di
	
	mov ax,12666	;31h,32h,36h,36h,36h,0
	call dtoc
	
	mov dh,8
	mov dl,3
	mov cl,00000010B
	mov ch,0
	call show_str
	
	mov ax,4c00h
	int 21h

dtoc:
	push ax
	push bx
	push cx
	push dx
	
	mov bx,0	; store how many digits
s0:
	mov cx,10d
	mov dx,0
	div cx
	
	add dx,30h
	push dx
	inc bx
	
	mov cx,ax	
	jcxz s1		; int(ax/10d)==0
	
	jmp short s0
	
s1:
	mov cx,bx
s2:
	pop ax
	mov [di],al
	inc di
	loop s2
	
	pop dx
	pop cx
	pop bx
	pop ax
	ret
	
show_str:
	mov ax,0b800h
	mov es,ax
	
	dec dh
	mov al,160	;bytes per row
	mul dh
	mov di,ax	
	
	dec dl
	mov al,2	;bytes per character
	mul dl
	add di,ax	;  es:di is the screen buffer 
	
	mov bl,cl	;mov the color to bx
	mov ch,0
s:
	mov cl,[si]
	jcxz ok	; 0?

	mov es:[di],cl		;copy the character		
	mov es:[di+1],bl	;copy the color
	add di,2
	
	inc si
	jmp short s
ok:	ret

codesg ends
end start

11 标志寄存器flag

flag寄存器用来存储程序状态字psw。它有3种作用:

  1. 存储相关指令的某些执行结果
  2. 为cpu执行相关指令提供行为依据
  3. 控制cpu的相关工作方式

flag按位起作用,每一位有专门的含义。

| f | e | d | c |  b |  a |  9 |  8 |  7 |  6 | 5 |  4 | 3 |  2 | 1 |  0 |
|   |   |   |   | of | df | if | tf | sf | zf |   | af |   | pf |   | cf |

1,3,5,12,13,14,15在8086中没有含义,0,2,4,6,7,8,9,10,11有特殊含义。

从低位到高位:cpazstido

在debug中,如下显示:

标志10
ofOVNV
dfDNUP
ifEIDI
sfNGPL
zfZRNZ
afACNA
pfPEPO
cfCYNC

运行指令时,要注意指令会影响哪些位。

11.1 zf

zf(zero flag)在第6位,记录结果是否为0,是则zf=1,否则为0.

mov ax,1
and ax,0
则zf=1

运算指令会影响flag,传送指令没有影响。

11.2 pf

pf(parity flag)在第2位,是奇偶校验位,如果结果bit位中1的个数是偶数则pf=1,奇数则pf=0。可以联系单词0dd来记。

pf不常用。

11.3 sf

sf(sign flag)在第7位,符号标志位,结果为负则sf=1,非负则sf=0。

sf在无符号运算时没有意义。

11.4 cf

cf(carry flag)在第0位,进位标志位,记录了无符号数运算最高有效位向更高位的进位值,或从更高位的借位值。

cf是对无符号数运算有意义的标志位。例如,他可以充当8位数据运算的第9位。

11.5 of

of(overflow flag)在第11位,记录有符号数运算是否产生溢出。

of是对有符号数运算有意义的标志位,就像进位只针对无符号数一样。

11.6 adc指令

带进位加法指令,add carry。它用到了cf。

格式:adc ax,bx

功能:(ax) = (ax) + (bx) + cf

如果cf由sub设置,则含义是借位值;如果由add设置,则含义是进位值。

下面的指令和add ax,bx有相同结果:

add al,bl
adc ah,bh

adcadd配合可以对更大的数进行加法运算。

计算1E F000H + 20 1000H,结果高16位存在ax中,低16位存在bx中。

mov ax,001eh
mov bx,0f000h
sub cx,cx  ;set cf 0
add bx,1000h
adc ax,0020h

大数运算,可以用内存来存储。运算前先将cf置0.

assume cs:codesg,ds:datasg

datasg segment
	db 88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h,88h
	db 11h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11h,11h
datasg ends

codesg segment
start:
	mov ax,datasg
	mov ds,ax
	mov si,0
	mov di,10h
	
	call add128
	
	mov ax,4c00h
	int 21h

add128:
	push si
	push di
	
	sub ax,ax ;set cf 0
	mov cx,0fh
s:
	mov ax,[si]
	adc ax,[di]
	mov [si],ax
	
	inc si
	inc si
	inc di
	inc di	; add will influence cf
	loop s
	
	pop di
	pop si
	ret

codesg ends
end start

11.7 sbb指令

带错位减法指令,subtract with borrow.

格式:sbb ax,bx

功能:(ax) = (ax) - (bx) - cf

利用sbb可以对更大的数进行减法运算。

计算003E 1000H - 0020 2000H
mov bx,1000h
mov ax,003eh
sub bx,2000h
sbb ax,0020h

11.8 cmp指令

比较指令,相当于减法指令,但不保存结果,仅对flag进行设置。

cmp ax,ax
zf = 1
pf = 1
sf = 0
cf = 0
of = 0

执行后,主要观察zfcf

只由sf并不能判断大小关系,因为有符号数可能会溢出。所以要根据sfof判断结果的正负。of为1时,结论相反。

对于cmp ah,bh

ofsf结论
00(ah) > (bh)
01(ah) < (bh)
10(ah) < (bh)
11(ah) > (bh)

11.9 检测比较结果的条件转移指令

这些指令与cmp配合,根据被cmp指令影响的标志位跳转。

cmp可以同时进行无符号数和有符号数的比较,只不过改变了不同的标志位。所以这些转移指令也分为两种:

  • 根据无符号数比较结果转移,检测zfcf
  • 根据有符号数比较结果转移,检测zfofsf

无符号数比较结果相关指令:

指令含义执行时的标志位
jejump if equalzf=1
jnezf=0
jbjump if belowcf=1
jnbcf=0
jajump if abovecf=0,zf=0
jnacf=1zf=1
如果(ah)=(bh),则(ah)=(ah)+(bh),否则(ah)=(ah)+(bh)
cmp ah,bh
je f
add ah,bh
jmp short ok
f:
add ah,ah
ok:
ret
判断8的个数
assume cs:codesg,ds:datasg

datasg segment
	db 8,1,1,8,2,2,8,8
datasg ends


codesg segment
start:
	mov ax,datasg
	mov ds,ax
	mov si,0
	
	xor ax,ax
	mov cx,8
s:
	cmp byte ptr [si],8
	;or je ..
	jne next
	inc ax
next:
	inc si
	loop s
	
	mov ax,4c00h
	int 21h
codesg ends
end start
判断大于8的个数
assume cs:codesg,ds:datasg

datasg segment
	db 8,1,1,8,2,2,9,8
datasg ends


codesg segment
start:
	mov ax,datasg
	mov ds,ax
	mov si,0
	
	xor ax,ax
	mov cx,8
s:
	cmp byte ptr [si],8
	jna next
	inc ax
next:
	inc si
	loop s
	
	mov ax,4c00h
	int 21h
codesg ends
end start

11.10 df标志和串传送指令

方向标志位direction flag在第10位,在串处理指令中控制每次操作后si,di的增减。

df=0,递增;df=1,递减。

串传送指令movsb(move string byte)功能:

  1. mov es:[di],byte ptr ds:[si] ,即以字节为单位传送;8086不支持这种指令,只是描述,即((es)*16 + (di)) = ((ds)*16 + (si))
  2. if df=0,inc si;inc di;if df=1,dec si; dec di

movsw则是传送一个字,每次si,di加2或减2.

movsbmovsw一般和rep配合使用。rep是根据cx重复执行后面的串指令,即repeat。

rep movsb功能:传送(cx)个字节。

s: movsb
   loop s

cld指令:将df设为0

std指令:将df设为1

assume cs:codesg,ds:datasg

datasg segment
	db 1,2,3,4,5,6,7,8
	db 0,0,0,0,0,0,0,0
datasg ends

codesg segment
start:
	mov ax,datasg
	mov ds,ax
	mov es,ax
	mov si,0
	mov di,8
	
	mov cx,8
	cld
	rep movsb
	
	mov ax,4c00h
	int 21h
codesg ends
end start

11.11 pushf和popf

pushf:将flag寄存器的值压栈

popf:从栈中弹出数据送入flag寄存器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值