第三章 汇编语言程序设计第一节 汇编语言上机过程第二节 汇编语言程序结构一,程序结构二,语句结构第三节 指示性语句一,程序开始和结束二,段定义三,变量定义四,过程定义五,ASSUME语句六,等值定义七,表达式中的操作符第四节 汇编语言程序举例例一,数据传送例二,查找关键字
▲ DOS的装入和返回功能第五节 BIOS和 DOS功能调用一,概述二,BIOS功能调用三,DOS系统功能调用第六节 汇编语言程序设计一,概述二,汇编语言程序设计举例第三章 汇编语言程序设计第一节 汇编语言上机过程第二节 汇编语言程序结构第三节 指示性语句第四节 汇编语言程序举例第五节 BIOS和 DOS功能调用第六节 汇编语言程序设计第一节 汇编语言上机过程
D:>EDIT ABC.asm
D:>MASM ABC;
有语法错,回 EDIT下改该程序
D:>LINK ABC;
有错,回在 EDIT下改程序
D:>ABC
运行结果错,回 EDIT下改程序或在 DEBUG下调试,找原因 。
D:>DEBUG ABC.exe
编辑源程序 E DIT AB C.A SM
汇编源程序 M A SM   AB C,A S M
形成目标程序 A BC.O BJ
连接目标程序 LIN K A BC,OB J
有连接错误信息?
形成可执行程序 A B C,EX E
装入可执行程序到内存,并执行
D:\>s ub>AB C
下一程序用 D E B UG 调试可执行程序
D:\>s ub> DE B UG AB C.E X E
找到原因
Y
N
Y
N
N
Y
N
有汇编错误信息?
Y
运行结果正确?
用 D E B UG 调试程序查找原因?
第二节 汇编语言程序结构一,程序结构二,语句结构一,程序结构
程序由数条语句构成,每条语句占一行 。
指令性语句 (指令语句 )
指示性语句 (伪指令语句 )
分段结构程序按段编写,与 8088内存分段编址相对应 。
每段由伪操作 SEGMENT开始,由 ENDS结束 。
程序最后为 END结束语句,后跟一启动地址 。
启动地址指示程序开始执行的第一条语句 。
程序中设有返回 DOS的功能 。
使程序执行完后返回 DOS系统的命令接受状态 。
程序中用到内存操作数时,
应按操作数的寻址方式,给相应的段寄存器赋值;汇编语言程序结构例一 movs.asm;实现数据传送功能
aa SEGMENT ;数据段 1
str1 DB 'Hello!’
aa ENDS
bb SEGMENT ;数据段 2
str2 DB 6 dup (?)
bb ENDS
cc SEGMENT ;代码段
ASSUME CS:cc,DS:aa,ES:bb
start,CLD
MOV AX,aa
MOV DS,AX
LEA SI,str1
MOV AX,SEG str2
MOV ES,AX
MOV DI,OFFSET str2
MOV CX,6
REP MOVSB
MOV AH,4CH
INT 21H ;返回 DOS
cc ENDS
END start ;指示程序结束程序可由多个段构成,至少有一个代码段;汇编语言程序结构例二 ( 子程结构 ) scans.asm;用二进制显示中断向量表中数据 D0H的个数
key EQU 0D0H ;用符号表示常量 (关键字 )
code SEGMENT ;代码段开始
ASSUME CS:code
begin,MOV AX,0000H
MOV DS,AX
MOV SI,0000H
MOV CX,0400H
MOV BX,0
MOV AL,key
next,CMP [ SI ],AL
JNZ point
INC BX
point,INC SI
LOOP next
CALL display ; 调用显示子程
MOV AH,4CH ; 返回 DOS
INT 21H;用二进制显示 BX内容子程
display PROC
MOV CX,16
rotate,ROL BX,1
MOV DL,BL
AND DL,01H
ADD DL,30H
MOV AH,2H
INT 21H
LOOP rotate
RET ;子程返回
display ENDP
code ENDS ;代码段结束
END begin ;指示程序结束和;程序入口二、语句结构例 code SEGMENT ;代码段开始
string DB ‘Tsinghua’ ;定义字符串
next,CMP AL,[ BX ] ;查找关键字
display PROC ;显示子程序
key EQU 90H ;字符常量
[ 名字 ] [,] 助记符 [ 操作数,] [ ;注释 ]
名字项 助记符项 操作数项 注释项
[ 名字 ] [,] 助记符 [ 操作数,] [ ;注释 ]
名字项 助记符项 操作数项 注释项
1,名字项
据语句功能的不同,
名字项可用来表示段名,变量名,标号,过程名以及常量名等 。
名字项用一个符号表示。
对符号的规定,
① 由字符 A~Z,a~z,0~9及符号 @,$、下划线 _ 等组成,
最长 31个字符,超出部分忽略。
② 不能用数字打头,以免与十六位进制数相混。
③ 不使用汇编程序中的保留字。 (如指令的助记符等 )
④ 对定义的符号不区分大小写。
[ 名字 ] [,] 助记符 [ 操作数,] [ ;注释 ]
名字项 助记符项 操作数项 注释项
2,助记符项助记符可以是指令,伪操作中的助记符 。
对于指令,汇编程序将其翻译成机器语言指令。
MOV AX,100 → B8 00 01
对于伪操作,汇编程序据其要求的功能进行处理。
data SEGMENT → data与一段值对应
string DB ‘Tsinghua’ → string与一内存地址对应
3,操作数项
操作数给出参与操作的数或数所在的地方 。
操作数多于一个时,用逗号分开 。
操作数可以是常数,寄存器,存储器操作数,
标号名,过程名或表达式等 。
[ 名字 ] [,] 助记符 [ 操作数,] [ ;注释 ]
名字项 助记符项 操作数项 注释项
① 常数给出具体的数据 。 可以是数字常量或字符常量 。
◢ ◢ 数字默认十进制,也可加 D表示十进制数 。 如 1234D,1234
◢ ◢ 数字后加 B表示二进制数 。 如 1010B
◢ ◢ 数字后加 H表示十六进制数 。 如 1234H
◢ ◢ 字符常量,用单引号表示 。 如 ‘ 1234’
汇编时,用字符对应的 ASCII表示 。 如 31H,32H,33H,34H
例 data1 DB 12,34,56 ;十进制
data2 DB 12H,34H,56H ;十六进制
MOV AL,‘G’ ;字符
string DB ‘1234’ ;字符串
② 寄存器
8位,AH,AL,BH,BL,CH,CL,DH,DL
16位,AX,BX,CX,DX,SP,BP,SI,DI
CS,DS,SS,ES
③ 内存操作数放在内存中的操作数,称变量 。 存储器操作数
◢ ◢ 变量用符号表示 。
◢ ◢ 变量的三个属性:段值,偏移值,类型段值,偏移值:地址属性类型:字节,字,双字等例 string DB ‘Tsinghua’ ;定义变量
、、、、、、
MOV AL,string ;应用变量
④ 标号
指示指令存在的地方,是转移,调用指令的操作数 。
标号在符号名的后面加上冒号构成 。 next:
标号的三个属性:段,偏移,类型标号实质上是一符号地址,具有段值,偏移值 。
类型有 SHORT,NEAR和 FAR
⑤ 过程
指示一个子程的入口地址,是调用指令的操作数 。
过程名用一个符号表示 。
过程名实质是一符号地址,有段,偏移,类型三个属性 。
有 NEAR和 FAR类型
⑥ 表达式
由常量,寄存器,标号,变量和一些操作符组合的序列 。
汇编程序对表达式进行运算后,得到一个确定的数值,
再把这个数值汇编到指令中 。
据表达式所表示的内容,分数字表达式,地址表达式 。
表达式是指令或伪操作的操作数,本身不是一条指令 。
表达式中的操作符由汇编程序完成
有关表达式中的操作符在伪指令中介绍 。
例 MOV AX,12 - 4 MOV AX,8 ;数字表达式
LEA BX,[ string + 4 ] ;地址表达式
4,注释项
由分号引出,用来说明语句或程序的功能 。
汇编程序对分号后的内容不做处理 。
作用,① 注释程序,增强程序可读性 。
② 可放在语句最前,暂时注释某语句,调试程序用 。
例,、、; MOV AH,2 ;显示提示信息; MOV DL,’A’; INT 21H
、、、
[ 名字 ] [,] 助记符 [ 操作数,] [ ;注释 ]
名字项 助记符项 操作数项 注释项第三节 指示性语句一,程序开始和结束二,段定义三,变量定义四,过程定义五,ASSUME语句六,等值定义七,表达式中的操作符指示性语句与指令性语句:
指令性语句 是用指令系统中的指令构成的语句 。
例 MOV AX,BX
指示性语句 是指示汇编程序进行汇编的操作 。
例 MOV AX,4 + 8 中的 +
code SEGMENT 中的 SEGMENT
MOV BX,OFFSET string 中的 OFFSET
指示性语句与指令性语句区别一个程序经汇编,连接和装入内存后,在执行程序之前:
◢ 指示性语句的功能已经完成,故又称伪操作 。
◢ 而指令性语句的功能尚未完成,需控制 CPU去执行,才能完成 。
aa SEGMENT ;数据段 1
str1 DB 'Hello!’
aa ENDS
bb SEGMENT ;数据段 2
str2 DB 6 dup (?)
bb ENDS
cc SEGMENT ;代码段
ASSUME CS:cc
ASSUME DS:aa,ES:bb
start,CLD
MOV AX,aa
MOV DS,AX
LEA SI,str1
MOV AX,bb
MOV ES,AX
LEA DI,str2
MOV CX,6
REP MOVSB
MOV AH,4CH
INT 21H
cc ENDS
END start
D:\masm>DEBUG hello2.exe
-U,查看代码段
12A0:0000 FC CLD
12A0:0001 B89E12 MOV AX,129E
12A0:0004 8ED8 MOV DS,AX
12A0:0006 8D360000 LEA SI,[0000]
12A0:000AB89F12 MOV AX,129F
12A0:000D 8EC0 MOV ES,AX
12A0:000F 8D3E0000 LEA DI,[0000]
12A0:0013 B90600 MOV CX,0006
12A0:0016 F3 REPZ
12A0:0017A4 MOVSB
12A0:0018 B44C MOV AH,4C
12A0:001ACD21 INT 21
、、、
-D 129E:0 L10 ;查看数据段 1的内容
129E:0000 48 65 6C 6C 6F 21 00 00-00 00 00 00 00 00 00 00
Hello!..........
-D 129F:0 L10 ;查看数据段 2的内容
129F:0000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
................
-
数据传送源程序 hello2.asm 程序经汇编、连接后,装入内存的情况如下:
常用伪操作介绍一,程序开始和结束二,段定义三,变量定义四,过程定义五,ASSUME语句六,等值定义七,表达式中的操作符一,模块定义和程序结束伪操作
1,NAME 和 TITLE 伪操作格式 NAME 模块名格式 TITLE 模块名
▲ 在源程序开始可用 NAME 或 TITLE 为模块命名,
模块名的作用是指示给连接程序进行连接用 。
▲ 源程序中可无模块定义,此时源文件名作为模块名 。
2,END伪操作格式 END 启动地址
▲ 作用是指示源程序到此结束 。
汇编程序对 END 之后的语句不进行处理 。
程序中所有有效语句应放在 END 语句之前 。
▲ 源程序中必须有 END 结束语句 。
汇编程序对无 END 语句的源程序不进行处理,
只给出无 END 语句错误信息 。
假设 TEST.asm 是一个无 END 语句的汇编语言源程序 。
其汇编结果如下,
D:\ MASM TEST;↙
Microsoft (R) Macro Assembler Version 5.10
Copyright (C) Microsoft Corp 1981,1988,All rights reserved.
End of file encountered on input file
End of file encountered on input file
49968 + 421181 Bytes symbol space free
0 Warning Errors
0 Severe Errors
D:\
由于没有 END语句,汇编程序根本没对源程序进行汇编,
此时显示警告性错误总数为 0,严重性错误总数为 0,
用户不要被此值的误导 。
▲ 启动地址可是一个标号或过程名,指示程序的入口 。
程序装入内存后,系统跳转到入口处,开始执行程序 。
aa SEGMENT ;数据段 1
str1 DB 'Hello!’
aa ENDS
bb SEGMENT ;数据段 2
str2 DB 6 dup (?)
bb ENDS
cc SEGMENT ;代码段
ASSUME CS:cc
ASSUME DS:aa,ES:bb
start,CLD
MOV AX,aa
MOV DS,AX
LEA SI,str1
MOV AX,SEG str2
MOV ES,AX
MOV DI,OFFSET str2
MOV CX,6
REP MOVSB
MOV AH,4CH
INT 21H
cc ENDS
END start
D:\masm>DEBUG hello.exe
-U,查看代码段
129F:0000 FC CLD
129F:0001 B89D12 MOV AX,129D
129F:0004 8ED8 MOV DS,AX
129F:0006 8D360000 LEA SI,[0000]
129F:000AB89E12 MOV AX,129E
129F:000D 8EC0 MOV ES,AX
129F:000FBF0000 MOV DI,0000
129F:0012 B90600 MOV CX,0006
129F:0015 F3 REPZ
129F:0016 A4 MOVSB
129F:0017 B44C MOV AH,4C
129F:0019 CD21 INT 21
、、、
-D 129d:0 l10 ;查看数据段 1的内容
129D:0000 48 65 6C 6C 6F 21 00 00-00 00 00 00 00 00 00
00 Hello!..........
-D 129e:0 l10 ;查看数据段 2的内容
129E:0000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
................
-
二,段定义伪操作格式 段名 SEGMENT
、、、
、、、
段名 ENDS
▲ 段定义由伪操作 SEGMENT开始,ENDS结束 。
其中,SEGMENT 和 ENDS 必须成对出现,
且语句前必须有段名,段名必须相同 。
▲ SEGMENT和 ENDS语句之间可以有指令和其他伪操作,
表示存放在该段内存的变量,指令或其他伪操作对该段内存的处理
▲ 程序中可以定义多个段 。
▲ 程序经汇编,连接及装入内存后,段名为一具体的段值 。
aa SEGMENT ;数据段 1
str1 DB 'Hello!’
aa ENDS
bb SEGMENT ;数据段 2
str2 DB 6 dup (?)
bb ENDS
cc SEGMENT ;代码段
ASSUME CS:cc
ASSUME DS:aa,ES:bb
start,CLD
MOV AX,aa
MOV DS,AX
LEA SI,str1
MOV AX,bb
MOV ES,AX
LEA DI,str2
MOV CX,6
REP MOVSB
MOV AH,4CH
INT 21H
cc ENDS
END start
D:\masm>DEBUG hello2.exe
-U,查看代码段
12A0:0000 FC CLD
12A0:0001 B89E12 MOV AX,129E
12A0:0004 8ED8 MOV DS,AX
12A0:0006 8D360000 LEA SI,[0000]
12A0:000AB89F12 MOV AX,129F
12A0:000D 8EC0 MOV ES,AX
12A0:000F 8D3E0000 LEA DI,[0000]
12A0:0013 B90600 MOV CX,0006
12A0:0016 F3 REPZ
12A0:0017A4 MOVSB
12A0:0018 B44C MOV AH,4C
12A0:001ACD21 INT 21
、、、
-D 129E:0 L10 ;查看数据段 1的内容
129E:0000 48 65 6C 6C 6F 21 00 00-00 00 00 00 00 00 00 00
Hello!..........
-D 129F:0 L10 ;查看数据段 2的内容
129F:0000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
................
-
数据传送源程序,程序经汇编、连接后,装入内存的情况如下:
三,变量定义伪操作格式 变量名 类型助记符 操作数 [,操作数,..,]
▲ 用来定义程序中所用的内存操作数 。
其中 变量名 指示内存操作数的地址 ( 符号地址 )
类型助记符 指示内存操作数的类型 (字节,字,双字等 )
操作数 指示内存操作数的内容
▲ 汇编程序将定义的操作数,按其类型所占单元数,
顺序存入变量名指向的内存单元中 。
▲ 常用的类型助记符有:
DB 指示其后的操作数为字节类型
DW 指示其后的操作数为字类型
DD 指示其后的操作数为双字类型例 1,定义赋初值的变量
data SEGMENT
xx DB 1,-1,0fcH
yy DW 1,-1,0fcH
zz DD 1,- 1,0fcH
data ENDS
xx
yy
zz
01
FF
FC
01
00
FF
FF
FC
00
01
00
00
00
FF
FF
FF
FF
FC
00
00
00
1
- 1
FC
1
- 1
FC
1
- 1
FC
例 2,定义字符串变量 ( 只能用 DB定义 )
data SEGMENT
str1 DB ' TsingHua '
str2 DB 'INPUT:',0dH,0aH,'$'
data ENDS
注意,3个及其以上的字符,
只能用 DB定义
str1 DW ‘abcd’
str2 DD ‘abcd’
str1
str2
54
73
69
6e
67
48
75
61
49
4e
50
55
54
3a
0d
0a
24
‘T’
‘s’
‘i’
‘n’
‘g’
‘H’‘u’
‘a’
‘I’
‘N’
‘P’
‘U’
‘T’
‘:’0dH
0aH
‘$’
▲ 操作数可以是用 常量,表达式和? 表示 。
常量和表达式 表示内存操作数的初始值,
其值应在其定义的类型范围内,否则汇编出错 。
例 aa DB 270
bb DW 80000
用? 表示不置初始值的内存操作数 。
例 cc DB?
可用 DUP 复制操作符 定义相同的操作数,其格式为重复次数 DUP( 操作数 )
例 ee DB 3 DUP ( 4 )
等价于 ee DB 4,4,4
data SEGMENT
xx DB 1,-1,0FCH
yy DW 1,- 1,0FCH
zz DD 1,-1,0FCH
str DB 'TsingHua'
buf DB 4,?,4 DUP (?)
DB ‘dataend’
data ENDS
code SEGMENT
ASSUME CS:code
ASSUME DS:data
start,MOV AX,data
MOV DS,AX
LEA BX,xx
LEA SI,yy
LEA DI,zz
MOV AH,4CH
INT 21H
code ENDS
END start
D:\ MA SM > D E B UG v ari ble,e xe
- U
12A 1:0 000 B 8 9E 12 MO V AX,129E
12A 1:0 003 8 E D8 MO V DS,AX
12A 1:0 005 8 D 1E 000 0 LEA BX,[0000]
12A 1:0 009 8 D 360 300 LEA SI,[0003 ]
12A 1:0 00 D 8 D 3E 090 0 LEA DI,[0009]
12A 1:0 01 1 8 D 1E 150 0 LEA BX,[0015]
12A 1:0 015 8 D 361 D0 0 LEA SI,[001D]
12A 1:0 019 B 4 4C MO V AH,4C
12A 1:0 01B C D2 1 INT 21
12A 1:0 01 D F F 362 43E PUSH [3E2 4]
-D 1 29E,0 L 30
129E,0 000 01 F F FC 0 1 0 0 F F F F F C-00 0 1 00 00 0 0 F F F F F F,.,..,..,..,,..,
129E,0 010 FF FC 00 0 0 0 0 5 4 73 69 -6E 6 7 4 8 7 5 6 1 0 4 0 0 00,.,.,T singH ua,..
129E,0 020 00 0 0 0 0 6 4 6 1 74 61 65 -6E 6 4 00 0 0 0 0 00 0 0 00,.,d atae nd...,..
129E,0 030 B8 9E 12 8E D8 8D 1 E 0 0-00 8D 3 6 0 3 00 8 D 3E 09,..,..,..,6..,>.
-
xx
yy
zz
str buf
‘d a t a e n d’
段名 d a t a
变量 xx
变量 yy
变量 zz
变量 s tr
变量 b u f
例 4,在 DEBUG下查看变量存放情况。
aa SEGMENT ;数据段 1
str1 DB 'Hello!’
aa ENDS
bb SEGMENT ;数据段 2
str2 DB 6 dup (?)
bb ENDS
cc SEGMENT ;代码段
ASSUME CS:cc
ASSUME DS:aa,ES:bb
start,CLD
MOV AX,aa
MOV DS,AX
LEA SI,str1
MOV AX,bb
MOV ES,AX
LEA DI,str2
MOV CX,6
REP MOVSB
MOV AH,4CH
INT 21H
cc ENDS
END start
D:\masm>DEBUG hello2.exe
-U,查看代码段
12A0:0000 FC CLD
12A0:0001 B89E12 MOV AX,129E
12A0:0004 8ED8 MOV DS,AX
12A0:0006 8D360000 LEA SI,[0000]
12A0:000AB89F12 MOV AX,129F
12A0:000D 8EC0 MOV ES,AX
12A0:000F 8D3E0000 LEA DI,[0000]
12A0:0013 B90600 MOV CX,0006
12A0:0016 F3 REPZ
12A0:0017A4 MOVSB
12A0:0018 B44C MOV AH,4C
12A0:001ACD21 INT 21
、、、
-D 129E:0 L10 ;查看数据段 1的内容
129E:0000 48 65 6C 6C 6F 21 00 00-00 00 00 00 00 00 00 00
Hello!..........
-D 129F:0 L10 ;查看数据段 2的内容
129F:0000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
................
-
数据传送源程序,程序经汇编、连接后,装入内存的情况如下:
四,过程定义伪操作格式 过程名 PROC 类型
、、、
过程名 ENDP
▲ 过程定义由伪操作 PROC开始,ENDP结束 。
其中,PROC 和 ENDP 必须成对出现,
且语句前必须有过程名,过程名必须相同 。
▲ PROC和 ENDP语句之间为子程的指令序列 。
▲ 程序中可以定义多个过程 。
▲ 程序经汇编,连接及装入内存后,
过程名为一具体的内存地址,指示子程入口 。
▲ 过程名常用作 CALL调用指令的操作数,
子程的最后安排 RET返回指令,使执行完子程后能返回调用处 。
▲ 过程有两种类型,NEAR和 FAR
无类型项时,默认为 NEAR类型 。
当过程与调用指令不在同一段时,应将过程定义为 FAR 类型 。
过程类型决定子程中 RET的返回类型例 1 display PROC
、、
、,C3H
、、
RET ;NEAR 属性的过程对应段内返回
display ENDP
例 2 display PROC FAR
、、
、,CBH
、、
RET ;FAR属性的过程对应段间返回
display ENDP;汇编语言程序结构例二 ( 子程结构 );用二进制显示中断向量表中数据 D0H的个数
key EQU 0D0H ;用符号表示常量 (关键字 )
code SEGMENT ;代码段开始
ASSUME CS:code
begin,MOV AX,0000H
MOV DS,AX
MOV SI,0000H
MOV CX,0400H
MOV BX,0
MOV AL,key
next,CMP [ SI ],AL
JNZ point
INC BX
point,INC SI
LOOP next
CALL display ; 调用显示子程
MOV AH,4CH ; 返回 DOS
INT 21H;用二进制显示 BX内容子程
display PROC
MOV CX,16
rotate,ROL BX,1
MOV DL,BL
AND DL,01H
ADD DL,30H
MOV AH,2H
INT 21H
LOOP rotate
RET ;子程返回
display ENDP
code ENDS ;代码段结束
END begin ;指示程序结束和;程序入口五,ASSUME伪操作格式 ASSUME 段寄存器:段名 [,段寄存器,段名,… ]
其中 段寄存器 为 CS,DS,ES,SS中的一个段名 为用伪操作 SEGMENT定义过的段名例 ASSUME CS,cc,DS:aa
▲ ASSUME 伪操作的作用指示汇编程序指令中用到的标号,过程及变量所在的段 。
其中 对标号,过程必须用 CS 段寄存器指示对变量可用 CS,DS,ES,SS段寄存器指示
▲ 若未用 ASSUME语句指示指令中用到的标号,
过程和变量所在的段,汇编程序将给出错误信息 。
▲ ASSUME语句只起指示作用,并无实际的操作 。
在程序中引用定义的变量做内存操作数时,
需按寻址方式用传送指令 ( 如 MOV) 给相应的段寄存器赋值 。
例 用程序实现 1234H + 5678H
va lu e
r esu lt
34
12
78
56
00
00
data SEGMENT
value DW 1234H,5678H
result DW?
data ENDS
code SEGMENT
ASSUME CS:code,DS:data
start,MOV AX,data ;给 DS赋值
MOV DS,AX
MOV AX,value ;取数
ADD AX,value+2 ;两数相加
MOV result,AX ;保存结果
MOV AH,4CH ;返回 DOS
INT 21H
code ENDS
END start
注释掉 ASSUME语句,其汇编结果:
data SEGMENT
value DW 1234H,5678H
result DW?
data ENDS
code SEGMENT; ASSUME CS:code,DS:data
start,MOV AX,data
MOV DS,AX
MOV AX,value
ADD AX,value+2
MOV result,AX
MOV AH,4CH
INT 21H
code ENDS
END start
D:\MASM>MASM assume;
Microsoft (R) MacroAssembler Version 5.10
Copyright (C) Microsoft Corp 1981,1988,All rights
reserved.
assume.ASM(8),Missing or unreachable CS
assume.ASM(10),Cannot address with segment register
assume.ASM(11),Cannot address with segment register
assume.ASM(12),Cannot address with segment register
49872 + 421341 Bytes symbol space free
0 Warning Errors
4 Severe Errors
D:\MASM>
程序中有 ASSUME语句,经汇编,连接和装入内存后的情况:
data SEGMENT
value DW 1234H,5678H
result DW?
data ENDS
code SEGMENT
ASSUME CS:code,DS:data
start,MOV AX,data ;给 DS赋值
MOV DS,AX
MOV AX,value ;取数
ADD AX,value+2 ;两数相加
MOV result,AX ;保存结果
MOV AH,4CH ;返回 DOS
INT 21H
code ENDS
D:\MASM>DEBUG assume.exe
-R ;查看程序执行前各寄存器
AX=0000 BX=0000 CX=0023 DX=0000
SP=0000 BP=0000 SI=0000 DI=0000
DS=1295 ES=1295 SS=12A5
CS=12A6 IP=0000
NV UPEI PL NZ NA PO NC
12A6:0000 B8A512 MOV AX,12A5
-U ;查看在内存的程序
12A6:0000 B8A512 MOV AX,12A5
12A6:0003 8ED8 MOV DS,AX
12A6:0005A10000 MOV AX,[ 0000 ]
12A6:0008 03060200 ADD AX,[ 0002 ]
12A6:000CA30400 MOV [ 0004 ],AX
12A6:000F B44C MOV AH,4C
12A6:0011 CD21 INT 21
、、、、、
-注意:
程序装入内存后,执行程序前,
当前的 DS值并非程序定义的 data段值,1295 不等于 12A5
思考,如果上例中没有 MOV DS,AX 程序执行的结果会怎样?
D:\MASM>DEBUG assume.exe
-R ;查看程序执行前各寄存器
AX=0000 BX=0000 CX=0023 DX=0000
SP=0000 BP=0000 SI=0000 DI=0000
DS=1295 ES=1295 SS=12A5 CS=12A6 IP=0000
NV UPEI PL NZ NA PO NC
12A6:0000 B8A512 MOV AX,12A5
-U ;查看在内存的程序
12A6:0000 B8A512 MOV AX,12A5
12A6:0003A10000 MOV AX,[ 0000 ]
12A6:0006 03060200 ADD AX,[ 0002 ]
12A6:000AA30400 MOV [ 0004 ],AX
12A6:000D B44C MOV AH,4C
12A6:000F CD21 INT 21
、、、、、
data SEGMENT
value DW 1234H,5678H
result DW?
data ENDS
code SEGMENT
ASSUME CS:code,DS:data
start,MOV AX,data ;给 DS赋值; MOV DS,AX
MOV AX,value ;取数
ADD AX,value+2 ;两数相加
MOV result,AX ;保存结果
MOV AH,4CH ;返回 DOS
INT 21H
code ENDS
结论:
1,ASSUME语句只起指示作用,没有赋值作用
2,程序中用到内存操作数时,
应按操作数的寻址方式,给相应的段寄存器赋值 。
六,等值定义伪操作格式 符号名 EQU 需等值的表达式
▲ 作用是用符号名等值指定的表达式其中 表达式可以是任何有效的操作数汇编时用语句中的表达式代替程序中符号所在的地方 。
▲ 应用:
1.定义符号常量,方便修改程序 。
2,某表达式多次出现时,用等值伪操作可以方便编程 。;汇编语言程序结构例二 ( 子程结构 );用二进制显示中断向量表中数据 D0H的个数
key EQU 0D0H ;用符号表示常量 (关键字 )
code SEGMENT ;代码段开始
ASSUME CS:code
begin,MOV AX,0000H
MOV DS,AX
MOV SI,0000H
MOV CX,0400H
MOV BX,0
MOV AL,key
next,CMP [ SI ],AL
JNZ point
INC BX
point,INC SI
LOOP next
CALL display ; 调用显示子程
MOV AH,4CH ; 返回 DOS
INT 21H;用二进制显示 BX内容子程
display PROC
MOV CX,16
rotate,ROL BX,1
MOV DL,BL
AND DL,01H
ADD DL,30H
MOV AH,2H
INT 21H
LOOP rotate
RET ;子程返回
display ENDP
code ENDS ;代码段结束
END begin ;指示程序结束和;程序入口七,表达式中的操作符
▲ 有以下几类,
1,算术运算符 ( +,-,*,/,MOD )
2,逻辑运算符 ( AND,OR,NOT,XOR )
3,关系运算符 ( EQ,NE,GT,GE,LT,LE )
真,FFFFH; 假,0
4,数值返回操作符 ( SEG,OFFSET )
5,类型操作 ( PTR )
6,地址记数器 ( $ )
▲ 表达式中的操作符是由汇编程序进行处理的运算符号 。
例,
1,算术运算符 ( +,-,*,/,MOD(取余数 ) )
MOV AX,6 * 8 ← MOV AX,48
2,逻辑运算符 (AND,OR,NOT,XOR)
MOV AX,80h OR 70h ← MOV AX,0F0h
3,关系运算符 ( EQ,NE,GT,GE,LT,LE )
真,FFFFH; 假,0
MOV AX,1 GE 2 ← MOV AX,0
4,数值返回操作符 ( SEG,OFFSET )
MOV AX,SEG string ← MOV AX,1270H
MOV BX,OFFSET string ← MOV AX,0002H
注意,SEG,OFFSET只能对符号地址操作
mov ax,seg [bx]
mov bx,offset [si]
5,类型操作 ( PTR )
MOV BYTE PTR [ BX ],0 ;字节类型
MOV WORD PTR [ BX ],0 ;字类型
6,地址记数器 (自看 )
▲ 汇编程序利用地址记数器,
确定该段内各指令,变量,标号和过程名的偏移地址 。
SEGMENT伪操作将地址记数器的值清零 ;
每处理一条指令,地址计数器就增加一个值,
即该指令所需的字节数 ;
在汇编过程中,
地址计数器的值为当前正在被汇编的指令的偏移地址 ;
可用符号 $ 引用地址记数器的值 。
地址记数器 $
▲ 汇编程序利用地址记数器,
确定该段内各指令,变量,
标号和过程名的偏移地址 。
SEGMENT将地址记数器的值清零 ;
每处理一条指令,
地址计数器就增加一个值,
即该指令所需的字节数 ;
在汇编过程中,
地址计数器的值为当前正在被汇编的指令的偏移地址 ;
可用符号 $ 引用地址记数器的值 。
$是一个随汇编过程变化的量地址记数器 $的值
aa SEGMENT 0
str1 DB ‘Tsinghua’ 0
lenth EQU $ - str1 8
aa ENDS
bb SEGMENT 0
str2 DB lenth DUP(?) 0
bb ENDS
cc SEGMENT
ASSUME CS,cc,DS,aa,ES,bb
start,CLD
MOV AX,aa
MOV DS,AX
LEA SI,str1 ← LEA SI,[ 0000]
MOV AX,bb
MOV ES,AX
LEA DI,str2 ← LEA DI,[ 0000]
MOV CX,lenth ← MOV CX,8
REP MOVSB
MOV AH,4CH
INT 21H
cc ENDS
END start
aa SEGMENT
str1 DB ‘Tsinghua’
lenth EQU $ - str1
aa ENDS
bb SEGMENT
str2 DB lenth DUP(?)
bb ENDS
cc SEGMENT
ASSUME CS:cc
ASSUME DS:aa,ES:bb
start,CLD
MOV AX,aa
MOV DS,AX
LEA SI,str1
MOV AX,bb
MOV ES,AX
LEA DI,str2
MOV CX,lenth
REP MOVSB
MOV AH,4CH
INT 21H
cc ENDS
END start
D:\MASM>DEBUG test$.exe
-U
129F:0000 FC CLD
129F:0001 B89D12 MOV AX,129D
129F:0004 8ED8 MOV DS,AX
129F:0006 8D360000 LEA SI,[ 0000]
129F:000A B89E12 MOV AX,129E
129F:000D 8EC0 MOV ES,AX
129F:000F 8D3E0000 LEA DI,[ 0000]
129F:0013 B90800 MOV CX,0008
129F:0016 F3 REPZ
129F:0017A4 MOVSB
129F:0018 B44C MOV AH,4C
129F:001A CD21 INT 21
、、、、、
-
在 DEBUG下查看程序代码: