汇编语言程序的格式
汇编语言程序的上机过程
伪指令语句
汇编语言程序设计的基本方法本章内容
了解汇编语言程序的基本格式,及其上机过程 。
熟练掌握数据定义伪指令,段定义伪指令,符号定义伪指令,过程定义伪指令 。
熟练掌握汇编语言程序设计的一般步骤以及顺序程序,分支程序,循环程序,子程序设计的方法 。
学习目的
6.1 汇编语言程序的格式一、什么是汇编语言
1 ) 机器语言直接用 0,1序列表示指令和数据的编程方法。
2) 汇编语言用指令助记符编写程序的方法。
语句格式:
[NAME] OPERATION OPERAND [; COMMENT]
NAME:是一个符号或称为标号。
OPERATION:是一个操作码的助记符,可为指令,
伪指令等。
OPERAND:是一个或多个表达式,是操作的对象。
COMMENT:用来说明语句或程序的功能。以“;”开始二、汇编语言程序的语句格式注,
指令助记符前面还可以有 [ 前缀 ]。
汇编程序语句中的四项,均可以用 大 写,
小写 或 混合编写 。
1,标号 (含数据变量标号和程序位置标号 )
标号 是一个自行设计的标识符或名称,
最多可由 31个字母,数字和特别字符 (?,@、
-,$)等组成 。 但
不能用数字开头 。
不能为汇编语言的保留字 。
注:保留字指有专门用途的字符或字符串,
如 CPU的寄存器名,指令助记符,伪指令助记符等 。
(1) 数据变量标号的三种属性
a,段值,即所在段的段地址。
b,偏移量,即数据变量所在位置的地址与其段地址之差值。
c,类型,指该数据变量是字节、字还是双字。
(2) 程序位置标号的两种属性
a,NEAR——段内调用或转移标号。
b,FAR——段间调用或转移标号。
2,操作数区操作数可以是 常数,变量,标号,寄存器名 或 表达式
(1) 常数,二进制,八进制,十进制,十六进制或 ASC Ⅱ 码,范围 -32768? 32767。
(2) 标号,寄存器名 前面已讲,变量 下一节介绍。
(3) 表达式,由 运算符 连接起来的式子叫表达式,
按一定的规则对表达式进行运算后得到一个数值或一个地址 。
表达式可分 算术表达式,逻辑表达式,关系运算表达式,分析运算表达式 和 合成运算表达式 。
用算术运算符 +,-,*,/和 MOD连接的表达式 。
a,算术表达式用逻辑运算符 AND,OR,XOR和 NOT
连接的表达式 。
b,逻辑表达式用 EQ,NE,LT,GT,GE和 LE连接的表达式 。 若条件成立,其值为 1,否则为 0。
c,关系运算表达式分析运算表达式把存储器操作数分解为几个组成部分;而合成运算式是把这些组成部分综合为存储器操作数 。
d,分析运算表达式和合成运算表达式三、汇编语言的程序格式汇编语言程序是由汇编语句按照一定的语法规则和顺序排列起来的 。 从结构上来看,它是采用 分段结构,每个段由 SEGMENT语句开始 ENDS结束,一个程序中可以有多个段,每个段中也可以有多个程序 。 END为整个程序的结束语句,其一般格式为:
NAME1 SEGMENT
语句
语句
NAME1 ENDS
NAME2 SEGMENT
语句
语句
NAME2 ENDS
END
通常一条语句占用一行 ( 不能超过 132个字节 ),注释部分可任意长,但必用,;,开头 。
6.2 伪指令指令语句,汇编程序把它们翻译成机器代码,命令 8086执行对应操作 。
伪指令语句,汇编程序并不把它们翻译成机器代码,只是用来指示,引导汇编程序在汇编时做一些操作,它本身不占用存储单元 。
* 程序分段及存储器分配
* 变量定义及存储器申请
* 过程定义
* 符号定义
* 程序模块定义与通信
* 宏定义及宏调用
* 条件汇编
* 格式控制,列表及其他功能伪指令主要分为下列几类:
本章只介绍前五类一、程序分段及存储器分配
1,SEGMENT和 ENDS
定义方式:
[段名 ]SEGMENT[定位方式 ][组合方式 ][类别名 ]
语句
[段名 ]ENDS
段名 是赋予该段的一个名称,SEGMENT
与 ENDS成对出现,且前面的段名要相同,段名的取法与文件名,标号及变量名等相同 。
(1) 段名
LINK程序除完成段与段的联合操作以外,还把联合后得到的各个段互相衔接起来,
段与段的 衔接方式 叫做定位方式,共 4种 。
(2) 定位方式
c,WORD (字 ):表示段从地址是一个最低位为 0的二进制数开始 。
d,PAGE(页 ):段从十六进制数表示地址的最低两位均为 0处开始 。
a,PARA (未定义的 ):表示段从一个字节的边界即用十六进制数表示地址的最低位为 0处开始 。
b,BYTE (字节 ):表示段可从任一地址开始 。
例,设 A,B,C,D这 4个段的长度分别为
1376H,A47H,1234H和 405H字节,分配给 A段的物理地址是 00000H ( 段址
0000H,位移量 0000H) 。 在不同的定位方式下,各段定位后的段地址如下图所示:
C01DB,000D01DB,1240
D0301,00010301,0405
A0000,00000000,1375
C01E4,000801E4,123B
A
0000,0000
0000,1375
D0301,00000301,0404
C01DD,000001DD,1233
B0138,00000138,0A46
A0000,00000000,1375
(a)
A,B,C,D
均为 PARA方式
(b)
A,B,C,D
均为 BYTE方式
(c)
A,PARA
B,PAGE
C,WORD
D; PARA定位方式选择
B0137,00060137,0A4C
B0140,00000140,0A46
D0308,00000308,0404
a,PUBLIC:
表示该段与其他模块中说明为 PUBLIC方式的同名段互相组合成 一个逻辑段,公用一个段址,运行时装入同一个物理段中 。
(3) 组合方式程序不同模块中具有相同性质的段若使用同样的段名,则连接时就会把同名的段按照指定的方式组合起来,组合方式共有 6种 。
b,STACK:
连接时把所有 STACK方式的同名段连接成一个段,运行时就是 SS的装入值,且栈指针 SP指向该段的起始地址 。
c,COMMON:
表示该段与其它模块中所有已说明为
COMMON的同名段共享相同的存储区域,
即具有相同的段起始地址,共享的长度为模块同名段中最大长度 。
d,MEMORY方式:
表示该段应定位在所有其他段的上面,
若有多个段选用 MEMORY,则除第一个之外,
其余段均作为 COMMON处理 。
e,AT:
表示该段按 绝对地址 定位,其段地址即为其后表达式的值,位移量为 0。
若定义一个段时不指定上述任何一种方式,
则该段与其他模块的段没有任何关系,独立定义 。
例,有 A,B; C,A,B; A,C共 7个段是 3个模块中的段,用 P,C,S分别代表 PUBLIC,
COMMON或 STACK。 组合成 4个新段 (见下图 ),新段的长度为被组合在一起的各段长度之和 (用 PUBLIC和 STACK方式时 ),
或是各段中最长段的长度 (COMMON方式 )。
f,缺省方式:
A (P)
B (C)
C (S)
A (P)
B (C)
A
C (S)
模块 1
模块 2
模块 3
LINK
P
C
S
A
B
C
D
连接程序的组合处理示意图
(4) 类别名是一个用 单引号 括起来的 字符串,LINK
程序把类别名相同的所有段放在连续的存储区域内,先出现的在前,后出现的在后 。
例,A SEGMENT ‘FAT’ A
B SEGMENT ‘BAZ’ E
C SEGMENT ‘BAZ’ B
D SEGMENT ‘ZOU’ C
E SEGMENT ‘FAT’ D
LINK 处理前 LINK 处理后
2,GROUP伪指令格式,[组名 ] GROUP [段名 ] [,…]
功能,用来把模块中若干不同名的段集合成一个组,使其装入 同一个物理段中,组内各段之间的跳转可视为 段内跳转 。
注,组名与段名是一样的取名规则,是代表该组的段地址,格式中的段名也可用表达式 SEG[变量 ]或 SEG[标号 ]。
3,ORG伪指令格式,ORG [数据表达式 ]
功能,把位置计数器的值设置为表达式的值 。 ORG后面的一条指令性语句或数据区定义命令即从指定的位置处进行汇编 。
4,ASSUME伪指令格式,ASSUME [段寄存器 ],[段名 ],
[段寄存器 ],[段名 ],…
功能,用于告知汇编程序,段寄存器 CS、
DS,ES和 SS的内容将被设定为那些段或组的 段址 。
注,(1) 段名 可以是已定义过的任何 段名 或组名,也可以是表达式 SEG [变量 ]或
SEG [标号 ],还可以是 NOTHING。
(2) 除 CS外,DS,ES,SS的设置必须通过指令性语句来完成 。
例,SEGC SEGMENT
ASSUME DS,SEGA,ES,SEGB,SS:
NOTHING,CS,SEGC
MOV AX,SEGA
MOV DS,AX ;设置 DS
MOV AX,SEGB
MOV ES,AX ;设置 ES
SEGC ENDS
二、变量定义及存储器申请
DB,DW和 DD等可用于 定义变量 和 预置存储器,变量后不能带冒号,任何变量均有下列三属性 。
(1) 段属性即变量所使用的段;
(2) 段内偏移属性;
(3) 变量的类型:字节、字、双字等。
1,DB/DW/DD伪指令
(1) 格式,[变量名称 ] { DB/DW/DD}表达式功能,定义一数据存贮区 。
该数据存贮区的 类型 由所使用的数据定义伪指令指定 (其中 DB/DW/DD定义的分别为字节型 /字类型 /双字型 );
存贮区中数据的 个数 由其后表达式的个数 (包括重复因子 )决定;
并为各存储单元提供一个 初值 。
(2) 表现形式:
根据表达式的不同可有以下几种常见形式。
a,表达式为预置的一个常数项表达式如,AB DB ‘AB’ ; 4142H
BA DW ‘AB’ ; 4241H
FEN DW OFEH ; 254
SEG-FEH DW SEG FEH ;变量 FEH的段址
PAR1 DB 74
PAR2 DW 1234H
b,表达式中出现,?,,表示只分配存储单元,
其初值不定 。
如,SUM DW? ;分配一个字单元
F1 DB? ;分配一个字节单元
c,表达式为预置地址表达式 (DW/DD)
如,TABLE-0FF DW TABLE ; TABLE的偏移量
D-PTR-T DD TABLE ; TABLE的 16位偏移量和段址
d,表达式为预置重复的算式 。
如,ZIPS DB 100 DUP (0)
DB 2 DUP (0,3 DUP (1) )
2,RECORD伪指令
(1) 记录定义的一般格式:
记录名称 RECORD 字段名称:表达式,…
功能,记录可视为能进行 位处理的字节或字,用记录名称作为汇编期间的操作符,去预置任何多个 8bit或 16bit的记录,并为它分配存储单元 。
注,表达式 左边 表示字段名称的位数,最多不能超过 16bit,当定义中的字段其位不能占满整个字节或字时,汇编程序就把所定义的字段与记录的 低位端对齐 。
如,QUASI RECORD A:6,B:6
未定义 A B
15 12 11 6 5 0
如,MODEL3 RECORD X,3=7,Y:4=8,Z:9=257
1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 1
15 13 12 9 8 0
MODEL3
X Y Z
(2) 记录的预置和存储分配记录可以用记录名称作为操作符。
[名称 ]记录名称 <表达式,…>
表达式 DUP(<表达式,…>)
一般格式:
意思是将已定义的记录 MODEL3分配 100
个存储单元 (字单元 ),并把 Y和 Z字段修改为 15
和 3。
如,MANY MODEL3 100 DUP (<,15,3 >)
111 1111 000000011
111 1111 000000011
111 1111 000000011
MANY MODEL3 [0]
MANY MODEL3 [2]
MANY MODEL3 [198]
… …
(3) 记录的使用与处理如,MOV DX,MANY MODEL3 [40]
111 1111 000000011
000 1111 000000000
000000000000 1111;执行 MOV后 DX的值; Y字段为 1其余为 0;执行 SHR后 DX的值
AND DX,MASK Y
MOV CL,9
SHR DX,CL;执行 AND后 DX的值
3,STRUC/END伪指令使用格式:
注,结构和记录较少使用,当设计大型复杂程序,或程序设计中使用多种语言时,他们常用来传送数据和状态量 。
结构名称 STRUC
[字段名称 ] { DB/DW/DD}
结构名称 ENDS
表达式,…
表达式 DUP (表达式,… )


三、过程定义伪指令其中过程名是为该过程指定的一个名称,
与变量,标号的定义法相同 。
使用格式:过程名 PROC NEAR/FAR
RET
过程名 ENDP


功能,把具有一定功能的程序段设计成为一个过程 (子程序 ),便于实现模块化的程序设计 。
注,(1) CALL指令中过程名起着标号的作用 。
有段属性,偏移量属性和类型属性
(NEAR和 FAR)。
(2) 子程序中至少有一个 RET。
四、符号定义伪指令
1,EQU伪指令格式:符号名 EQU 数值表达式功能,为常量,变量,表达式或其他符号定义一个名字,但不申请分配内存 。
如,THREE EQU 3
FIRSTW EQU WORD PTR BYT;把变量; BYT定义为名字是 FIRSTW的字
,=”伪操作与 EQU相似,其区别是前者可重复定义而后者不能 。
使用 EQU可使程序简单明了和便于修改 。
注:
EQU可用 PURGE解除 。
2,LABEL伪指令格式:变量名 /标号 LABEL [类型 ]
功能,为当前存储单元定义一个指定类型的变量名或标号,其 类型 为 BYTE、
WORD,DWORD,结构名,记录名,NEAR和 FAR。
如,(1) BUFF LABEL BYTE
DB 21
等效于 BUFF DB 21
(2) TRANS LABEL NEAR
MOV AX,CX
等效于 TRANS,MOV AX,CX
(3) ADD-E LABEL FAR
ADD-M,ADD AX,FOO[BX]
这样 ADD-M标号不仅适合 近程调用和转移 也可用新名 ADD-E使之适合 远程调用和转移 。

