当前位置:   article > 正文

汇编语言-考试重点_从 0500h 单元开始依次输入数据:09h(数据个数)12h、80h、78h、c8h、00h、00

从 0500h 单元开始依次输入数据:09h(数据个数)12h、80h、78h、c8h、00h、00h

复习大纲参考

① 题型:选择题、填空题、简答题、程序分析、代码填空、编程题,论述题。
编程程序分析主要在六七八章,注意上课讲的例子、课后作业、实验
③ 一、二、四、五章一些关键的东西。名词、对应的代码形式等。
重点关注一下上课讲的例题习题
下方图片中左半图是书本上复习的重要内容,右半图是重要的习题。

第一章 计算机基本原理

1.2 计算机中数据表示

1.2.1 不同进位计数制及相互转换

  • 二进制+B
  • 十进制+D
  • 十六进制+F

转换

  1. 二进制、十六进制转换为十进制:对应位的数值乘以对应的权之和——例:5FH=5*16^1+15*16^0=95D
  2. 十进制转换为二进制:
    1. 降幂法(适于数值不大):写出小于此数的二进制权值后求和——例:13.5H=8+4+2+1+0.5=1101.1B
    2. 除2求余法:不断除以2,记下余数,直到商为0为止——例:13D=1101B
  1. 十进制转换为十六进制:

同2.

  1. 二进制数转换十六进制

一位十六进制数由四位二进制数组成

1.2.2 二进制和十六进制运算

运算规则
  1. 二进制
    1. 加法:0+0=0;0+1=1;1+1=0(进位1)
    2. 乘法:0*0=0;0*1=0;1*1=1
  1. 十六进制
    1. 加减符合逢16进一
    2. 可以先转换为二/十进制运算,最后结果转换十六进制

1.2.3 带符号数的补码表示

带符号数:最高位是符号位,一般规定正数符号位0,负数符号位1

机器数:一个数连同其符号在内数值化表示。机器数表示可以用不同码制,常用的有原码、补码、反码。

补码
  • 正数:符号位+绝对值表示,即:数最高位0,其余部分为该数绝对值
  • 负数:对其正数(符号位此时为0)各位取反(符号位一样取反),最低位加1(求补运算:二进制取反加1)

1.2.4 补码加减

  1. 加法规则:[X+Y]补 = [X]补 + [Y]补
  2. 减法规则:[X-Y]补 = [X]补 + [-Y]补
  • 不必考虑数正负,符号位参与运算即可
  • 从最高有效位向高位的进位由于机器字长的限制而自动丢弃

1.2.5 无符号数表示

把最高有效位也作为数值

U1习题

1.3 十进制转换为二进制、十六进制

(1)67 (2)34 (3)254 (4)123

答:

(1)6710=10000112 6710=4316

(2)3410=1000102 3410=2216

(3)25410=111111102 25410=FE16

(4)12310=11110112 12310=7B16

1.4 下列十进制数转换为二进制数和十六进制数

(1)01101101 (2)10110010 (3)111111

答:

(1)011011012=10910 011011012=6D16

(2)101100102=17810 101100102=B216

(3)1111112=6310 1111112=3F16

1.5 作下列十六进制的运算

(1)5A+64 (2)86-49 (3)123-9A (4)43x2B

答:

(1)BE16

(2)3D16

(3)8916

(4)B4116

1.6 根据补码定义把下列十进制表示为8位二进制补码

(1)64 (2)-24

答:

(1)010000002

(2)111010002

第二章 计算机基本原理

2.2 存储器

2.2.1 16位结构的CPU

8086是16位结构的CPU,具有以下4方面结构特征:

  1. 数据总线为16位
  2. 运算器一次最多可以处理16位的数据
  3. 寄存器的最大宽度为16位
  4. 寄存器和运算器之间的通路为16位

2.2.2 存储器

基本存储单元
  1. 最小单元:一个二进制位bit
  2. 字节byte:8位二进制位
  3. 字:2个字节;双字:2个字
  4. 80x86内存储器以字节为基本存储单位/基本存储单元——>对内存的读写至少一个字节
内存中字的存储
  1. 字节:byte,一个字节由8位bit组成,可存放8位寄存器中
  2. 字:word,一个字由两个字节组成,分别称为高位字节和低位字节

当处理16为数据,需要以字为单位表示,需要两个字节单元存放,并且规定:低字节数据存放于低地址单元,高字节数据存放于高地址单元。

  • 8086CPU有20位地址总线,可以传送20位地址,即物理地址有20位
  • 8086CPU又是16位结构,如何用16位结构实现20位的物理地址的传送和内存寻址?8086采用内部使用2个16位地址合成来形成一个20位物理地址的方法

2.2.3 存储器分段

分段

内存无分段,段的划分来着CPU

内存单元的物理地址=段地址*16+偏移地址

段类型

逻辑段分为:代码段、数据段、附加段、堆栈段

存储器逻辑分段类型:

  • 代码段——用于存放指令,代码段段基址存放段寄存器CS
  • 数据段——用于存放数据,数据段段基址存放段寄存器DS
  • 附加段——用于辅助存放数据,附加段段基址存放段寄存器ES
  • 堆栈段——重要数据结构,堆栈段段基址存放段寄存器SS

2.2.4 逻辑地址

逻辑地址分为段地址、偏移地址

8086CPU内部寄存器只有16位,无法存放20位地址,故计算公式:

段地址*16(二进制,向左移动四位)+偏移地址=物理地址

例:段基址1896H,偏移地址1655H。其物理地址?

18960H+1655H=19FB5H

段重叠:数据段紧接着附加段的最后单元存放,而不必在附加段的64kb最大区域之外设置其他段

2.2.5 CPU对内存的读写

CPU进行数据读写必须和外部进行信息交互:

  1. 存储单元的地址(地址信息)
  2. 器件的选择,读写命令(控制信息)
  3. 读写数据(数据信息)

总线逻辑上分三类:地址总线、控制总线、数据总线

2.3 CPU中的寄存器

2.3.1 寄存器

8086CPU所有寄存器都是16位,可以存放两个字节。

  1. 通用寄存器(存放一般性数据/存放地址)
    1. AX:累加器,运算较多时运用,有些指令规定必须使用它(add)
    2. BX:基址寄存器,除了存放数据,还经常存放一段内存的起始偏移地址(base)
    3. CX:计数寄存器,除了存放数据,还经常存放重复操作的次数(count)
    4. DX:数据寄存器,除了存放数据,还有时存放32位数据的高16位(data)
    5. 这四个寄存器都可以分为两个独立的8位寄存器使用:AH,AL,BH,BL,CH,CL,DH,DL例:AX:15-0  中  AH:15-8(高位),AL:7-0(低位) 
  2. 地址寄存器(存放数据所在偏移地址,存放数据)
    1. SP:堆栈指针,是专用的寄存器,存放堆栈栈顶的偏移地址
    2. BP:基址指针,用来存放内存中数据的偏移地址
    3. SI:源变址寄存器,用来存放内存中源数据区的偏移地址,所谓变址寄存器,指某些指令下可以自动递增/递减其中的值
  3. 段寄存器
    1. CS:代码段寄存器,存放当前正在执行的程序段的段基址
    2. SS:堆栈段寄存器,存放堆栈段的段基址
    3. DS:数据段寄存器,存放数据段的段基址
    4. ES:附加段寄存器,存放另一个数据段的段基址
  4. 指令指针寄存器
    1. IP,存放即将执行指令的偏移地址
  5. 标志寄存器

             FLAGS:存放CPU两类标志

            a.状态标志:反应处理器当前的状态,有无溢出/进位。状态标志:CF,PF,AF,ZF,SF,OF

            b.控制标志:控制CPU的工作方式,是否响应可屏蔽中断。控制标志:TF,IF,DF

OF:运算结果超出可以表示的范围

DF:控制地址变化方向,0为加法修改地址,1为减法

IF:1允许处理器响应可屏蔽中断请求信号,即开中断;0为不允许,即关中断

SF:1表示运算结果最高位为‘1’。对于有符号数,OF=0时,SF=1表示运算结果为负,SF=0为非负;OF=1由于结果错误,所以符号位也和正确值相反,。对于无符号数运算,无意义。

AF:字操作时,低字节向高字节进位时,AF=1,否则为0

PF:1表示运算结果低8为有偶数个1,0则表示奇数个

CF:1表示无符号数加法有进位/减法有借位,需要对高位补充处理;0表示无进位/借位

状态标志在每次运算后自动产生,控制标志值由指令设置

2.3.2 CS和IP

8086CPU工作过程

  1. 从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器
  2. IP=IP+所读取指令的长度,从而指向下一条指令
  3. 执行指令,转到步骤1,重复过程

2.3.3 堆栈

数据在堆栈区存放时,必须以字存入,每次存入一个字,后存入的数据依次放入栈的低地址单元中。栈指针SP每次-2,由栈指针SP指出当前栈顶的位置,数据存取时采用先进后出的方式

2.4 外部设备和接口

接口内有若干寄存器进行统一编号,给每个寄存器规定一个端口号,CPU可以通过端口地址区分和访问不同外设。接口中寄存器(端口)分为以下三类:

  1. 数据端口:存放要在外设和主机间传送的数据,实际上起数据缓冲作用。端口传送方向可输入/输出
  2. 控制端口:传递CPU对外部设备的控制信号。信号由CPU发出,传递到接口内的控制端口,后发送到外部设备。传送方向对于CPU总是输出
  3. 状态端口:协调外设和主机的同步。外设工作状态在此得到反应。传送方向对于CPU总是输入

CPU与I/O接口中端口的信息传输也都是通过数据总线进行。

2.5 32位80x86CPU工作模式

  1. 实模式:特点-为了兼容16位机的特点。20位的物理地址由16位段地址、16位偏移地址组成,CPU地址线只能低20位线有效。可以使用32为寄存器和32位操作数。MS DOS只能在实模式下运行
  2. 保护模式:是32位8060CPU主要工作模式,特点-全部地址线参与寻址。程序访问内存是用逻辑地址(虚拟地址)。虚拟地址由16位段选择符和32位偏移地址得到,16位的段选择符存放在段寄存器中,应用程序不可更改,操作系统决定。实际物理地址-由16位段选择符对应的32位段基址和32位偏移地址组成。
  3. 虚拟8086模式:生成多个虚拟8680CPU,以便运行实模式下的8086程序

Windows下在打开的DOS窗口运行一个DOS应用程序,则该程序运行在虚拟8086模式,这是我们常用的运行模式。

U2习题

2.3 写出每条汇编指令执行后的相关寄存器值

Mov ax,1345H ax= 1345H

Mov ah,24H ax= 2445H

Mov al,45H ax= 2445H

Mov bx,3412H bx= 3412H

Mov al,bh ax= 2434H

Mov ah,bl ax= 1234H

2.4 实模式下,写出段地址和偏移地址为1234:2002、1430:0042、FF00:0FFF的物理地址

答:

(1)1234:2002 = 14342H

(2)1430:0042 = 14342H

(3)FF00:0FFF = FFFFFH

2.5 下列各数均为十进制数,请采用8位二进制补码运算,并回答标志寄存器FLAGS中CF、OF值,运算结果的十进制数为?如果采用16位二进制补码运算,其结果所代表十进制数为?FLAGS中CF、OF值?

(1)85+69 (2)85+(-69)(3)85-(-69)(4)85-(69)

答:85=55H,69=45H,-69=BBH,

8位二进制补码运算:

(1)85+69 =55H+45H=9AH=154, CF=0,OF=1

(2)85+(-69)=55H+BBH=10H=16,CF=1,OF=0

(3)85-(-69)=55H-BBH=9AH=154,CF=1,OF=1

(4)85-(69)=55H-45H=10H=16,CF=0,OF=0

16位二进制补码运算:

85=0055H,69=0045H,-69=0FFBBH,

(1)85+69 =0055H+0045H=009AH=154, CF=0,OF=0

(2)85+(-69)=0055H+0FFBBH=0010H=16,CF=1,OF=0

(3)85-(-69)=0055H-0FFBBH=009AH=154,CF=1,OF=0

(4)85-(69)=0055H-0045H=0010H=16,CF=0,OF=0

2.6 给定段地址为0001H,仅通过变化偏移地址寻址,CPU的寻址范围:0010H 到 1FFFH

答:

偏移地址的范围从 0000H 到 FFFFH(因为 16 位的偏移地址可以表示从 0 到 216−1 的所有值)。

计算物理地址的范围: 物理地址=(段地址×16)+偏移地址物理地址=(段地址×16)+偏移地址

物理地址范围=(0001H×16)+0000H 到 (0001H×16)+FFFFH

物理地址范围=0010H 到 1FFFH

2.7 有一数据存放在内存20000H单元中,现给定段地址为SA,若想用偏移地址寻址到此单元,则SA应满足的条件:最小为1001H,最大为2000H

答:

20000H-0000 再挪位

20000H-FFFF 再挪位,验证后不能到达20000H,移位后1001H满足

2.8 已知8086系统某存储单元物理地址为:52506H,你认为段基址的最大值、最小值分别?8086最多可以有多少个不同的段基址?

答:

52506 = 5250:0006 段基址最大值5250

52506 = 4251:FFF6 段基址最小值4251

2.9 从物理地址为00100H开始到00103H单元中顺序存放的数据为:12H、34H、56H、78H。请画出数据存放示意图。

(1)写出地址00101H字节单元内容

(2)写出地址00102H字节单元内容

答:

(1)34H

(2)56H

注意是字单元/字节单元——字单元为两个字节单元,且高地址在前

第四章 操作数的寻址方式

4.1 立即寻址方式

立即数:所要找的操作数直接写在指令中

注意

  1. 立即寻址方式只能用于源操作数字段
  2. 立即数的类型必须与目的操作数的类型一致

目的操作数是字节,立即数也必须是字节,或者两者都是字

立即寻址方式的用途:用于直接指定一个常数送给寄存器

MOV AL,6H

MOV AX,12AFH

4.2 寄存器寻址方式

寄存器寻址方式:操作数就是寄存器中的值,指令中给出寄存器名

对于16位操作数-寄存器:AX,BX,CX,DX,SI,DI,SP,BP

对于8位操作数-寄存器:AH,AL,BH,BL,CH,CL,DH,DL

寄存器寻址方式的用途:用于指定2个寄存器作为操作数

以上立即寻址方式和寄存器寻址方式的指令在执行时,都无需到存储器寻找操作数

以下操作数都在存储器中,偏移地址称为有效地址,称为EA

MOV AX,BX

MOV AX,CX

4.3 直接寻址方式

直接寻址方式:操作数的有效地址EA就在指令中(适用于处理单个变量)

操作数物理地址

DSx10H+EA

存储单元看作变量,存储单元的名字为变量名,内容为变量值

  • 存储器读操作:如MOV AX,DS:[2000H],表示从数据段2000H单元读出
  • 存储器写操作:如MOV DS:[2000H],AX,把MOV指令的目的操作数变为存储单元,源操作数变为CPU寄存器
  • 符号地址:如MOV AX,[VALUE]
  • 段前缀:操作数段地址默认为数据段,若操作数在其他段存放,称为段超越,需要在段超越前缀中指出

MOV AX,DS:[2000H]

MOV AX,DS:[VALUE]

4.4 寄存器间接寻址方式

寄存器间接寻址:操作数的有效地址EA就在寄存器中

默认搭配:

  • DS:BX
  • DS:SI
  • DS:DI
  • SS:BP

MOV AX,[BX]

MOV DX,[BP]

MOV ES:[DI],AX

4.5 寄存器相对寻址方式

寄存器相对寻址方式:操作数的有效地址EA是一个寄存器和位移量之和

MOV AX,TOP[SI](DS为段地址)

MOV [BX+2623H],AX (DS为段地址)

4.6 基址变址寻址方式

基址变址寻址方式:操作数的有效地址是一个基址寄存器和一个变址寄存器的内容之和

允许使用的基址寄存器:BX,BP

允许使用的变址寄存器:SI,DI

操作数物理地址

  • DS x 10H +BX +DI
  • DS x 10H +BX +SI
  • SS x 10H + BP +SI
  • SS x 10H + BP +DI

MOV AX,[BX][SI] (DS段地址)

MOV AX,ES:[BX][DI] (SS段地址)

4.7 相对基址变址寻址方式

相对基址变址寻址方式:操作数的有效地址是一个基址寄存器和一个变址寄存器以及一个位移量之和。

以下都是DS为段地址:

MOV AX,MASK[BX][SI]

MOV AX,[BX+SI].MASK

MOV AX,[MASK+BX+DI]

U4习题

4.1 段地址?有效地址?逻辑地址?物理地址?用指令举例说明

答:若DS=1500H,MOV AX,DS:[2000H]中,2000H为有效地址,1500H为段地址物理地址为15000H+2000H=17000H,逻辑地址为2000H

4.2 指出以下指令的寻址方式,array为变量

(1)MOV AX,9

(2)MOV BYTE PTR[BX],9

(3)MOV BX,[DI]

(4)MOV AX,BX

(5)MOV [SI+BX],9

(6)MOV ARRAY[BX],CX

(7)MOV AX,ARRAY+9

(8)MOV AX,ARRAY[BX+DI]

答:

(1)立即寻址

(2)寄存器间接寻址 (BTYE PTR/WORD PTR表明字节/字类型)

(3)寄存器间接寻址

(4)寄存器寻址方式

(5)基址变址寻址方式

(6)寄存器相对寻址方式

(7)直接寻址方式

(8)相对基址变址寻址方式

4.3 假定DS=1200H,SS=4400H,BX=463DH,BP=2006H,SI=6A00H,位移量D=4524H,以AX寄存器为目的操作数,试写出以下寻址方式的传送指令,并确定操作数的有效地址EA和物理地址

(1)立即寻址
(2)直接寻址
(3)使用BX的寄存器寻址;无EA
(4)使用BX的间接寻址
(5)使用BP的寄存器相对寻址
(6)基址变址寻址
(7)相对基址变址寻址

答:

(1)操作数在指令中无EA
(2)直接寻址:EA=4524H,物理地址=DS:4524
(3)使用BX的寄存器寻址:无EA
(4)使用BX的间接寻址:EA=463DH,物理地址=DS:463D
(5)使用BP的寄存器相对寻址:MOV AX,[BP+4524],EA=2006+4524,物理地址=SS:EA
(6)基址变址寻址: MOV AX,[BX+SI],EA= BX+SI,物理地址=DS:EA
(7)相对基址变址寻址:MOV AX,[4524+BX+SI],EA=4524+BX+SI,物理地址=DS:EA

