汇编语言知识点汇总

目录

前言

参考教材:王爽编著的《汇编语言》(第3版)

第1章 基础知识

1.6 存储单元

一个存储单元存储 1字节(Byte/B) = 8比特/位(bit)。

转换前 转换后
1KB 210B
1MB 220B
1GB 230B
1TB 240B

1KB的存储器有_1024_个存储单元,存储单元的编号从__0__到__1023__。

8080、8088、80286、80386的地址总线宽度分别为16根、20根、24根、32根,则它们的寻址能力分别为:__64__KB、__1__MB、__16__MB、__4__GB。

在存储器中,数据和程序以__二进制__形式存放。

1.8 地址总线

一个CPU有N根地址线,则可以说这个CPU的地址总线的宽度为N。这样的CPU最多可以寻找2的N次方个内存单元。

1个CPU的寻址能力为8KB,那么它的地址总线的宽度为_13_位。
解答:8KB = 23 x 210B = 213B。

1.9 数据总线

8根数据总线一次可传送一个8位二进制数据(即一个字节)。

8086和80386的数据总线宽度分别是16根和32根,也就是说8086和80386一次可传送16位和32位二进制数据即2Byte和4Byte。

8080、8088、8086、80286、80386的数据总线宽度分别为8根、8根、16根、16根、32根,则它们一次可以传送的数据分别为:__1__B、__1__B、__2__B、__2__B、__4__B。

从内存中读取1024字节的数据,8086至少要读__512__次,80386至少要读__256__次。

第2章 寄存器

  • 8086CPU有14个寄存器,每个寄存器有一个名称。这些寄存器是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。
  • add ax,bx的含义:
    将寄存器 ax 中的数据与寄存器 bx 中的数据相加,结果保存在寄存器 ax 中。

2.1 通用寄存器

8086CPU的所有寄存器都是16位的,可以存放两个字节。AX、BX、CX、DX这4个寄存器通常用来存放一般性的数据,被称为通用寄存器。

2.3 几条汇编指令

add al,93H 指令产生的进位不会存储在 ah 中,add al,93H 进行的是 8 位运算。

2.7 “段地址×16+偏移地址=物理地址”的本质含义

给定段地址为0001H,仅通过变化偏移地址寻址,CPU的寻址范围为__00010H__和__1000FH__。
解答:0001H×10+0000H=00010H,0001H×10+FFFFH=1000FH。

有一数据存放在内存20000H单元中,现给定段地址为SA,若想用偏移地址寻到此单元。则SA应满足的条件是:最小为__1001H__,最大为__2000H__。
解答:偏移地址最大时,段地址最小,偏移地址最大为FFFFH,20000H-FFFFH=10001H,发现10001H除以10H除不尽,所以不能这样计算。可以换一种角度理解,当段地址为1000H时,偏移地址取FFFFH,则其内存单元为1FFFFH,而1FFFFH+1H=20000H,偏移地址仍是FFFF,则段地址应为1001H。求最大则可以直接计算。

2.10 CS和IP

CS为代码段寄存器,IP为指令指针寄存器。

在8086PC机中,任意时刻设CS中的内容为M,IP中的内容为N,8086CPU将从内存M×16+N单元开始,读取一条指令并执行。

2.11 修改CS、IP的指令

mov指令不能用于设置CS、IP的值。

jmp指令可以修改CS、IP。

  • “jmp 段地址:偏移地址”——同时修改CS、IP的内容

例:jmp 2AE3:3,执行后:CS=2AE3H,IP=0003H,CPU将从2AE33H处读取指令。

  • “jmp 某一合法寄存器”——仅修改IP的内容,jmp ax 可以理解为 mov IP,ax。

例:jmp ax,指令执行前:ax=1000H,CS=2000H,IP=0003H
指令执行后:ax=1000H,CS=2000H,IP=1000H

下面的3条指令执行后,CPU几次修改IP?都是在什么时候?最后IP中的值是多少?
mov ax,bx
sub ax,ax
jmp ax
解答:CPU读取mov ax,bx的时候,第一次修改IP
读取sub ax,ax的时候,第二次修改IP
读取jmp ax的时候,第三次修改IP
当执行jmp ax的时候,IP变为0,这是第4次修改
最后IP变为0