(4) BAR LABEL BYTE
ARR DW 100 DUP (0)
ADD AL,BAR[99]
ADD AX,ARR[98]
同一数据区内容既可作为字节又可作为字参加运算。


五、程序模块通讯用伪指令汇编语言程序可划分为许多模块,对每个模块独立地进行汇编及调试 (见下图 ),
一般从 低层 到 高层 逐步进行 。
PUBLIC
二级子模块 1
PUBLIC
二级子模块 2
PUBLIC PUBLIC
二级子模块 n- 1 二级子模块 n

PUBLIC PUBLIC PUBLIC
一级子模块 1
EXTRN
一级子模块 2
EXTRN
一级子模块 m
EXTRN

主模块
EXTRN
主模块
PUBLIC
二级子模块 1
PUBLIC
二级子模块 2
PUBLIC PUBLIC
二级子模块 n- 1 二级子模块 n

一级子模块 一级子模块 一级子模块…
汇编语言程序的模块结构
1,NAME和 END伪指令功能,定义一个模块,作为一个独立的汇编单位,NAME缺省时模块若使用了 TITLE语句,则 TITLE语句中前 6个字符为模块名,
否则源文件名将作为模块名 。
格式,NAME 模块名
END 标号

注,一个模块是一个独立的汇编单位,汇编处理只进行到模块结束语句 END为止 。
注,符号必须用,,,分开,且均在本模块中定义过 。
注:
2,PUBLIC伪指令格式,PUBLIC [符号表 ]
功能,用来说明该模块中被定义的那些常量,变量 和 标号 (含过程名 )可以被其他模块所引用 。
如,PUBLIC ABC,BCD,CDE
3,EXTRN伪指令格式,EXTRN [符号:类型,…]
功能,指出本模块中需要引用但却在其他模块中定义并说明为 PUBLIC属性的符号 (含常量,变量,标号和过程 ),
符 号 的 类 型 (BYTE,WORD,
DWORD,NEAR,FAR和 ABS(符号常量 ))必须与它们在其他模块中定义时的类型一致 。
6.3 汇编语言属性操作符一、修改属性的操作符(合成操作符)
1,指针操作符 PTR
格式,类型 PTR 表达式类型,
表达式,是变量、标号或数值
变量的类型有,BYTE,WORD和 DWORD;
标号的类型有,NEAR和 FAR;
结构名称功能,PTR把它左边的属性指派给它右边的变量,
标号或数值,使之产生一个新的存储器地址操作数 。
如,(1) INC BYTE PTR [BX]
(2) ADD DX,WORD PTR FOOB[20]
新存储器操作数的 段地址和段内偏移量与
PTR运算符右边的操作数的对应量相同 。
PTR给已分配的存储器一个另外的定义但并不重新分配存储器 。
2,SHORT操作符
SHORT用于条件转移,转移和调用指令中,指出其转移的相对位移量不超过一个字节所能表达的范围 。
3,THIS操作符
THIS用于定义当前所指单元的 类型 。
格式,THIS 类型 /距离其中类型是 BYTE,WORD和 DWORD,
距离是 NEAR和 FAR属性 。
功能,与 PTR类似建立一个新的存储器地址操作数,但不分配存储器,其类型由
THIS指定 。
(1) FOOB EQU THIS BYTE
(2) FAR-OUT EQU THIS FAR
如:
二、数值返回操作符(分析运算符)
返回的是变量或标号的 段地址,偏移地址 及 类型 的属性值 。
格式,分析运算符 变量或标号其运算的结果为一常数
1,SEG—— 取段址算符
2,OFFSET—— 取偏移地址算符功能,分离出该变量或标号的段址如,MOV AX,SEG BUF
功能,分离出该变量或标号的偏移地址如,MOV SI,OFFSET BUF
3,TYPE—— 取类型算符
4,LENGTH—— 取变量所含存储单元的个数功能,分离出该变量所含存储单元的个数 。
功能,分离出该变量或标号的类型的字节数 。
变量 类型为 BYTE,WORD和 DWORD时,
返回的值分别为 1,2和 4;
标号类型为 NEAR或 FAR时,则返回 -1或 -2。
注意,在定义该变量时,数据定义伪指令后面的第一个表达式的形式为,n
DUP(表达式 )”时,取值为 n,否则为 1。
如,BUF1 DB 100 DUP( 0)
BUF2 DW 10,5 DUP( 2)
BUF3 DD 5 DUP( 1,2 DUP( 0))
则 LENGTH BUF1=100,LENGTH BUF2=1
LENGTH BUF3=5。
5,SIZE—— 取变量所含存储区的总字节数。
功能,SIZE=LNGTH*TYPE
SIZE BUF1=100(因为 TYPE BUF1=1)
SIZE BUF2=2(因为 TYPE BUF2=2)
SIZE BUF3=20(因为 TYPE BUF3=4)
三、记录专用操作符
2,WIDTH操作符它用一个记录字段名称作为操作数,结果是字段名称所在位置的位是 1,其余是 0。
返回的是记录或记录中字段的位数。
1,MASK操作符
6.4 常用的 DOS系统功能调用使用 DOS系统功能调用的一般过程:见下图所示。
功能调用号?AH
置入口参数执行,INT 21H,
分析出口参数


系统功能调用的方法一、键盘输入 (1号调用 )
格式,MOV AH,1
INT 21H
功能,等待从键盘输入一个字符并将输入字符的 ASCII码 送入寄存器
AL中,碰到 CTRL+Break则退出 。
二、显示输出 (2号调用 )
格式,MOV AH,2
MOV DL,待显字符的 ASCII码
INT 21H
功能,将 DL中的字符送显示器显示,若为 CTRL+Break的 ASCII码 则退出 。
三、打印输出 (5号调用 )
格式,MOV DL,待打印字符的 ASCII码
MOV AH,5
INT 21H
功能,将 DL中字符送打印机打印 。
四、控制台输入 (8号调用 )
格式,MOV AH,8
INT 21H
功能,与 1号 相似,但只从键盘上输入而 不显示 。
五、显示字符串 (9号调用 )
格式,LEA DX,字符串首偏移地址
MOV AH,9
INT 21H
功能,将当前数据区中以 ‘ $’结尾的字符串送显示器显示 。
六、键盘输入字符串 (10号调用 )
格式,LEA DX,缓冲区首偏移地址
MOV AH,10
INT 21H
功能,从键盘上往指定缓冲区中输入字符串并送显示器显示 。
如,BUF DB 81
DB?
DB 80 DUP (0)
注,缓冲区应按规定的格式定义。
BUF第一字节规定了缓冲区的大小,从键盘输入的字符串从第三个字节存放,第二个字节存放实际输入的字符个数 。
6.5 汇编语言程序的上机过程一、汇编语言上机运行的软件环境
1,DOS操作系统
2,全屏幕编辑器 EDIT.EXE
3,宏汇编语言软件 TASM.EXE
4,连接软件 TLINK.EXE
5,调试软件 TD.EXE
二、汇编程序和汇编过程汇编程序:即用于把源程序翻译成机器代码程序的程序 。
源程序:即用汇编语言编写的程序称为汇编语言程序,也称源程序 。
目标程序:即汇编后产生的机器代码程序 。
1) 检查源程序
2) 测出源程序中的语法错误
3) 产生源程序的目标程序,并可给出列表文件
4) 展开宏指令汇编程序的主要功能是:汇编程序的主要功能是:
汇编程序将源文件汇编后的情况通常有以下几种:
1,汇编成绝对地址并能立即运行汇编将源程序按绝对地址格式产生目标程序,并将它放在内存中 。
优点:实现简单,容易理解。
缺点:由于这种方式每次执行程序前都要汇编一次,故时间浪费较多,而且又占用内存空间 。
2,汇编成绝对地址格式,装入后运行将源程序的不同模块分别汇编成绝对地址的目标程序,装入相应的内容空间后,才能运行 。
优点:装入程序比较简单,占用空间小,可连接几个用不同语言写成的模块 。
缺点:由用户直接管理内存资源,易出错 。
3,汇编成浮动模块,连接和装入后运行汇编程序将各个程序模块汇编成相对地址的浮动目标文件,即每个模块的地址均从 0开始,然后由连接和装入程序将它们连接一个完整的绝对地址的目标程序,该目标程序可立即运行,也可存储在磁盘上备用 。 特点是:可连接不同语言的程序模块 。
4,动态连接和装入
\
汇编时仍产生浮动目标程序,而且只有当某个模块被调用时才连接和装入 。
Intel 8086/8088汇编程序采用的是第 3种工作方式。
实现一个 8086汇编语言程序运行的过程见下图。
优点:节省内存,各子程序模块可重叠装入,一个模块可为几个用户共享,
缺 点:降低了处理速度。
编写源程序用编辑程序将源程序输入计算机调用汇编程序对源程序进行汇编是否有错误?
调用连接程序对汇编后生成的目标文件 (? · OBJ )进行连接连接是否有错误?
运行连接后生成的可执行文件结果是否有错误?
调用调试文件进行调试运行是否成功?
结束修改已输入的源程序Y
Y
N
Y
Y
N
N
N
程序从编写到运行的过程修改已输入的源程序修改已输入的源程序修改已输入的源程序因此在计算机上运行汇编语言程序的步骤是:
1,用编辑程序建立 ASM源文件。
2,用 TASM程序把源文件转换成 OBJ文件。
3,用 TLINK程序把目标文件转换成 EXE文件。
4,用 DOS命令直接键入文件名就可执行该程序。
编辑程序 PROGR·ASM
文件
PROGR· OBJ
文件
PROGR· EXE
文件汇编程序 连接程序
TASM TLINK
汇编语言程序的建立及汇编过程三、汇编程序对变量和标号的处理汇编程序通过 ASSUME语句了解到运行时各段寄存器的设定值后,就可以对被汇编的指令语句中的变量和标号作如下处理 。
1,检查指令中所引用的变量和标号是否合理,即它们的段属性是否和某个段寄存器的段假设值相符 。
2,检查是否需要为所引用的变量和标号是否产生跨段前缀字节,即检查变量和标号的段属性是否与硬件为该指令所规定的段寄存器的假设值相符 。
下图是汇编程序对指令中引用的变量 /标号是否合理以及是否需要生成跨段前缀字节处理过程的示意图 。
取变量 / 标号的段属性它们是否已被设定在某个段寄存器中?
地址表达式是否有跨段前缀运算符?
前缀是段寄存器吗?
是 JMP或 CALL指令吗?
地址表达式是否带有跨段前缀运算符?
前缀是硬件为该指令规定的段寄存器吗?
汇编生成带段前缀字节的目标指令代码与段属性一致的寄存器是硬件为该指令规定的寄存器吗?
汇编生成不带跨段前缀字节的指令目标代码出错
N
N
Y
Y
NN
N
Y
Y
Y
Y
Y
N
N
汇编程序以变量 /标号段属性的检查与处理四、汇编语言程序上机举例例,把 40个字母 a的字符串从源缓冲区传送到目的缓冲区 。;PROGRAM TITLE GOES HERE--ex_movs;*****************************************************
data segment ;define data segment
source_buffer db 40 dup ('A')
data ends;*****************************************************
extra segment ;define extra segment
dest_buffer db 40 dup (?)
extra ends;*****************************************************
code segment ;define code segment;-------------------------------------------------------------
main proc far ;main part of program
assume cs:code,ds:data,es:extra
start,;starting execution address;set up for return
push ds ;save old data segment
sub ax,ax ;put zero in AX
push ax ;save it on stack;set DS register to current data segment
mov ax,data ;data segment addr
mov ds,ax ; into DS register;set ES register to current extra segment
mov ax,extra ;extra segment addr
mov es,ax ; into ES register
建立 DOS的返回地址;MAIN PART OF PROGRAM GOES HERE
lea si,source_buffer ;put offset addr of source; buffer in SI
lea di,dest_buffer ;put offset addr of destination; buffer in DI
cld ;set DF flag to forward
mov cx,40 ;put count in CX
rep movsb ;move entire string
ret ;return to DOS
main endp ;end of main part of program;--------------------------------------------------------------
code ends ;end of code segment;*******************************************************
end start ;end assembly
下面对该程序进行上机调试:
D:\lxy1>TASM MY ;对源文件 MY进行汇编
Turbo Assembler Version 2.5 Copyright (c) 1988,1991 Borland
International
Assembling file,MY.ASM
*Warning* MY.ASM(8) Reserved word used as symbol,STACK
Error messages,None
Warning messages,1
Passes,1
Remaining memory,423k
D:\lxy1>TLINK MY ;对源文件 MY进行连接
Turbo Link Version 4.0 Copyright (c) 1991 Borland International
D:\lxy1>
程序在存储区中存放的逻辑地址源程序部分 程序执行后各寄存器,标志位的结果数据段中存放的 40个
,A”及对应的 ASCII码
DEBUG调试环境如下:
6.6 汇编语言程序设计的基本方法一、概述
(1) 分析课题,抽象出数学模型。
(2) 确定控制方案和算法。
(3) 画出程序框图,分析设计方案的可行性及实现方法 。
1,汇编语言程序设计的一般步骤
(4) 编制源程序,确定 I/O口地址及存储器空间的具体分配。
(5) 调试修改源程序。
(6) 运行试验,模拟或直接给出各种条件,
使程序充分运行。
(7) 对最终的软件程序进行整理,并建立文档。
2,判断程序质量的标准
(1) 程序的执行时间。
(2) 程序所占用的内存字节数。
(3) 程序的语句行数。
3,程序流程图
(1) 用 方框 表示工作框,分别有一个入口和出口,用箭头表示,框内简单说明所完成的特定功能 。
程序流程图是在编写程序之前用于确定程序的结构和相互之间的关系。按惯例:
(3) 六边形框 为子程序或过程框,框内标出子程序或过程名,有一个入口一个出口,
用箭头表示 。
(4) 带箭头的直线,各框之间用带箭头的直线连接起来,表示程序的走向 。
(2) 用 菱形 表示判断框,菱形内标明比较,
判断和条件,一个入口几个出口 。
二、顺序程序设计 (算术运算程序 )
直线运行程序是没有分支,没有循环,
没有转移顺序执行的一种简单程序 。
例,两个 32位无符号数乘法程序
8088/8086中只有 16bit运算指令,两个
32bit数相乘无法直接用指令实现,但可以利用 16bit乘法指令,采用快速乘法算法编程实现 。
A B
B × D
C D
A × D
B × C
A × C+
×
部分积 1
部分积 2
部分积 3
部分积 4
32位数乘法图解用 16位乘法指令实现 32位乘法的程序流程图设地址指针被乘数的低 16位 B?AX
乘数的低 16位 D?SI
乘数的高 16位 C?DI
B? D = 部分积 1
存入缓冲区被乘数的高 16位?AX
A? D = 部分积 2
部分积 2的低 16位
+部分积 1的高 16位进位加至部分积 2高 16位
A? C = 部分积 4
存入缓冲区
B? C = 部分积 3
与前面的对应 16位相加保存进位恢复进位部分积 4与前面的和相加保存在缓冲区返回相应的程序为:
NAME 32- BIT- MULTIPLY
DATA SEGMENT
MULNUM DW 0000,0FFFFH,0000,0FFFFH,4 DUP(?)
DATA ENDS
STACK SEGMENT
DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS,CODE,DS:DATA,SS:STACK,ES:DATA
START PROC FAR
BEGIN,PUSH DS ;DS中包含的是程序段前缀的起始地址
MOV AX,0
PUSH AX ;设置返回至 DOS的段值和 IP值
MOV AX,DATA
MOV DS,AX
MOV ES,AX ;置段寄存器初值
LEA BX,MULNUM
MULU32,MOV AX,[BX] ; B?AX
MOV SI,[BX+4] ; D?SI
MOV DI,[BX+6] ; C?DI
MUL SI ; B× D
MOV [BX+8],AX ;保存部分积 1
MOV [BX+0AH],DX
MOV AX,[BX+2] ; A?AX
MUL SI ; A× D
ADD AX,[BX+0AH]
ADC DX,0 ;部分积 2的一部分与部分积 1的相;应部分相加
MOV [BX+0AH],AX
MOV [BX+0CH],DX ; 保存
MOV AX,[BX] ; B?AX
MUL DI ; B× C
ADD AX,[BX+0AH] ; 与部分积 3的相应部分相加
ADC DX,[BX+0CH]
MOV [BX+0AH],AX
MOV [BX+0CH],DX
PUSHF ; 保存后一次相加的进位位
MOV AX,[BX+2] ; A?AX
MUL DI ; A× C
POPF
ADC AX,[BX+0CH] ; 与部分积 4的相应部分相加
ADC DX,0
MOV [BX+0CH],AX
MOV [BX+0EH],DX
RET
START ENDP
CODE ENDS
END BEGIN
三、分支程序设计程序中根据各种可能出现的情况及相应的处理方法分成若干支路,运行时,根据不同情况有选择地执行相应处理程序 。
例,符号函数

1
0
1
( x )s ig n y
当 x > 0时当 x = 0时当 x < 0时其程序流程图如下图所示相应的程序段为;
X
出 口入 口
<0 >0
=0
y?- 1 y?0 y?1
符号函数流程图
MOV AX,BUFFER
OR AX,AX
JE ZERO
JNS PLUS
MOV BX,-1
JMP CONTI
ZERO,MOV BX,0
JMP CONTI
PLUS,MOV BX,1
CONTI,…

四、循环程序一段程序有时重复执行多次,就牵涉到循环程序结构,其组成部分为:
1,循环体即要求重复执行的程序段部分,包括循环工作部分和循环控制部分 。
2,循环初态循环开始时往往要置初态,赋初值,
包括循环工作部分初态和结束条件初态 。
3,循环结束条件在循环程序中必须给出循环结束条件,
否则就会进入死循环,结束条件有好多种,
最常见的有:
(1) 用计数器控制循环
(2) 按问题的条件控制循环
(3) 多重循环
(4) 用开关量控制循环
(5) 用逻辑尺控制循环例,某一数据采集系统采得的 12个数据已存放到 BUF缓冲区,若第 1,2,5,7,10
这几个测量值作 FUN1 处理,其余的作
FUN2处理 。
我们设置为一个位串,作 FUN1处理的位记为 0,作 FUN2处理的位记为 1,则实现上述控制要求的位串为 0011010110110000,
此位串称为逻辑尺 (不足 16bit用 0补足 ),可放在某一寄存器中,其流程图如下图所示 。
初始化:设逻辑尺,
设循环次数,设地址指针取逻辑尺逻辑尺左移一位标志 C=0?
调用 FUN1 调用 FUN2
完成否?
存结果,修改地址指针返回
Y N
N
Y
上图相应程序如下:
NAME LOOP_USE_LOGIC_RULA
DATA SEGMENT
BUFFER DW 11,22,33,44,55,66,77,88,99,1234,5678,9876
BLOCK DW 12 DUP (?)
COUNT EQU 12
LOGRUL EQU 0011010110110000B
DATA ENDS
STACK SEGMENT PARA STACK ' STACK '
DB 100 DUP (?)
STACK ENDS
CODE SEGMENT
ASSUME CS,CODE,DS:DATA,ES,DATA,SS:STACK
START PROC FAR
BEGIN,PUSH DS
MOV AX,0
PUSH AX ; 为返回 DOS,设置返回地址
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV DX,LOGRUL
MOV CX,COUNT
LEA BX,BUFFER
LEA SI,BLOCK
AGAIN,MOV AX,[BX]
RCL DX,1 ; 逻辑尺左移 1位
JC ANOTH
CALL FUN1
NEXT,MOV [SI],AX
INC BX
INC BX
INC SI
INC SI
LOOP AGAIN
RET
ANOTH,CALL FUN2
JMP NEXT
START ENDP
FUN1 PROC
ADD AX,AX
RET
FUN1 ENDP
FUN2 PROC
ADD AX,AX
ADD AX,AX
RET
FUN2 ENDP
CODE ENDS
END BEGIN
五、子程序设计常把具有独立功能模块设计成子程序,
在注释部分要明确描述:
(1) 本子程序的目的;
(2) 输入和输出参数;
(3) 所用寄存器和存储单元。
例,软件时钟程序首先在 CRT上输出一个要求用户用键盘输入时钟初始值的提示符 ‘,’。 用键盘敲入格式为 ‘ XX(时 ):
XX(分 ),XX(秒 )’
然后调用一个延时 1秒的子程序 (在程序中只用一个延时子程序代替,并未精确计算延时 1秒的子程序 ),每过去 1
秒使秒值 1,然后检查是否已为 60,若不是,则转至显示;
若是,则使秒值为 0,分值为 1,检查是否已为 60,若不是则转显示;若是,则使分值为 0,时值加 1。 接着检查时值是否已为 24,若不是则转显示;若是,则使时值为 0,接着也转显示,其流程如下图所示 。
调用,1”秒延时子程序秒增量
DAA调整
=60?
置秒值为 0
分值加 1
DAA调整
=60?
把 CH,DH,DL中的时分秒值转换为
ASCII码,送至缓冲区中利用功能调用 9,输出缓冲区中的时间值
=24?
DAA调整时值加 1
置分值为 0
初始化利用功能调用 2,输出提示符‘,’,要求输入当前时间利用功能调用 10,按规定格式从控制台输入 当前时间把输入数的 ASCII
码变为 BCD
把输入的时,分,秒的 BCD值转换为二进制数,分别送至 CH,DH,DL
置时值为 0
N
N
N
Y
Y
Y
name output_clock
data segment ;开辟 10个字节的缓冲区便于存放“时,分,秒”值
buffer db 10
db?
db 10 dup(?)
data ends
stack segment para stack 'stack'
db 100 dup(?)
stack ends
code segment
assume cs:code,ds:data,es:data,ss:stack
start proc far
begin,push ds
mov ax,0
push ax ;设置 DOS的返回地址
mov ax,data
mov ds,ax
mov es,ax
mov dl,':'
mov ah,2 ;输出提示符“:”
int 21h
lea dx,buffer
mov ah,10
int 21h ;向 buffer输入当前时钟初值
lea bx,buffer+2
mov al,[bx]
and al,0fh
mov [bx],al
inc bx
mov al,[bx]
and al,0fh
mov [bx],al
inc bx ;将时值的 ASCII码化为未压缩的 BCD码并放回原处
inc bx
mov al,[bx]
and al,0fh
mov [bx],al
inc bx
mov al,[bx]
and al,0fh
mov [bx],al
inc bx ;将分值的 ASCII码化为未压缩的 BCD码并放回原处
inc bx
mov al,[bx]
and al,0fh
mov [bx],al
inc bx
mov al,[bx]
and al,0fh
mov [bx],al ;将秒值的 ASCII码化为未压缩的 BCD码并放回原处
lea bx,buffer+2
mov al,[bx]
call mul10
mov ch,al ;时值压缩的 BCD码放入 CH中
inc bx
inc bx
mov al,[bx]
call mul10
mov dh,al ;分值压缩的 BCD码放入 DH中
inc bx
inc bx
mov al,[bx]
call mul10
mov dl,al ;秒值压缩的 BCD码放入 DL中
mov al,dl
add al,1
daa
mov dl,al
cmp al,60h ;秒值加 1不等于 60则将当前时钟值转换为 ASCII码再去显示
jne dispy
mov dl,0 ;否则秒值为 0,分值加 1
mov al,dh
add al,1
daa
mov dh,al
cmp al,60h ; 分值不等于 60则将当前时钟值转换为 ASCII码再去显示
jne dispy
mov dh,0 ;否则分值为 0,时值加 1
mov al,ch
add al,1
daa
mov ch,al
cmp al,24h ;时值不等于 24则将当前时钟值转换为 ASCII码再去显示
jne dispy
mov ch,0 ;否则时值为 0再去显示
again,call delay ;延时 1秒
mov al,0dh
mov [bx],al
inc bx
mov al,0ah
mov [bx],al
inc bx
mov al,ch
call tran
inc bx
mov al,':'
mov [bx],al
inc bx
mov al,dh
call tran
inc bx
mov al,':'
mov [bx],al
inc bx
mov al,dl
dispy,lea bx,buffer
inc bx
mov al,'$'
mov [bx],al
push bx
push cx
push dx
lea dx,buffer
mov ah,9
int 21h
pop dx
pop cx
pop bx
jmp again
call tran
start endp
add al,al
daa
mov cl,al
add al,al
daa
add al,al
daa
add al,cl
daa
mov cl,al
inc bx
mov al,[bx]
add al,cl
ret
mul10 endp
mul10 proc
mov cl,al
shr al,1
shr al,1
shr al,1
shr al,1
or al,30h
mov [bx],al
inc bx
mov al,cl
and al,0fh
or al,30h
mov [bx],al
ret
tran endp
tran proc
delay proc
push cx
push ax
mov cx,300h
l1,mov ax,0ffffh
goon,dec ax
jne goon
loop l1
pop ax
pop cx
ret
delay endp
code ends
end begin
本程序中有 3个子程序
mul10— 将未压缩的 BCD码转换成压缩的 BCD码
tuan— 将压缩的 BCD码转换成 ASCII码,
delay— 延时 1秒若输入当前时钟初值 11,20,32其运行情况如下:
D:\lxy1>MY
:11:20:32
11:20:33
11:20:34
11:20:35
11:20:36
11:20:37
11:20:38
11:20:39
11:20:40
初始化利用功能调用 2,输出提示符‘,’,要求输入当前时间利用功能调用 10,按规定格式从控制台输入 当前时间把输入数的 ASCII
码变为 BCD
把输入的时,分,秒的 BCD值转换为二进制数,分别送至 CH,DH,DL
调用,1”秒延时子程序秒增量
DAA调整
=60?
置秒值为 0
分值加 1
DAA调整
=60?
N
N
Y
把 CH,DH,DL中的时分秒值转换为
ASCII码,送至缓冲区中利用功能调用 9,输出缓冲区中的时间值
=24?
DAA调整时值加 1
置分值为 0
置时值为 0
Y