4.4 在数据段定义了ARRAY数组,其中依次存储了五个字数据,ARRAY的起始地址(第一个数据的地址)为24H,请用不同寻址方式的指令,把第5个字送AX寄存器,指令条数不限。

答:

(1)直接寻址
MOV AX,ARRAY+8 或MOV AX,[ARRAY+8]
(2)使用BX的间接寻址
LEA BX,ARRAY+8 ;MOV AX,[BX]
(3)使用BX的寄存器相对寻址
LEA BX,ARRAY ;MOV AX,[BX+8]
(4)基址变址寻址
LEA BX,ARRAY ; MOV SI,8 ; MOV AX,[BX+SI]

第五章 常用指令系统

  • 标号:符号地址,用来表示指令在内存中的位置,以便程序中其他指令能引用该指令,通常作为转移指令的操作数,以表示转向的目标地址。当一条指令使用标号时,应加:
  • 指令助记符:指令名称,指令功能的英文缩写。如MOV
  • 操作数:指令要操作的数据或数据所在地址。操作数可以是寄存器,常量,变量,表达式

双操作数:左边为目的操作数DST(参与指令操作且存放操作结果);右边为源操作数SRC

  • 注释:由“;”开始

5.1 数据传送指令

  1. 通用数据传送指令
  2. 累加器专用传送指令
  3. 地址传送指令
  4. 标志寄存器传送

5.1.1 通用数据传送指令

  • MOV:传送
  • PUSH:进栈
  • POP:出栈
  • XCHG:交换

双操作数指令规定:

  1. 源操作数与目的操作数长度必须明确且一致,同时为8/16位
  2. 目的操作数与源操作数不能同为存储器,不允许在两个存储单元之间直接传送数据
  3. 目的操作数不能为CS或IP,因为CS:IP指向的是当前要执行的指令所在的地址
  4. 目的操作数不可为立即数

5.1.2 累加器专用传送指令

  • IN:输入
  • OUT:输出
  • XLAT:换码
IN

把端口号PORT或由DX指向的端口的数据输入累加器。根据端口号长度有长格式、短格式。

  • 端口号范围——00~FFH—>长格式(指其机器指令长度为2字节(端口号占1字节))
  • 端口号范围——0100H~0FFFFH—>短格式(指令长度为1字节(端口号放在DX寄存器中))
OUT

同IN

XLAT

格式:XLAT

操作:AL<—BX+AL

把BX+AL的值作为有效地址,取出其中的一个字节送AL

5.1.3 地址传送指令

  • LEA:有效地址送寄存器
  • LDS:指针送寄存器和DS
  • LES:指针送寄存器和ES
LEA

把源操作数有效地址EA送到指定寄存器

LDS

把源操作数所指向的内存单元中2个字送到指定寄存器(SRC)和DS(SRC+2)

LES

把源操作数所指向的内存单元中2个字送到指定寄存器(SRC)和ES(SRC+2)

5.1.4 标志寄存器传送指令

  • LAHF:标志寄存器低字节送AH寄存器
  • SAHF:AH送标志寄存器
  • PUSHF:标志入栈
  • POPF:标志出栈

5.2 算术运算指令

5.2.1 类型扩展指令

  • CBW:字节扩展成字
  • CWD:字扩展成双字
CBW

默认将AL内容扩展到AX中,扩展方式为符号扩展

如果AL最高位1(负数),则CBW指令扩展时使AH=FFH

0(正数),则 AH=00H

4位有符号数(范围-8~7)1000H表示-8,1111H表示-7

CWD

如果AX最高位1(负数),则CBW指令扩展时使DH=FFFFH

0(正数),则 DH=0000H

5.2.2 加法指令

  • ADD:加法
  • ADC:带进位加法
  • INC:加1
ADD

将源操作数和目的操作数相加,结果存在目的操作数中。加法会影响CF,OF

注意:加法结果二进制位数

MOV AL,72H

MOV AL,93H

(1)值认为无符号数时:结果为105H,需要9位二进制表示,而AL只能存放8位二进制,所以AL存入低8位数值,即05H

(2)值认为有符号数时:该数据为补码形式

72H=01110010B=114D=[114D]补

93H=10010011B=[-109D]补

加法运算:

  • 无符号数:CF=0表示结果正确,CF=1则错误
  • 有符号数:不用考虑CF结果,考虑OF

两个有符号数的符号相同时可能发生溢出,需要根据OF判断(当运算1结果与符号相反时,OF=1)

ADC

格式:ADC DST,SRC

操作:DST<-DST+SRC+CF(运算前CF标志位的值)

为实现双精度加法,必须用两条指令分别完成低位字和高位字的加,并在高位字相加时使用ADC指令,从而把低位字相加时的进位值加进去。不论有无符合数,低位字相加无需考虑溢出,只有高位字相加所产生的CF,OF才是判断是否溢出的依据

如:数A存入DX(高位字),AX(低位字),数B存入BX(高位字),CX(低位字)

ADD AX,CX

ADC DX,BX

INC

格式:INC OPR

操作:OPR<-OPR+1

该指令不影响CF标志位

5.2.3 减法指令

  • SUB:减法
  • SBB:带借位减法
  • DEC:减1
  • NEG:求补
  • CMP:比较
SUB

格式:SUB DST SRC

操作:DST<-DST-SRC

SBB

格式:SBB DST SRC

操作:DST<-DST-SRC-CF

DEC

格式:DEC OPR

操作:OPR<-OPR-1

该指令不影响CF标志位

NEG

格式:NEG OPR

操作:OPR<-(-OPR)

=求补码

CMP

格式:CMP OPR1,OPR2

操作:OPR1-OPR2

虽然做减法,但是不返回结果,只产生标志位

cmp a,b——a<b,CF=1 , a>=b,CF=0(a=b,ZF=1,否则=0)

减法运算时:两个有符号数符号相同时,无论正数或者负数,都不会发生溢出;符号相反时可能发生溢出,需要判断OF

以上加减法指令都可作字或字节运算,除了INC,DEC指令不影响CF标志外,其他指令都影响条件标志位

5.2.4 乘法指令

  • MUL:无符号数乘法
  • IMUL:有符号数乘法
MUL

格式:MUL SRC

操作:当操作数为字节时,AX<-AL x SRC

当操作数为字时,DX,AX<-AX x SRC

乘法运算中,目的操作数默认是累加器AX,不必在指令中写出。因为两个相乘的数需长度相同,根据SRC长度,默认参与运算是AL/AX寄存器的值。SRC可以是寄存器、变量,但不能是立即数,因为立即数长度明确。

5.2.5 除法指令

  • DIV:无符号除法
  • IDIV:有符号数除法
DIV

格式:DIV SRC

操作:SRC为字节,AL<-AX/SRC的商,AH<-AX/SRC的余数

SRC为字,AX<-AX/SRC的商,DX<-AX/SRC的余数

和乘法相同,除法需要考虑是否为有无符号数,而选择不同指令,SRC不能为立即数。由于除法指令字节操作需要被除数为16位,字操作要求被除数32位,因此往往需要符号扩展,使被除数长度比除数长度扩一倍。

注意:乘法不会溢出,除法会溢出

除法是字节类型:要求商8位,如果被除数的高8位绝对值≥除数的绝对值——商会溢出

除法是字类型:要求商16位,如果被除数的高16位绝对值≥除数的绝对值——商会溢出

5.2.6 BCD码的十进制调整指令

  • DAA:加法的十进制调整指令
  • DAS:减法的十进制调整指令
DAA
  1. 如果 AL 寄存器的低四位(AL 的低半字节)大于 9 或 AF=1,则AL=AL+6( AL 寄存器的低四位加上 6)。
  2. 如果 AL 寄存器的高四位(AL 的高半字节)大于 9 或 CF=1,则 AL=AL+60H,CF=1(AL寄存器的高四位加上 6) 。

如:AL=28H=28(BCD),BL=65H=65(BCD)

ADD AL,BL ; AL=28H+65H=8DH

DAA ; AL=AL+6H=8DH+6H=93H=93(BCD)

DAS
  1. 如果 AL 寄存器的低四位(AL 的低半字节)大于 9 或 AF=1,则AL=AL-6( AL 寄存器的低四位加上 6),AF=1。
  2. 如果 AL 寄存器的高四位(AL 的高半字节)大于 9 或 CF=1,则 AL=AL-60H,CF=1(AL寄存器的高四位加上 6) 。

5.3 逻辑与移位指令

5.3.1 逻辑指令

  • AND 与
  • OR 或
  • NOT 非
  • XOR 异或
  • TEST 测试
TEST

格式:TEST OPR1,OPR2

操作:OPR1与 OPR2

说明:结果不保存,只根据结果置标志位

test a,b——结果=,ZF=1,结果符号位1,SF=1,1的奇偶性设置PF

逻辑运算指令只会对部分标志位产生影响,NOT不影响任何标志位,其他指令将使CF,OF=0,AF无定义,其他根据运算结果设置

逻辑指令除了常规逻辑运算,还可以屏蔽某些位或测试某些位或使某些位置1

5.3.2 移位指令

  • SHL:逻辑左移
  • SHR:逻辑右移
  • SAL:算术左移
  • SAR:算术右移
  • ROL:循环左移
  • ROR:循环右移
  • RCL:带进位循环左移
  • RCR:带进位循环右移

移位指令均为双操作数指令,指令格式相同,以SHL为例:

  1. SHL OPR,1
  2. SHL OPR,CL(其中CL寄存器值大于1)

OPR为寄存器或内存单元,移位次数可以是1/CL寄存器,如需移位次数大于1则可以在该移位指令前把移位次数先送CL寄存器中。

移位区别:P83

对于无符号整数:算术左/右移和逻辑左/右移一样

对于有符号正式:移位之后算术的补符号位,逻辑的补0

5.4 串操作指令

  • MOVS 串传送
  • CMPS 串比较
  • SCAS 串扫描
  • STOS 存入串
  • LODS 从串取

串操作指令的重复有特定的前缀指令配合:

  • REP——重复至CX=0为止,每执行一次CX-1
  • REPE/REPZ——相等/为零重复;只有CX≠0且ZF=1(字节相等)时重复
  • REPNE/REPNZ——不相等/不为零则重复;只有CX≠0且ZF=0(字节不等)时重复

5.4.1 MOVS串传送指令

  • MOVSB:以字节为单位传送
    • 操作:ES:DI<-DS:SI DI±1,SI±1
  • MOVSW:以字为单位传送
    • 操作:ES:DI<-DS:SI DI±2,SI±2
  • MOVS DST,SRC:将源串SRC传送到目的串DST中

当方向标志DF=0时,SI,DI用+;DF=1时,SI,DI用-

  • CLD:设置正向(向前,使DF=0,SI/DI自动+)
  • STD:设置正=负向(向后,使DF=1,SI/DI自动-)

为实现串传送,使用串操作指令前需要:

  1. 数据段源串首/末地址DS/SI
  2. 附加段目的串首/末地址ES/DI
  3. 串长度送计数寄存器CX
  4. 方向标志DF

5.4.2 CMPS串比较指令

  • CMPSB:以字节为单位传送
    • 操作:ES:DI<-DS:SI, DI±1,SI±1
  • CMPSW:以字为单位传送
    • 操作:ES:DI<-DS:SI, DI±2,SI±2
  • CMPS DST,SRC:将源串SRC传送到目的串DST中

此串操作把对应字节/字相减,不保存结果,只根据结果设置标志位

5.4.3 SCAS串扫描指令

  • SCASB:以字节为单位传送
    • 操作:AL-ES:DI,DI±1
  • SCASW:以字为单位传送
    • 操作:AX-ES:DI,DI±2,SI±2
  • SCAS DST:将源串SRC传送到目的串DST中

5.4.4 STOS串存入指令

  • STOSB:以字节为单位传送
    • 操作:ES:DI<-AL, DI±1
  • STOSW:以字为单位传送
    • 操作:ES:DI<-AX,DI±2
  • STOS DST

5.4.5 LODS从串中取数指令

  • STOSB:以字节为单位传送
    • 操作:AL<-DS:SI, SI±1
  • STOSW:以字为单位传送
    • 操作:AX<-DS:SI,SI±2
  • STOS SRC

5.5 程序转移指令

  1. 无条件转移指令
  2. 条件转移指令
  3. 循环指令
  4. 子程序调用指令
  5. 中断调用指令

5.5.1 无条件转移指令与程序的可重新定位

无条件转移指令分为:

  • 段内转移:转移的目标地址与本条跳转指令在同一代码段-跳转后CS不变,IP改变
  • 段间转移:转移的目标地址与本条跳转指令不在同一代码段-跳转后CS也变
  • 直接转移:转移的目标地址在跳转指令直接给出
  • 间接转移:转移的目标地址在跳转指令间接给出
段内直接转移

格式:JMP NEAR PTR OPR

操作:IP<-IP+16位偏移量

段内间接转移

格式:JMP WORD PTR OPR

操作:IP<-EA

OPR除立即数

段间直接转移

格式:JMP FAR PTR OPR

操作:IP<-OPR的偏移地址

CS<-OPR所在段的段地址

段间间接转移

格式:JMP DWORD PTR OPR

操作:IP<-EA

CS<-EA+2

5.5.2 条件转移指令

根据上一条指令执行后所产生的标志位进行测试条件判断

具体指令P94

5.5.3 循环指令

  • LOOP:循环
    • 指令:LOOP OPR
    • 测试条件:CX≠0,循环
  • LOOPZ/LOOPE 为零/相等时循环
    • 指令:LOOPZ OPR
    • 测试条件:ZF=1 且CX≠0,循环
  • LOOPNZ/LOOPNE 不为零/不相等时循环
    • 指令:LOOPNZ OPR
    • 测试条件:ZF=0 且CX≠0,循环

以上均:首先执行CX-1再根据条件判断是否要转移

U5习题

5.5 V 是变量,指出下列错误的指令,说出错误原因,并给出合适的修改。

(1) MOV AX,[DX]

(2) MOV DS,DATA

(3) MOV CS,AX

(4) MOV AX,DL

(5) PUSH AL

(6) ADD [BX],[DI]

(7) LEA [BX],V

(8) MOV [DX],OFFSET V

(9) MOV [SI],2

(10) MUL BX,CX

(11) DIV 5

(12) MOV BYTE[SI],AX

(13) MOV AX,[SI+DI]

(14) SHR AX,4

(15) CMP 6,AX

(16) MOV [FFFF],AX

(17) MOV AX,BX+4

(18) JMP FAR PRO

答:

(1)[BX] 这种是寄存器间接寻址,规定只能BX,BP,SI,DI作间接地址寄存器,可改为:

MOV AX,[BX]

(2)需要确保DS被正确初始化,以指向正确的段,常用组合是AX(BX也可以),可改为:

MOV AX, DATA(segment)

MOV DS, AX

(3)CS是只读寄存器,不能通过MOV修改,通常是执行跳转指令时,CPU自动完成,不能由程序员完成。可改为:

MOV ES,AX

(4)寄存器字节数不匹配,可改为:

MOV AL,DL

(5)PUSH是以字为单位操作的,可改为:

PUSH AX

(6)ADD不支持同时对两个内存位置的值进行相加,需要将其中一个位置的内容加载到一个寄存器中,再执行ADD。可改为:

ADD [BX],DI

(7)LEA用于将有效地址加载到一个寄存器中,可改为:

LEA BX,V

(8)OFFSET V偏移量需要存在寄存器中,可改为:

MOV DX,OFFSET V

(9)x86不允许直接用立即数存储到内存,因为[si]是一个内存操作数,不是一个明确的类型,所以访问内存时需要知道数据数据类型。可改为:

MOV WORD PTR [SI],AX

(10)MUL不能两个寄存器直接相乘,只需要一个操作数,默认是与AX寄存器的值相乘。可改为:

MUL BX

(11)DIV的操作数不能使用立即数。可改为:

DIV BX

(12)BYTE PTR是字节类型,AX是字类型,两者类型不对应,可改为:

MOV BYTE PTR [SI],2

(13)基址变址寻址时,基址寄存器应为BX,BP,变址寄存器应为SI,DI。可改为:

MOV AX,[BX+SI]

(14)SHR逻辑右移的位数,可以是一个立即数或者是存储CL寄存器的值。可改为:

SHR AX,1

(15)立即数只能作为源操作数。可改为:

CMP AX,6

(16)AX为字类型,所以放入FFFF不合法。可改为:

MOV [FFFE],AX

(17)语法不合法,应该用间接寻址方式,可改为:

MOV AX,[BX+4]

(18)FAR PTR更显式,表示跳转目标为远指针,包含了段和偏移地址,可改为:

JMP FAR PTR PRO

5.6 在数据段定义了 ARRAY 数组,其中依次存储了 4 个字数据,根据以下要求把第 4 个字送 AX 寄存器。

(1)直接寻址

(2)使用 BX 的间接寻址

(3)使用 BX 和 ARRAY 的寄存器相对寻址

(4)基址变址寻址

(5)MOV 以外的其它指令

答:

(1)MOV AX,ARRAY+6

(2)LEA BX,ARRAY+6

MOV AX,[BX]

(3)LEA BX,ARRAY

MOV AX,[BX+6]

(4)LEA BX ARRAY

MOV SI,6

MOV AX,[BX+SI]

(5)SUB AX,AX

ADD AX,[ARRAY+6]

5.7 画出数据在数据段中的存放情况,程序执行后,BX、DI、CX、DX 寄存器中的内容是什么? 程序如下:

DATA SEGMENT

ARRAY DW 20,30,40,20H,30H,-6

BUFF DB ‘ABCD$’

DATA ENDS

CODE SEGMENT

ASSUME CS:CODE,DS:DATA

START:

MOV AX, DATA

MOV DS, AX

MOV BX, ARRAY+1

MOV DI, OFFSET ARRAY

MOV CX, [DI+5]

MOV DL, BUFF+3

MOV AH, 4CH

INT 21H

CODE ENDS

END START

答:

14 00 1E 00 28 00 20 00 30 00 FA FF 61 62 63 64 $

(BX)=1E00H,(DI)=0000H,(CX)=2000H,(DX)=0064H

5.10 在数据段有 32 位的无符号数变量 X,Y,按如下格式定义,其中‘?’请用数值代替,用 16位指令按要求写出程序。

X DW ?,?

Y DW ?,?

Z DW ?,?,?,?

(1)Z=X+Y

(2)Z=X-Y

(3)Z=|X-Y|

(4)Z=X×Y

答:

(1)

MOV AX,X

MOV DX,X+2

ADD AX,Y

ADC DX,Y+2

MOV Z,AX

MOV Z+2,DX

(2)

MOV AX,X

MOV DX,X+2

SUB AX,Y

SBB DX,Y+2

MOV Z,AX

MOV Z,DX

(3)

MOV AX,X

MOV DX,X+2

SUB AX,Y

SBB DX,Y+2

TEST AX,8000H ;判断AX是否为负数,若为负数,ZF=0,为正数,ZF=1

JZ EXIT ;正数退出

NOT AX

NOT DX ;负数都取反

ADD DX,1

ADC AX,0

Exit: MOV Z,AX

MOV Z+2,DX

(4)

MOV AX,X

MUL Y

MOV Z,AX

MOV Z+2,DX

MOV AX,X+2

MUL Y

ADD Z+2,AX

ADC DX,0

MOV Z+4,DX

MOV AX,X

MUL Y+2

ADD Z+4,AX

ADC DX,0

MOV Z+6,DX

MOV AX,X+2

MUL Y+2

ADD Z+6,AX

ADC DX,0

MOV Z+8,DX

5.11 用移位指令为主实现对 AX 中的无符号数乘以 5,不考虑乘积可能超出 16 位。

答:

MOV DX,AX

MOV CL,2

SHL AX,2

ADD AX,DX

5.12 用移位指令为主实现对 AX 中的无符号数乘以 5,考虑乘积可能超出 16 位的情况。

答:

MOV DX,0

MOV BX,AX

SHL AX,1

ADC DX,0

SHL DX,1

SHL AX,1

ADC DX,0

ADD AX,BX

ADC DX,0

5.13 把 AX 中的内容依次倒排序,即第 0 位移到第 15 位,第 1 位移到第 14 位,…。

答:

先设 AX 值

Mov di,0 ;di存储结果

Mov bx,0

Mov si,1

Mov cl,2

Ror ax,1 ;移位时,首位特殊,本来左移一位即可,但后续都在原本基础上左移两位即可,为了统一处理,原数先右移一位,即所有位数都是原先基础上左移两位得到

K: Rol ax,cl

Mov bx,ax ;移位到位后存入bx

And bx,si ;与运算之后,目标数暂存bx中

Add di,bx ;di存储结果

Shl,si,1 ;移位之后目标数也进行左移

Cmp si,0 ;判断是否超出长度(逻辑移位超出后补0全为0)

Jnz k ;cmp a,b,若相等zf=1,不等于,则zf=0。jnz,若zf=0转移

Mov ax,di

5.14 在数据段有如下定义:

BUFF DB ‘ABCD$EFGHIJK$’

STR1 DB 12 DUP(?)

LEN DB ?

用串指令编写程序完成以下操作:

(1) 对字符串 STR1 全部置‘*’符。

(2) 从左到右把 BUFF 中的字符串传送到 STR1。

(3) 从右到左把 BUFF 中的字符串传送到 STR1。

(4) 比较 BUFF 与 STR1 两个字符串是否相等,如相等则 DX=1,否则 DX=0。(5) 查找 BUFF 中有无字符$,把字符$出现的次数计入 BX 寄存器。

答:

(1)

MOV AX,DATA

MOV DS,AX

MOV AL,‘*’

LEA DI,STR1

MOV CX,STR1-BUFF

CLD

REP STOSB ;重复执行将AL寄存器中字节值存到目的地址中,直到cx值为0(STOSB)存储字节store byte的意思

(2)

MOV AX,DATA

MOV DS,AX

MOV ES,AX

CLD

LEA SI,BUFF

LEA DI,STR1

MOV CX,STR1-BUFF

REP MOVSB

(3)

MOV AX,DATA

MOV DS,AX

MOV ES,AX

STD

LEA SI,STR1-1

LEA DI,LEN-1

MOV CX,STR1-BUFF

REP MOVSB

(4)

MOV AX,DATA

MOV DS,AX

MOV ES,AX

CLD

LEA SI,BUFF

LEA DI,STR1

MOV CX,STR1-BUFF

REPE CMPSB

(5)

MOV AX,DATA

MOV ES,AX

MOV BX,0

CLD

MOV AL,‘$’

LEA SI,BUFF

MOV CX,STR1-BUFF

NEXT: REPNE SCASB

JCXZ NO-FOUND

INC BX

JMP NEXT

5.15 对于给定的 AX 和 BX 的值,执行下列程序段,程序将转向哪里?

ADD AX, BX

JNO L1 ;结果不溢出(OF=0)则转移

JNC L2 ;进位为0(CF=0)则转移

SUB AX,BX

JNC L3

JNO L4

JMP L5

(1) AX=1234H, BX=6789H

(2) AX=790EH, BX=8831H

(3) AX=E002H, BX=8086H

答:

(1)L1

(2)L1

(3)L5

5.16 下面不完整的程序段是比较 AX 和 BX 的值,把其中大的数送 MAX 变量。如果是无符号数,应如何填写指令?如果是有符号数,应如何填写指令?

CMP AX,BX ;cmp a,b——a<b,CF=1 , a>=b,CF=0

( )

MOV MAX,AX

( )

L1:MOV MAX,BX

L2:HLT

答:

无符号数:

(1)JC L1

(2)JMP L2

有符号数:

(1)JL L1

(2)JMP L2

5.17 在下列程序段的括号中分别填入如下指令,程序执行完后,AX、CX 的内容是什么?

(1) LOOP L1

(2) LOOPE L1

(3) LOOPNZ L1

MOV AX, 6

MOV CX,3

L1:ROL AX,CL

TEST AL,3

( )

答:

(1)AX=0180H,CX=0000

(2)AX=0180H,CX=0000

(3)AX=0030H,CX=0002

5.18 测试 AL 寄存器,如果最高位和最低位同时为 0,则转 L0,如果最高位和最低位只有一位为 1,则转 L1,如果最高位和最低位同时为 1,则转 L2。画出流程图,并编写程序段。

答:

Code segment

Assume cs:code

Start:

ROR AL,1 ;ROL

AND AL,3

JZ L0

SUB AL,3

JZ L2

JMP L1

L0:

JMP Exit

L1:

JMP Exit

L2:

Exit:hlt

code ends

end start

5.19 从键盘输入一个英文字母,显示输出其大写。画出流程图,并编写程序段。

答:

Code segment

Assume cs:code

Start:

Mov ah,1 ;1号功能是输入(al)

Int 21h

sub al,20h

mov dl,al

mov ah,2 ;2号功能是输出(dl)

int 21h

hlt

code ends

end start

(a-61h,A-41h)

5.20 从键盘输入一位数字 N,显示输出 N 个 N。画出流程图,并编写程序段。

答:

CODE SEGMENT

ASSUME CS:CODE

START:

MOV AH,1

INT 21H

MOV DL,AL

AND AL, 0FH ;清空AL第一位

MOV CL,AL

MOV CH,0

NEXT: MOV AH,2 ;2号功能将DL输出

INT 21H

LOOP NEXT

MOV AH,4CH

INT 21H

CODE ENDS

END START

第六章 伪指令

6.1 伪指令

6.1.1 处理机选择伪指令

eg:.8086——选择8086指令系统,前面的“.”不能省略,如果没有指明则是默认8086系统

6.1.2 段定义伪指令

  1. 段定义伪指令格式:
  1. segment_name segment
  2. ..
  3. segment_name ends

为了确定用户定义的段和哪个段寄存器相关联,用ASSUME伪指令来实现

assume register_name:segment_name....

注:

  1. 其中register_name为段寄存器名,必须是CS,DS,ES和SS
  2. assume只能指定把某个段分配给哪一个段寄存器,它并不能把段地址装入段寄存器中,所以需要在代码段中通过代码进行,但代码段无需,这一操作在程序初始化时完成的

  1. 简化的段定义伪指令
  1. .model small ;定义存储模型为small
  2. .data ;定义数据段data
  3. string db 'hello,world!$'
  4. .code ;定义代码段code
  5. start:
  6. mov ax,@data ;对ds赋data段基地址
  7. mov ds,ax
  8. mov dx,offset string
  9. mov ah,9
  10. int 21h
  11. mov ah,4ch
  12. int 21h
  13. end start

注:

  1. small模型:所有数据都放在一个64KB的数据段,所有代码放在另一个64KB的代码段,数据和代码都为近访问
  2. .DATA伪指令用来定义数据段,但没有给出段名,默认段名是_DATA
  3. @DATA表示段名_DATA,在指令中表示段地址

6.1.3 程序开始和结束伪指令

END [label]  ;label表示程序开始执行的起始地址

6.1.4 数据定义与存储器单元分配伪指令

[变量] 操作码 n个操作数 [;注释]
  1. 常用的数据类型(操作码字段)
    1. DB:字节,8位
    2. DW:字,16位,数据低位在低地址,数据高位在高地址
    3. DD:双字,32位
    4. DF:6个字节的字,48位
    5. DQ:4个字,64位
    6. DT:10个字

6.1.5 类型属性操作符

word ptr——字类型

byte ptr——字节类型

  1. oper1 db 3,4
  2. oper2 dw 5678h,9
  3. ...
  4. mov ax,word ptr oper1 ;从oper1处取一个字使AX=0403H
  5. mov bl,byte ptr oper2 ;从oper2处取一个字节使BL=78H
  6. mov byte ptr[di],0 ;常数0送到内存字节单元

6.1.6 THIS操作符和LABEL伪操作

可以把一个变量定义成不同的访问类型

  1. name=THIS type
  2. name LABEL type ;type只能是byte和word

6.1.7 表达式赋值伪指令“EQU”和”=“

  1. Expression_name EQU Expression ;不可以修改
  2. Expression_name = Expression ;可以修改

6.1.8 汇编地址计数器$与定位伪指令

  1. 地址计数器$

用法:用来设置当前正在汇编的指令的偏移地址。每一段的开始,地址计数器初始化为0,接着每处理一条指令,地址计数器就增加一个值(DW自增2),此值为该指令所需要的字节数

  1. ARRAY DW 3,$+7,7
  2. COU=$
  3. NEW DW COU

以下是汇编结果:ARRAY的初始地址为03的地址,NEW的地址为06的地址,0009的由来是2+7($=2)

03

00

09

00

07

00

06

00

  1. ORG伪操作

用来设置当前地址计数器$的值,可修改

ORG constant expression

  1. EVEN伪操作

定义:使下一个变量或指令开始于偶数地址

  1. EVEN
  2. ARRAY DW 800 DUP(?)
  1. ALIGN伪操作

定义:使下一个变量的地址从4的倍数开始

  1. ALIGN boundary ;必须是2的幂
  2. ARRAY DW 800 DUP(?)

6.1.9 基数控制伪指令

.RADIX expression

6.1.10 过程伪指令

子过程又称程序,可以把一个程序写成一个过程或多个过程

  1. procedure_name PROC Attribute
  2. ...
  3. procedure_name ENDP

注:

  1. 过程名(procedure_name)为标识符,起到标号的作用
  2. 属性(Attribute)是指类型属性,可以是NEAR(段内调用)或FAR(跨段调用)

U6习题

6.1 画图说明下列数据定义语句所示内存空间的数据,并回答寄存器的值。

ORG 0

ARRAY LABEL BYTE

DA1 DW 2,9,14,3,315H,-6

DA2 DB 7,‘ABCDEDFG’

LEN = $-DA2 ;当前地址与DA2的距离

ORG 100H

DA3 DW DA4 ;是将DA4的地址(0102H)赋给DA3了,

DA4 DB 4 DUP(2 DUP(1,2,3),4)

。。。。。。

MOV AL,ARRAY+2 (AL)=( )H

ADD AL,DA2+1 (AL)=( )H

MOV AX,DA2-DA1 (AX)=( )H

MOV BL,LEN (BL)=( )H

MOV AX, DA3 (AX)=( )H

MOV BX, TYPE DA4 (BX)=( )H

MOV BX, OFFSET DA4 (BX)=( )H

MOV CX, SIZE DA4 (CX)=( )H

MOV DX, LENGTH DA4 (DX)=( )H

MOV BX, WORD PTR DA4 (BX)=( )H

MOV BL, LEN AND 0FH (BL)=( )H

MOV BL, LEN GT 5 (BL)=( )H

MOV AX, LEN MOD 5 (AX)=( )H

答:

MOV AL,ARRAY+2 (AL)=( 09 )H

ADD AL,DA2+1 (AL)=( 41 )H ;DA2+0为长度7,+1为首位

MOV AX,DA2-DA1 (AX)=( 000c )H ;DA2为12,DA1为0

MOV BL,LEN (BL)=( 09 )H ;$此时为21,21-12=9

MOV AX, DA3 (AX)=( 0102 )H ;DA3即DA4地址

MOV BX, TYPE DA4 (BX)=( 0001 )H ;DB类型的字节数1

MOV BX, OFFSET DA4 (BX)=( 0102 )H ;DA4的地址0102

MOV CX, SIZE DA4 (CX)=( 0004 )H ;嵌套不计,只看dup前面数,再*总字节数

MOV DX, LENGTH DA4 (DX)=( 0004 )H ;嵌套不计,只看dup前面数

MOV BX, WORD PTR DA4 (BX)=( 0201 )H ;取DA4一个字,01,02都存入,高位在前

MOV BL, LEN AND 0FH (BL)=( 09 )H ;LEN为09

MOV BL, LEN GT 5 (BL)=( ff )H ;结果为真,返回FF,假返回00

MOV AX, LEN MOD 5 (AX)=( 0004 )H ;9取模得

6.3 指令和伪指令的区别在哪里?伪指令可以出现在代码段吗?指令可以在数据段吗?

答:指令只能出现在代码段,定义数据的伪指令通常在数据段,伪指令在代码段两端也可,但不能在指令之间。

6.5 用 16 位指令编写完整程序,并上机调试,计算 V=(X+Y)*R,其中所有变

量均为 32 位变量,X、Y、R 的具体数值由你自己确定,变量定义格式如

下:

X DW ?,?

Y DW ?,?

R DW ?,?

V DW 4 dup(?)

答:

data segment

x dw 1

y dw 2

r dw 3

v dw 4 dup(?)

data ends

code segment

assume cs:code,ds:data

.386p80386指令系统,eax寄存器为32位

start:

mov ax,data

mov ds,ax

mov eax,x

add eax,y

mov ebx,r

imul ebx

mov v,eax

mov v+4,edx ;32位+4,16位+2

mov dl,al

add dl,30h

mov ah,2

int 21h

mov ah,4ch

int 21h

code ends

end start

6.6 数据定义如下:执行下列指令,填写寄存器的值。(指令是分别来看的)

ARRAY LABEL BYTE

DA1 DW 2,9,14,3

DA2 DB 7,‘ABCDEDF’

LEN = $-DA1

MOV AL,ARRAY+2 (AL)=( )H

ADD AL,DA2+1 (AL)=( )H

MOV AX,DA2-DA1 (AX)=( )H

MOV AX,DA1+1 (AX)=( )H

MOV BL,LEN (BL)=( )H

答:

MOV AL,ARRAY+2 (AL)=( 09 )H

ADD AL,DA2+1 (AL)=( 41 )H

MOV AX,DA2-DA1 (AX)=( 0008 )H

MOV AX,DA1+1 (AX)=( 0900 )H

MOV BL,LEN (BL)=( 10 )H

6.7 定义数据段,满足如下要求:

(1)array 为字符串变量:‘inspire a generation!’

(2)data1 为十六进制数:0FEDCBAH

(3)data2 为二进制数:10101010B。

(4)data3 为 100 个为零的字节变量。

(5)分配 500 个字的空间待用。

答:

data segment

Array db ‘inspire a generation!’

Data1 df 0fedcbah ;df定义6字节的字,f前的0可以不加

Data2 db 10101010B

Data3 db 100 dup(0)

dw 500 dup(?)

data ends

6.10 给出下列程序段汇编后的结果:

Val1 EQU 6

Val2 EQU 3

MOV BX,(Val1 LT 5) AND 20

MOV BX, (VAL2 GE 1) AND 30

MOV BX,(Val2 AND 5) OR (VAL1 GE 5)

MOV BX,(Val2 - VAL1) GE 5

答:

(1)MOV BX,0

(2)MOV BX,30

(3)MOV BX,FFFF

(4)MOV BX,0

第七章 分支与循环程序设计

7.1 分支程序设计

7.1.1 分支程序结构

  1. if-then-else——两个分支
  2. case——多个分支

7.1.2 单分支程序

if-else

eg:双字长数存放在DX和AX寄存器中,求该数的绝对值

7.1.3 复合分支程序

定义:分支结构中又出现分支

eg:从键盘输入一位十六进制数,并将其转换成十进制数显示输出

7.1.4 多分支程序

eg:根据键盘输入的一位数字(1~4),使程序转移到4个不同的分支中去,以显示键盘输入的数字

7.2 循环程序设计

7.2.1 循环程序结构

  1. DO-WHILE——相当于for循环,先判断后执行
  2. DO-UNTIL——相当于do while循环,先执行后判断

7.2.2 计数循环程序

计数循环是基本的循环组织方式,用循环计数器的值来控制循环

eg:把BX寄存器中的二进制数用十六进制数格式显示输出

7.2.3 条件循环程序

标志字称为逻辑尺

eg:先从键盘输入8位二进制数作为逻辑尺。再从键盘输入一个英文字母,根据逻辑尺当前的最高位标志显示输出该英文字母的相邻字符,标志位位0则显示其前趋字符,标志位位1则显示其后继字符。显示相邻字符后,逻辑尺循环左移一位,再接收下一个英文字母的输入,并依据逻辑尺显示相邻字符,直到回车键结束程序

7.2.4 条件计数循环程序

eg:设置键盘缓冲区位16个字节,从键盘输入一串字符,然后再从键盘输入一个单个字符,查找这个字符是否在字符串中出现,如果找到,显示该字符串,否则显示”NOT FOUND“

7.2.5 多重循环程序

eg:显示输出20H~7EH的ASCII表。每行16个字符