第3章 寄存器(内存访问)

3.1 内存中字的存储

我们用0、1两个内存单元存放数据20000(4E20H)。0、1两个内存单元用来存储一个字,这两个单元可以看作一个起始地址为0的字单元(存放一个字的内存单元,由0、1两个字节单元组成)。对于这个字节单元来说,0号单元是低地址单元,1号单元是高地址单元,则字型数据4E20H的低位字节单元存放在0号单元中,高位字节存放在1号单元中。同理,将2、3号单元看作一个字单元,它的起始地址为2。在这个字单元中存放数据18(0012H),则在2号单元中存放低位字节12H,在3号单元中存放高位字节00H。
在这里插入图片描述

3.2 DS和[address]

在8086PC中,内存地址由段地址和偏移地址组成。8086CPU中有一个DS寄存器,通常用来存放要访问数据的段地址。

在DEBUG中,用 “d 0:0 lf” 查看内存,结果如下:
0000:0000 70 80 F0 30 EF 60 30 E2-00 80 80 12 66 20 22 60
0000:0010 62 26 E6 D6 CC 2E 3C 3B-AB BA 00 00 26 06 66 88
下面的程序执行前,AX=0,BX=0,写出每条汇编指令执行完后相关寄存器中的值
mov ax,1
mov ds,ax
mov si,2
mov ax,[0000] ax=__2662__H
mov bx,[0001] bx=__E626__H
mov ax,bx ax=__E626__H
mov ax,[000C] ax=__0626__H
mov bx,[0002] bx=__D6E6__H
add ax,bx ax=__DD0C__H
提示:注意ds的设置。
解答:为什么从0000:0010开始找?因为0001:0000和0000:0010指向的都是00010H处,是等价的。
相关题目:https://blog.csdn.net/freezhanacmore/article/details/17740999

3.7 CPU提供的栈机制

8086CPU的入栈和出栈操作都是以字为单位进行的。

8086CPU中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。任意时刻,SS:SP指向栈顶元素。

  • push ax 的执行,由以下两步完成:
    1. SP=SP-2,SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶;
    2. 将 ax 中的内容送入 SS:SP 指向的内存单元处, SS:SP 此时指向新栈顶。
  • pop ax 的执行过程和 push ax 刚好相反,由以下两步完成:
    1. 将 SS:SP 指向的内存单元处的数据送入ax中;
    2. SP=SP+2,SS:SP 指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

如果将 10000H~1000FH 这段空间当作栈,初始状态栈是空的,此时,SS=1000H,SP=0010H。
在这里插入图片描述

3.9 push、pop指令

push和pop指令是可以在寄存器和内存之间传送数据的。

push 寄存器 ;将一个寄存器中的数据入栈
pop 寄存器 ;出栈,用一个寄存器接收出栈的数据

push 内存单元 ;将一个内存字单元处的字入栈(注意:栈操作都是以字为单位)
pop 内存单元 ;出栈,用一个内存字单元接收出栈的数据

1.补全下面的程序,使其可以将10000H ~ 1000FH中的8个字,逆序复制到20000F ~ 2000FH中。逆序复制的含义如图所示(图中内存里的数据均为假设)。
在这里插入图片描述
mov ax,1000H
mov ds,ax
----补充部分----
mov ax,2000H
mov ss,ax
mov sp,0010
----补充部分----
push [0]
push [2]
push [4]
push [6]
push [8]
push [A]
push [C]
push [E]
2.补全下面的程序,使其可以将10000H ~ 1000FH中的8个字,逆序复制到20000H ~ 2000FH中。
mov ax,2000H
mov ds,ax
----补充部分----
mov ax,1000H
mov ss,ax
mov sp,0000H
----补充部分----
pop [E]
pop [C]
pop [A]
pop [8]
pop [6]
pop [4]
pop [2]
pop [0]

如果要在10000H处写入字数据2266H,可以用以下的代码完成:

mov ax,1000H

mov ds,ax

mov ax, 2266H

mov [0], ax

补全下面的3条指令,实现采用push ax 语句完成同样的功能:在10000H处写入字型数据2266H。

____mov ax,1000H__

____mov ss,ax_____

____mov sp,2______

mov ax,2266H

push ax

第4章 第一个程序

4.2 源程序

下面就是一段简单的汇编语言源程序。

assume cs:codesg

codesg segment
	mov ax,0123H
	mov bx,0456H
	add ax,bx
	add ax,ax

	mov ax,4c00H
	int 21H
	
codesg ends

end

下面对程序进行说明。

1. 伪指令

  • segment和ends是一对成对使用的伪指令,它们的功能是定义一个段,segment说明一个段开始,ends说明一个段结束。
    比如,程序中的:
    codesg segment	;定义一个段,段的名称为“codesg”,这个段从此开始
    ......
    codesg ends		;名称为“codesg”的段到此结束
    
  • end是一个汇编程序的结束标记。
  • assume的含义为“假设”。它假设某一段寄存器和程序中的某一个用segment…ends定义的段相关联。

5. 程序返回

mov ax,4c00H
int 21H

这两条指令所实现的功能就是程序返回。

4.8 谁将可执行文件中的程序装载进入内存并使它运行?

汇编程序从写出到执行的过程:

编程 (Edit) → 1.asm → 编译 (masm) → 1.obj → 连接 (link) → 1.exe → 加载 (command) → 内存中的程序 → 运行 (CPU)

第5章 [BX]和loop指令

  • 为了描述上的简洁,我们将使用一个描述性的符号“()”来表示一个寄存器或一个内存单元中的内容。比如:
  • (ax)表示ax中的内容、(al)表示al中的内容。
  • 约定符号idata表示常量。

5.1 [BX]

mov ax,[bx]
功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将SA:EA处的数据传入ax中。即:(ax)=((ds)*16+(bx))。
mov [bx],ax
功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将ax中的数据送入内存SA:EA处。即:((ds)*16+(bx))=(ax)

程序和内存中的情况如图所示,写出程序执行后,21000H~21007H单元中的内容。(inc bx的含义是bx中的内容加1)
在这里插入图片描述

mov ax,2000H
mov ds,ax
mov bx,1000H
mov ax,[bx]
inc bx
inc bx
mov [bx],ax
inc bx
inc bx
mov [bx],ax
inc bx
mov [bx],al
inc bx
mov [bx],al

执行后:
在这里插入图片描述

5.2 Loop指令

用cx和loop指令相配合实现循环功能的程序框架如下:

	mov cx,循环次数
s:
	循环执行的程序段
	loop s

第6章 包含多个段的程序

6.1 在代码段中使用数据

考虑这样一个问题,编程计算以下8个数据的和,结果存在ax寄存器中:
0123h、0456h、0789h、0abch、0defh、0fedh、0cbah、0987h

assume cs:code
code segment
	dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
start:	mov bx,0
		mov ax,0
		mov cx,8
  	s:	add ax,cs:[bx]
		add bx,2
		loop s
		mov ax,4c00h
		int 21h
code ends
end start
  • 程序第一行的“dw”的含义是定义字型数据。dw即“define word”。在这里,定义了8个字型数据(数据之间以逗号分隔),它们所占的内存空间的大小为16个字节。“db”的含义则是定义字节型数据。
  • end除了通知编译器程序结束外,还可以指明程序的入口在标号start处。
    我们可以这样安排程序的框架(便于debug):
    assume cs:code
    code segment
    		..........
    		...数据...
    		..........
    start:
    		..........
    		...代码...
    		..........
    code ends
    end start
    
1.下面的程序实现依次用内存0:00:15单元中的内容改写程序中的数据,完成程序:

assume cs:codesg

codesg segment

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

 start:mov ax,0

     mov ds,ax

     mov bx,0

     mov cx,8

   s: mov ax,[bx]

     ____mov cs:[bx],ax____

     add bx,2

     loop s

     mov ax,4c00h

     int 21h

codesg ends

end start

2.下面的程序实现依次用内存0:00:15单元中的内容改写程序中的数据,数据的传送用栈来进行。栈空间设置在程序内。完成程序:

assume cs:codesg

codesg segment

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

  dw 0,0,0,0,0,0,0,0,0,0 ;10个字单元用栈空间

 start:

     mov ax,__cs__ 

     mov ss,ax

     mov sp,__24h__ 

     mov ax,0

     mov ds,ax

     mov bx,0

     mov cx,8

   s:

     push [bx]

     ___pop cs:[bx]___

     add bx,2

     loop s

     mov ax,4c00h

     int 21h

codesg ends

end start
注意:程序中的数据是0123h~0987h,是使用别处的数据(位于内存0:0~0:15)对它们进行更新。cs指向的是0123h~0987h所在的段。
解答:第二空为什么是24h?因为0123h~0987h为0h~0Fh,栈空间为11h~23h,sp指向下一个即24h。

第7章 更灵活的定位内存地址的方法

7.1 and和or指令

  • and指令:逻辑与指令,按位进行与运算。
    例如指令:
    mov al,01100011B
    and al,00111011B
    
    执行后:al=00100011B
  • or指令:逻辑或指令,按位进行或运算。
    例如指令:
    mov al,01100011B
    or al,00111011B
    
    执行后:al=01111011B

7.3 以字符形式给出的数据

我们可以在汇编程序中,用 ‘…’ 的方式指明数据是以字符的形式给出的,编译器将把它们转化为相对应的ASCII码。
例如:

db 'unIX'
mov al,'a'

7.5 [bx+idata]

[bx+idata]表示一个内存单元,它的偏移地址为(bx)+idata(bx中的数值加上idata)。
下面三种形式是等价的:

mov ax,[200+bx]
mov ax,200[bx]
mov ax,[bx].200

7.7 SI和DI

si 和 di 是8086CPU中和 bx 功能相近的寄存器,si和di不能够分成两个8位寄存器来使用。