U7习题

7.4 编写程序,从键盘接收一个小写字母,然后找出它的前导字符和后续字符,再按顺序显示这三个字母。

答:

code segment

assume cs:code

main proc far

push ds

sub ax,ax

push ax

mov ah,1

int 21h

cmp al,61h

jb exit ;jb:al低于61h

cmp al,7ah ;61-a,7a-z

ja exit ;ja:al高于7a

mov bx,ax

sub al,1h ;输出前一字符

mov dl,al

mov ah,2

int 21h

mov dl,bl ;输出当前字符

mov ah,2

int 21h

add dl,1h ;输出后一字符

mov ah,2

int 21h

exit:ret

main endp

code ends

end main

7.5 分别用 LOOP 循环和条件转移指令实现 1+2+3+……+100,并将结果存入 AX。

答:

(1)

code segment

assume cs:code

main proc far

push ds

sub ax,ax

push ax

mov bx,1

mov ax,0

mov cx,99

a: add ax,bx

inc bx

loop a

exit: ret

code ends

end main

(2)

code segment

assume cs:code

main proc far

push ds

sub ax,ax

push ax

mov bx,1

mov ax,0

mov cx,99

a: add ax,bx

inc bx

cmp bx,101

jnz a

exit: ret

main endp

code ends

end main

7.6 打印下面图形。

*

**

***

****

*****

答:

code segment

assume cs:code

main proc far

push ds

sub ax,ax

push ax

mov ax,1

a: mov cx,ax ;循环次数

b: mov ah,2 ;输出一个字符

mov dl,’*’

int 21h

loop b

cmp ax,6

jz exit

inc ax

mov ah,2

mov dl,13 ;回车

int 21h

mov ah,2

mov dl,10 ;换行

int 21h

jmp a

exit: ret

code ends

end main

7.7 将 AX 和 BX 进行加、减、乘或除的运算,每种运算由用户从键盘上选择。AX和 BX 可在 DEBUG 下设置。

答:

code segment

assume cs:code

main proc far

push ds

sub ax,ax

push ax

mov ah,1

int 21h

cmp al,31h ;1加

jz ad

cmp al,32h ;2减

jz su

cmp al,33h ;3乘

jz mu

cmp al,34h ;4除

jz di

ad:ADD AX,BX

JMP exit

su:SUB AX,BX

JMP exit

mu:MUL BX

JMP exit

d:DIV BX

exit: ret

main endp

code ends

end main

7.8 求已知带符号数字节数组ARRAY的平均值,ARRAY的首字节单元为数组元素的个数。

答:

data segment

ARRAY db 5,01,12,23,45,F3

data ends

code segment

assume cs:code

start:

mov ax,data

mov ds,ax

mov ax,0

mov cl,array

mov ch,0

mov bl,cl ;存储元素个数

lea si,1

a: add al,array[si]

inc si

loop a

div bl

exit: mov ah,4ch

int 21h

code ends

end start

7.9 编写程序,实现对无符号字数组 ARRAY 的 6 个元素从小到大排序。

答:

data segment

array dw 6,5,9,4,5,15,3 ;首地址单元6为元素个数

data ends

code segment

assume cs:code,ds:data

start:

mov ax, data

mov ds, ax

mov di, array

k1: mov cx, di

mov bx,0

k2: mov ax, array[bx]

cmp ax, array[bx+2]

jl next

xchg ax,array[bx+2]

mov array[bx],ax

next: add bx,2

loop k2

dec di

jnz k1

mov ah,4ch

int 21h

code ends

end start

7.10 数据段有两个等长的字数组,分别求出各自的元素之和,并存入元素后面的单元中,即横向相加。再求出两个数组的对应元素之和,并把和存入新数组SUM 中,即纵向相加。

答:

data segment

Array1 dw 3, 1,0,1,? ;设简单数据,第一个为元素个数

Array2 dw 3,1,1,0,?

Array3 dw 3,3 dup (0) ;存放array1,2的和

data ends

code segment

assume cs:code,ds:data

start:

mov ax, data

mov ds, ax

mov ax, 0

lea bx, array1+2

mov cx, array1

sumh1: add ax, [bx]

add bx,2

loop sumh1

mov [bx],ax

;第二个数组累加

mov ax, 0

lea bx, array2+2

mov cx, array2

sumh2: add ax, [bx]

add bx,2

loop sumh2

mov [bx],ax

lea bx,2

mov cx, array2

sum3: mov ax, array1[bx]

add ax, array2[bx]

mov array3[bx],ax

add bx,2

loop sum3

exit: mov ah,4ch

int 21h

code ends

end start

7.11 编写程序,比较两个从键盘输入的字符串是否相同,如果相同,则显示

‘YES’,如果不同,则显示发现不同的字符位置。

答:

data segment

mess1 db 13,10, 'input string1:$'

mess2 db 13,10, 'input string2:$'

mess3 db 13,10, 'YES!$'

mess4 db 13,10, 'no match at $'

st1 label byte

max1 db 6

act1 db ?

stok1 db 6 dup(?)

st2 label byte

max2 db 6

act2 db ?

stok2 db 6 dup(?)

data ends

code segment

assume cs:code, ds:data,es:data

start: mov ax,data

mov ds,ax

mov es,ax

lea dx,mess1

mov ah,09

int 21h ;qust1?

lea dx,st1

mov ah,0ah

int 21h ;ans1

lea dx,mess2

mov ah,09

int 21h ;qust2?

lea dx,st2

mov ah,0ah

int 21h ;ans2

mov cl,act1

mov dl,act2

cmp cl,dl

jnz nomatch

mov ch,0

lea si,stok1

lea di,stok2

repe cmpsb

jnz nomatch

match: lea dx,mess3

mov ah,09

int 21h

jmp exit

nomatch:

lea dx,mess4

mov ah,09

int 21h

sub di,offset stok2

mov dx,di

add dl,30h

mov ah,2

int 21h

exit:

mov ah,4ch

int 21h

code ends

end start

7.12 编写程序,从键盘输入一个字符串到 BUFF,再输入一个字符到 AL,在字符

串 BUFF 中查找是否存在该字符,如果找到,显示发现的字符位置。

答:

data segment

mess1 db 13,10, 'input string:$'

mess2 db 13,10, 'input a char:$'

mess3 db 13,10, 'found at $'

mess4 db 13,10, 'no found !$'

st1 label byte

max1 db 6

act1 db ?

stok1 db 6 dup(?)

data ends

code segment para'code'

assume cs:code, ds:data

start: mov ax,data

mov ds,ax

mov es,ax

lea dx,mess1

mov ah,09

int 21h ;qust1?

lea dx,st1

mov ah,0ah

int 21h ;ans1

lea dx,mess2

mov ah,09

int 21h ;qust2?

mov ah,1

int 21h ;ans2

lea di,stok1

repne scasb

jz match

nomatch:

lea dx,mess4

jmp exit

match: lea dx,mess3

exit:

mov ah,09

int 21h

sub di,offset stok1

mov dx,di

and dx,0fh

add dl,30h

mov ah,2

int 21h

mov ah,4ch

int 21h

code ends

end start

7.13 编写程序,从键盘输入一个字符串到 BUFF,并按相反顺序显示输出。

答:

data segment

mess1 db 13,10, 'input string:$'

mess2 db 13,10,'$'

st1 label byte

max1 db 6

act1 db ?

stok1 db 6 dup(?)

data ends

code segment

assume cs:code, ds:data

start : mov ax,data

mov ds,ax

lea dx,mess1

mov ah,09

int 21h

lea dx,st1

mov ah,0ah

int 21h

lea dx,mess2

mov ah,09

int 21h

mov cl,act1

mov ch,0

mov bx, offset stok1

add bx, cx

next: dec bx

mov dl, [bx]

mov ah,2

int 21h

loop next

mov ah,4ch

int 21h

code ends

end start

7.14 编写程序,从键盘输入一个八位的二进制数,显示其十六进制数。

答:

code segment

assume cs:code

start:

mov cx,8

mov bl,0

next: mov ah,1

int 21h

cmp al,30h

jb exit

cmp al,31h

ja exit

sub al,30h

shl bl,1

add bl,al

loop next

mov cl,4

mov di,2

out1: rol bl,cl

mov dl,bl

and dl,0fh

add dl,30h

cmp dl,39h

jle dig

add dl,7

dig: mov ah,2

int 21h

dec di

cmp di,0

jnz out1

exit: mov ah,4ch

int 21h

code ends

end start

7.15 字数组 ARRAY 为有符号数,第一个单元为元素个数 N,后面为 N 个元素,编写程序,求数组元素中的最大值,并把它放入 MAX 单元。

答:

data segment

array dw 5,9,4,5,15,3

max dw ?

data ends

code segment

assume cs:code,ds:data

start:

mov ax, data

mov ds, ax

mov cx, array

lea bx, array+2

mov ax, [bx]

mov max, ax

k1: mov ax, [bx]

cmp ax, max

jl next

mov max,ax

next: add bx,2

loop k1

mov ah,4ch

int 21h

code ends

end start

第八章 子程序设计

8.1 子程序结构

8.1.1 子程序调用指令

  1. 过程:
    1. 首先把它下一条指令的地址(返回地址)压入堆栈保存
    2. 再把子程序的入口地址置入IP(CS)寄存器
    3. 执行完后,用返回指令(RET)回到主程序,把堆栈里保存的返回地址送回IP(CS)寄存器
  1. 具体的指令
  1. CALL DST目标地址
  2. RET
  3. RET 表达式 ;该指令除了完成RET操作,还使SP再加上这个常数,以修改SP值

注:

  1. call
    1. 段内调用(NEAR PTR):堆栈只保存IP寄存器的值
    2. 段间调用(FAR PTR):先保存CS寄存器的值,再保存IP寄存器的值
  1. ret
    1. 段内和段间的返回是按照call的对应进行
    2. 表达式的值是一个常数,加了这个表示ret除了完成本身的指令后,还需将sp+该值,来修改sp的值

8.1.2 过程定义与过程结构

  1. 过程定义伪指令见6.1.10
  2. 确定属性的原则:如果调用程序和该过程在同一个代码段,则适用NEAR属性,如果调用程序和该过程不在同一个代码段,则使用FAR属性

8.2 子程序的参数传递

  1. 入口参数:主程序传参数给子程序
  2. 出口参数:子程序传参数给主程序
  3. 值传递:把参数的值放在约定的寄存器或内存单元
  4. 地址传递:把参数的地址传递给子程序

8.2.1 用寄存器传递参数

  1. 定义:约定某些寄存器存放将要传递的参数

8.2.2 用变量传递参数

  1. 定义:用约定的变量在过程间传递参数

8.2.3 用地址表传递参数的通用子程序

这种方法是在主程序中建立一个地址表,把要传递的参数地址放在地址表中,然后把地址表的首地址放入寄存器,子程序通过寄存器间接寻址方式从地址表中取得所需参数

8.2.4 用堆栈传递参数的通用子程序

8.2.5 用结构变量传递参数的通用子程序

U8习题

8.3 主程序从键盘输入一个字符串到 BUFF,再输入一个字符到 AL,用子程序在

字符串 BUFF 中查找是否存在该字符,如果找到,显示发现的字符位置。用寄存器传递要查找的字符。

答:Data segment

BUFF1 db 16,?,16 dup(?),13,10,'$'

Data ends

Code segment

Assume cs:code,ds:data

Main proc far

Push ds

Xor ax,ax

Push ax

Mov ax,data

Mov ds,ax

Mov es,ax

Lea dx,BUFF1

Mov ah,10

Int 21h

mov ah,1

int 21h

Lea di,BUFF1+2

Mov cl,BUFF1+1

mov ch,0

Mov ah,0

Repne scasb

Jnz ye

dec di

mov bx,di

Call BTH

Ye: ret

Main endp

BTH proc near

mov cx,4

s:rol bx,1

rol bx,1

rol bx,1

rol bx,1

mov al,bl

and al,0fh

add al,30h

cmp al,39h

jle d

add al,7

d:mov dl,al

mov ah,2

int 21h

loop s

ret

BTH endp

Code ends

End main

8.4 主程序从键盘输入一个八位的二进制数,对其作求补码操作,用子程序对求补后的值以二进制形式显示。(正数的补码=输入)

答:Code segment

Assume cs:code

Main proc far

Push ds

Xor ax,ax

Push ax

Mov bx,0

Mov cx,8

A:mov ah,1

Int 21h

Shl bx,1

Sub al,30h

Jz b ;输入为 0

INC bx ;输入为 1

B:loop a

Test bx,0080h

Jz d

XOR bx,00FFh ;取反

INC bx

D:Call disp

Ret

Main endp

disp proc near

mov cx,8

shl bx,cl

ls1:shl bx,1

jnc k30

mov dl,31h

jmp outb

k30: mov dl,30h

outb:mov ah,2

int 21h

loop ls1

ret

disp endp

code ends

end main

8.5 主程序从键盘(连续)输入两个四位的十六进制数 A 和 B,用子程序作十六进制计算 A+B,并显示计算结果(二进制)。

答:

data segment

A dw ?

B dw ?

data ends

Code segment

Assume cs:code,ds:data

Main proc far

Push ds

Xor ax,ax

Push ax

Mov ax,data

Mov ds,ax

Call INH ;输入十六进制数到 BX 寄存器

Mov A,bx

Call INH ;输入十六进制数到 BX 寄存器

Mov B,bx

Call ad

Ret

Main endp

INH proc near

mov bx,0 ;初始化

mov ch,4

mov cl,4

inchr: mov ah,1 ;键盘输入

int 21h

cmp al,30h

jl exit ;非法输入

cmp al,39h

jle dig ;输入是数字 0~9

cmp al,41h

jl exit ;非法输入

cmp al,46h

jg exit ;非法输入

sub al,37h ;输入是大写 a~f

jmp ls4

dig: sub al,30h

ls4: shl bx,cl

add bl,al

dec ch

jnz inchr

exit: ret

INH endp

Ad proc near

Mov ax,a

Mov bx,b

Add bx,ax

Call disp

Ret

Ad endp

disp proc near

mov cx,16

ls1: shl bx,1

jnc l30

mov dl,31h

jmp outb

l30; mov dl,30h

outb: mov ah,2

int 21h

loop ls1

ret

disp endp

Code ends

End main

8.6 某字数组为有符号数,第一个单元为元素个数 N,后面为 N 个元素,编写通用子程序,求数组元素中的最大值,并把它放入 MAX 单元。

答:MAX_p proc near

Mov di,[bx] ;个数地址

Mov si,[bx+2] ;数组地址

Mov cx,[di]

Mov di,MAX

Xor ax,ax

Next:cmp di,[si]

Jg a

Mov di,[si]

A: Add si,2

Loop next

Mov MAX,di

ret

MAX_p endp

8.7 设有一个数组存放学生的成绩(0 ~ 100),编制一个子程序统计 0 ~ 59 分、60 ~ 69 分、70 ~ 79 分、80 ~ 89 分、90 ~ 100 分的人数,并分别存放到 scoreE、scoreD、score C、score B 及 score A 单元中。编写一个主程序与之配合使用。

答:

data segment

Array db 6,9,65,78,68,86,93 ;6为学生人数,后面为6个成绩

ScoreE db ?

scoreD db ?

scoreC db ?

scoreB db ?

scoreA db ?

Data ends

Code segment

Assume cs:code,ds:data

Main proc far

Mov ax,data

Mov ds,ax

Mov cl,array

mov ch,0

Call class

Ret

Main endp

Class proc near

Lea si, array

next:

inc si

Mov bl, [si]

Cmp bl,60

Jl e

Cmp bl,70

Jl d

Cmp bl,80

Jl k

Cmp bl,90

Jl b

Mov dl, scoreA

Inc dl

Mov scoreA,dl

loop next

jmp exit

B: Mov dl, scoreB

Inc dl

Mov scoreB,dl

loop next

jmp exit

k: Mov dl, scoreC

Inc dl

Mov scoreC,dl

loop next

jmp exit

D: Mov dl, scoreD

Inc dl

Mov scoreD,dl

loop next

jmp exit

E: Mov dl, scoreE

Inc dl

Mov scoreE,dl

loop next

jmp exit

exit:ret

class endp

Code ends

End main

8.8 用多模块程序设计一个简单的计算器程序,实现整数的加减乘除。运算符可以为:+,-,*,/,=。

答:

public num1,num2,res

extrn ad:far,su:far,mu:far,dv:far,el:far

data segment

num1 db ?

num2 db ?

res dw ?

data ends

code segment

assume cs:code,ds:data

main proc far

push ds

sub ax,ax

push ax

mov ax,data

mov ds,ax

call DTOB

mov num1,bx

call DTOB

mov num2,bx

mov ah,1

int 21h

cmp dl,’+’

jz a

cmp dl,’-’

jz s

cmp dl,’*’

jz m

cmp dl,’/’

jz d

cmp dl,’=’

call el

jmp exit

a:call ad

jmp exit

s:call su

jmp exit

m:call mu

jmp exit

d:call dv

exit:ret

main endp

dtob proc near

mov bx, 0

input: mov ah, 1 ;键盘输入

int 21h

sub al, 30h ;把 ascii 码转变为数值

jl exit ;如不是数则退出

cmp al, 9

jg exit ;如不是数则退出

cbw ;扩展为字

xchg ax, bx ;交换寄存器

mov cx, 10

mul cx ;a(n)= a(n-1)×10

xchg ax, bx ;交换寄存器

add bx, ax ;a(n)=a(n)+b(n)

jmp input

exit: ret

dtob endp

code ends

end main

------------------

public ad

extrn num1:byte,num2:byte,res:word

code segment

assume cs:code

ad proc near

mov ah,0

mov al,num1

add al,num2

adc ah,0

mov res,ax

ret

order endp

su proc near

mov ah,0

mov al,num1

sub al,num2

sbb ah,0

mov res,ax

ret

su endp

mu proc near

mov al,num1

mul num2

mov res,ax

ret

mu endp

dv proc near

mov al,num1

div num2

mov res,ax

ret

dv endp

el proc near

mov al,num1

cmp al,num2

jz z

mov res,0FFFFH ;不相等

jmp exit

z: mov res,0 ;相等

exit:ret

el endp

code ends

end

https://www.wpsshop.cn/w/weixin_40725706/article/detail/177628

推荐阅读
相关标签
  

闽ICP备14008679号