7.10 不同的寻址方式的灵活应用

  • [idata]用一个常量来表示地址,可用于直接定位一个内存单元;
  • [bx]用一个变量来表示内存地址,可用于间接定位一个内存单元;
  • [bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元;
  • [bx+si]用两个变量表示地址;
  • [bx+si+idata]用两个变量和一个常量表示地址。

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

我们定义的描述性符号:reg(寄存器)和 sreg(段寄存器)。

  • reg 的集合包括:ax、bx、cx、dx、ah、al、bh、bl、ch、cl、dh、dl、sp、bp、si、di;
  • sreg 的集合包括:ds、ss、cs、es。

8.1 bx、si、di 和 bp

  • 在8086CPU中,只有这4个寄存器可以用在 “[…]” 中来进行内存单元的寻址。
  • 在[…]中,这4个寄存器可以单个出现,或只能以4种组合出现:bx 和 si、bx 和 di、bp 和 si、bp 和 di。
  • 只要在[…]中使用寄存器 bp ,而指令中没有显性地给出段地址,段地址就默认在 ss 中。

8.3 汇编语言中数据位置的表达

立即数(idata)

立即数在汇编指令中直接给出。

例:mov ax,1

段地址(SA)和偏移地址(EA)

在汇编指令中可用 [X] 的格式给出 EA,SA 在某个段寄存器中。

存放段地址的寄存器可以显性给出。

例:mov ax,ds:[bp]

8.4 寻址方式

寻址方式 名称
[idata] 直接寻址
[bx] 寄存器间接寻址
[bx+idata] 寄存器相对寻址
[bx+si] 基址变址寻址
[bx+si+idata] 相对基址变址寻址

8.5 指令要处理的数据有多长

在没有寄存器名存在的情况下,用操作符 X ptr 指明内存单元的长度,X 在汇编指令中可以为 word 或 byte。

  • word ptr——指令访问一个字单元
  • byte ptr——指令访问一个字节单元

假设我们用 Debug 查看内存的结果如下:

2000:1000 FF FF FF FF FF FF ...

那么指令:

mov ax,2000H
mov ds,ax
mov byte ptr [1000H],1

将使内存中的内容变为:

2000:1000 01 FF FF FF FF FF ...

而指令:

mov ax,2000H
mov ds,ax
mov word ptr [1000H],1

将使内存中的内容变为:

2000:1000 01 00 FF FF FF FF ...

push 指令不用指明访问的是字单元还是字节单元,因为 push 指令只进行字操作。

8.7 div 指令

div 是除法指令,使用 div 做除法的时候应该注意以下问题。

  • 除数:有 8 位和 16 位两种,在一个 reg 或内存单元中。
  • 被除数:默认放在 AX 或 DX 和 AX 中,如果除数为 8 位,被除数则为 16 位,默认在 AX 中存放;如果除数为 16 位,被除数则为 32 位,在 DX 和 AX 中存放,DX 存放高 16 位,AX 存放低 16 位。
  • 结果:如果除数为 8 位,则 AL 存储除法操作的商,AH 存储除法操作的余数;如果除数为 16 位,则 AX 存储除法操作的商,DX 存储除法操作的余数。

几个例子:

div byte ptr ds:[0]
含义:	(al) = (ax) / ((ds) * 16 + 0)   的商
		(ah) = (ax) / ((ds) * 16 + 0)   的余数
div word ptr [bx+si+8]
含义:	(ax) = [(dx) * 10000H + (ax)] / ((ds) * 16 + (bx) + (si) + 8)	的商
		(dx) = [(dx) * 10000H + (ax)] / ((ds) * 16 + (bx) + (si) + 8)	的余数

8.8 伪指令dd

dd是用来定义 dword(doubleword,双字)型数据的。比如:

data segment
db 1
dw 1
dd 1
data ends

在 data 段定义了 3 个数据:

  • 第一个数据为 01H,在 data:0 处,占 1 个字节;
  • 第二个数据为 0001H,在 data:1 处,占1个字;
  • 第三个数据为 00000001H,在 data:3 处,占 2 个字。

用 div 计算 data 段中第一个数据除以第二个数据后的结果,商存在第三个数据的存储单元中。

data segment
dd 100001
dw 100
dw 0
data ends

分析:
data 段中的第一个数据是被除数,为 dword(双字)型,32 位,所以在做除法之前,用 dx 和 ax 存储。应将 data:0 字单元中的低 16 位存储在 ax 中,data:2 字单元中的高 16 位存储在 dx 中。程序如下:

mov ax,data
mov ds,ax
mov ax,ds:[0]	;ds:0字单元中的低16位存储在ax中
mov dx,ds:[2]	;ds:2字单元中的高16位存储在dx中
div word ptr ds:[4]	;用dx:ax中的32位数据除以ds:4字单元中的数据
mov ds:[6],ax	;将商存储在ds:6字单元中

8.9 dup

dub 是和 db、dw、dd 等数据定义伪指令配合使用的,用来进行数据的重复。

比如:

db 3 dup (0)
db 3 dup (0,1,2)

相当于:

db 0,0,0
db 0,1,2,0,1,2,0,1,2

第9章 转移指令的原理

可以修改 IP,或同时修改 CS 和 IP 的指令统称为转移指令。概括地讲,转移指令就是可以控制 CPU 执行内存中某处代码的指令。

8086CPU 的转移行为有以下几类:

  • 段内转移(只修改 IP)
    例如:
    jmp ax
    
    段内转移根据 IP 的修改范围又分为
    • 短转移(short)(修改范围为-128~127,一个字节)
    • 近转移(near)(修改范围为-32768~32767,一个字)
  • 段间转移(far,又称为远转移)(同时修改 CS 和 IP)
    例如:
    jmp 1000:0
    

8086CPU 的转移指令分为以下几类:

  • 无条件转移指令(如:jmp)
  • 条件转移指令(如:jcxz)
  • 循环指令(如:loop)
  • 过程
  • 中断

9.1 操作符 offset

offest 的功能是取得标号的偏移地址。比如下面的程序:

assume cs:codesg
codesg segment
	start:mov ax,offset start	;相当于mov ax,0
		s:mov ax,offset s		;相当于mov ax,3
codesg ends
end start

在上面的程序中,offset 操作符取得了标号 start 和 s 的偏移地址 0 和 3。第一条指令长度为 3 个字节,则 s 的偏移地址为 3 。

有如下程序段,添写两条指令,使该程序在运行中将 s 处的一条指令复制到 s0 处。

assume cs:codesg
codesg segment
	s:	mov ax,bx
		mov si,offest s
		mov di,offset s0
		__mov ax,cs:[si]__
		__mov cs:[di],ax__
   s0:	nop
   		nop
codesg ends
end s

9.3 依据位移进行转移的 jmp 指令

转移位移的计算方法:
在这里插入图片描述

9.6 转移地址在内存中的 jmp 指令

转移地址在内存中的 jmp 指令有两种格式:

  • jmp word ptr 内存单元地址(段内转移)
    例如:
    mov ax,0123H
    mov ds:[0],ax
    jmp word ptr ds:[0]
    
    执行后,(IP)=0123H。
  • 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。
程序如下:
assume cs:code

data segment
	?
data ends

code segment

   start: mov ax,data
            mov ds,ax
            mov bx,0
            jmp word ptr [bx+1]

code ends
end start

若要使程序中的jmp指令执行后,CS:IP指向程序的第一条指令,在data段中应该定义哪些数据?
答:db 8 dup (0)

程序如下:
assume cs:code,ds:data

data segment
   dd 12345678h
data ends

code segment

  	start: mov ax,data
           mov ds,ax
           mov bx,0
           mov [bx],__bx__
           mov [bx+2],__cs__
           jmp dword ptr ds:[0]

code ends

end start

补全程序,使jmp指令执行后,CS:IP指向程序的第一条指令。

用Debug查看内存,结果如下:

     2000:1000 BE 00 06 00 00 00 ......

则此时,CPU执行指令:

   mov ax,2000H
   mov es,ax
    jmp dword ptr es:[1000H]

后,(CS)=__0006__ H, (IP)=__00BE__H

9.7 jcxz 指令

jcxz 指令为有条件转移指令,所有的有条件转移指令都是短转移。

“jcxz 标号”的功能用 C 语言描述:

if((cx)==0) jmp short 标号;
补全编程,利用jcxz指令,实现在内存2000H段中找查第一个值为为0的字节,找到后,将它的偏移地址存储在dx中。

assume cs:code
code segment
    start: mov ax,2000H
             mov ds,ax
             mov bx,0
          s: __mov ch,0__
             __mov cl,[bx]__
             __jcxz ok__
             __inc bx__
             jmp short s
        ok: mov dx,bx
            mov ax,4c00h
            int 21h
 code ends
 end start

9.8 loop 指令

补全程序,利用loop指令,实现在内存2000H段中查找第一个值为0的字节,找到后,将它的偏移地址存储在dx中。

 assume cs:code
 code segment
     start: mov ax,2000h
              mov ds,ax
              mov bx,0
         s:   mov cl,[bx]
              mov ch,0
               __inc cx__
              inc bx
              loop s
        ok: dec bx	;dec指令的功能和inc相反,dec bx进行的操作为:(bx)=(bx)-1
            mov dx,bx
            mov ax,4c00h
            int 21h
 code ends
 end start

第10章 CALL 和 RET 指令

10.1 ret 和 retf

  • ret 指令用栈中的数据,修改 IP 的内容,从而实现近转移,相当于:
    pop IP
    
  • reft 指令用栈中的数据,修改 CS 和 IP 的内容,从而实现远转移,相当于:
    pop IP
    pop CS
    
补全程序,实现从内存1000:0000处开始执行指令。
assume cs:code
stack segment
	db 16 dup (0)
stack ends

code segment
start:	mov ax,stack
		mov ss,ax
		mov sp,16
		mov ax,__1000H__
		push ax
		mov ax,__0__
		push ax
		retf
code ends

end start

10.2 call 指令

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

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

10.3 依据位移进行转移的 call 指令

CPU 执行“call 标号”时,相当于进行:

push IP
jmp near ptr 标号

下面的程序执行后,ax 中的数值为__6__。

内存地址 机器码 汇编指令
1000:0 b8 00 00 mov ax,0
1000:3 e8 01 00 call s
1000:6 40 inc ax
1000:7 58 s:pop ax

10.4 转移的目的地址在指令中的 call 指令

CPU 执行“call far ptr 标号”时,相当于进行:

push CS
push IP
jmp far ptr 标号

下面的程序执行后,ax 中的数值为__1010H__。

内存地址 机器码 汇编指令
1000:0 b8 00 00 mov ax,0
1000:3 9A 09 00 00 10 call far ptr s
1000:8 40 inc ax
1000:9 58 s:pop ax
add ax,ax
pop bx
add ax,bx

10.5 转移地址在寄存器中的 call 指令

CPU 执行“call 16位reg”时,相当于进行:

push IP
jmp 16位reg

下面的程序执行后,ax 中的数值为__000BH__。

内存地址 机器码 汇编指令
1000:0 b8 06 00 mov ax,6
1000:3 ff d0 call ax
1000:5 40 inc ax
1000:6 mov bp,sp
add ax,[bp]

第11章 标志寄存器

8086CPU 的 flag 寄存器的结构如图所示:
在这里插入图片描述

11.1 ZF 标志

零标志位。

mov ax,1
sub ax,1

执行后,结果为 0,则 zf=1。

mov ax,2
sub ax,1

执行后,结果不为0,则 zf=0。

11.2 PF 标志

奇偶标志位。

mov al,1
add al,10

执行后,结果为 00001011B,其中有 3(奇数)个 1,则 pf=0。

mov al,1
or al,2

执行后,结果为 00000011B,其中有 2(偶数)个 1,则 pf=1。

11.3 SF 标志

符号标志位。

mov al,10000001B
add al,1

执行后,结果为 10000010B,sf=1,表示:如果指令进行的是有符号数运算,那么结果为负。

mov al,10000001B
add al,01111111B

执行后,结果为 0,sf=0,表示:如果指令进行的是有符号数运算,那么结果为非负。

检测点11.1

11.4 CF 标志

进位/借位标志位。

mov al,98H
add al,al	;执行后:(al)=30H,CF=1,CF记录了从最高有效位向更高位的进位值
add al,al	;执行后:(al)=60H,CF=0,CF记录了从最高有效位向更高位的进位值
mov al,97H
sub al,98H	;执行后:(al)=FFH,CF=1,CF记录了向更高位的借位值
sub al,al	;执行后:(al)=0,CF=0,CF记录了向更高位的借位值

11.5 OF 标志

溢出标志位。

11.6 adc 指令

adc 是带进位加法指令,它利用了 CF 位上记录的进位值。
比如指令 adc ax,bx 实现的功能是:(ax)=(ax)+(bx)+CF

11.7 sbb 指令

sbb 是带借位减法指令,它利用了 CF 位上记录的借位值。
比如指令 sbb ax,bx 实现的功能是:(ax)=(ax)-(bx)-CF

11.8 cmp 指令

cmp 是比较指令,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,说明(ax)≤(bx)

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

指令 含义 检测的相关标志位
je 等于则转移 zf=1
jne 不等于则转移 zf=0
jb 低于则转移 cf=1
jnb 不低于则转移 cf=0
ja 高于则转移 cf=0 且 zf=0
jna 不高于则转移 cf=1 或 zf=1

第一个字母 j 表示 jump,后面的字母表示意义如下:

e:表示 equal
ne:表示 not equal
b:表示 below
nb:表示 not below
a:表示 above
na:表示 not above

11.11 pushf 和 popf

pushf 的功能是将标志寄存器的值压栈,而 popf 是从栈中弹出数据,送入标志寄存器中。

猜你喜欢

转载自blog.csdn.net/qq_44491553/article/details/110317066