目录
一、汇编语言程序的开发
1.语句格式
执行性语句
标号: 处理器指令标记符 操作数,操作数
说明性语句
名字 伪指令标记符 参数,参数,...
(1)标号和名字
执行性语句中,标号表示处理器指令在主存中的逻辑地址,可有可无
说明性语句中,名字可以是变量名、段名、子程序名等,反映逻辑地址
标号和名字都是标识符,最多由31个字母、数字及规定的特殊符号(如$ ? @)组成,不能以数字开头
注:汇编语言对大小写不敏感
(2)助记符
助记符反映指令的功能,如MOV,DB
(3)操作数和参数
操作数可以是一个具体的常量,也可以是保存在寄存器的数据,还可以是一个保存在存储器中的变量。
参数可以是常量,变量名,表达式等,可以有多个,用“,”分隔
(4)注释
;后面的内容是注释,便于程序阅读
2.源程序框架
(1)简化段定义的源程序框架
以MASM 6.x版本的简化段定义为例
.model small ;定义程序的存储模式(small表示小端存储)
.stack ;定义堆栈段
.data ;定义数据段
...
.code ;定义代码段
.startup ;程序起始点
...
.exit0 ;主程序代码
... ;子程序代码
(2)完整段定义的源程序框架
stack segment stack
...
stack ends
data segment
...
data ends
code segment 'code'
assume cs:code,ds:data,ss:stack
start: mov ax,data
mov ds,ax
...
mov ax,4c00h
int 21h
...
code ends
end start
3.DOS系统功能调用
DOS提供给程序员的编程资源是以中断调用方法使用的各种子程序
8086CPU支持256个中断,每个中断用中断编号区别,即中断0-255
DOS系统主要分配21h中断,用于程序员调用DOS操作系统功能。
一般方法:
(1)在ah寄存器中设置调用号
(2)在指定寄存器中设置入口参数
(3)int 21h
(4)分析调用执行情况
(1)字符输出(02号DOS功能)
例:
mov ah,02h ;设置功能号
mov al,'?' ;提供入口参数
int 21h ;DOS功能调用:显示
按Ctrl+Break或Ctrl+C则退出
(2)字符串输出(09号DOS功能)
先将要显示的字符串保存在主存,设置入口参数DS:DX等于该字符串首地址,可以输出回车(0DH)和换行(0AH)字符产生回车和换行的作用
例:
string db 'Hello,every!',0dh,0ah,'$'
mov ah,09h
mov dx,offset string
int 21h
(3)字符输入(01H号DOS功能)
AL保存出口参数,即输入字符的ASCII编码
例:判断按键是Y还是N
getkey: mov ah,1
int 21h
cmp al,'y'
je teskey
cmp al,'n'
je nokey
jne getkey
(4)字符串输入(0AH号DOS功能)
要事先在主存设置用于保存输入字符串的缓冲区,并严格按照以下要求:
1)缓冲区第1字节事先填入欲接收的字符个数(包括回车符)
2)第2字节将存放实际输入的字符个数(不包括回车符)
3)从第3字节开始存放输入的字符串
注:实际输入的字符数多余定义数时,多出的字符被丢掉
例:
buffer db 81
db 0
db 81 dup (0)
...
mov ah,0ah
mov dx,seg buffer ;伪指令seg取得buffer的段地址
mov ds,dx
mov dx,offset buffer
int 21h
(5)按键判断(0BH号DOS功能)
按键功能仅判断当前是否有按下的键,设置出口参数AL后退出
若AL=0,说明当前没有按键;如果AL=FFH,说明当前已经按键
getkey: mov ah,0bh
int 21h
or al,al ;分析出口参数,AL=0?
jz getkey ;AL=0,没有按键,继续等待
二、参数、变量、符号
1.数值型参数
常数:
(1)十进制常数——以D/d结尾
(2)十六进制常数——以H/h结尾
(3)二进制常数——以B/b结尾
(4)八进制常数——以Q/q结尾
(5)字符串常数,如'd'==64H
(6)符号常数,利用标识符表达的一个数值
符号名 equ 数值表达式
符号名 equ <字符串>
符号名 = 数值表达式
例:
calldos equ <intt 21h>
注:EQU用于数值等价时不能重复定义符号名,但“=”允许有重复赋值
数值表达式
算术运算符:+,-,*,/,MOD
逻辑运算符:AND,OR,XOR(异或),NOT
移位运算符:SHL,SHR
关系运算符:EQ(相等),NE(不相等),GT(大于),LT(小于),GE(大于等于),LE(小于等于)
高低分离符:HIGH(高字节),LOW(低字节),HIGHWORD(高字),LOWWORD(低字)
2.变量定义伪指令
格式:
变量名 伪指令 初值表
变量名自定义,可没有,表示首元素的逻辑地址
伪指令有DB,DW,DD,DF,DQ,DT
DB为单字节,DW为单字,DD为双字,DF为3字(6字节),DQ为4字(8字节),DT为10字节
初值表是用","分割的参数,主要由数值参数,表达式或"?"(不确定),"DUP"(重复初值)组成
定位伪指令
(1)ORG参数
ORG将当前偏移地址指针指向参数表达的偏移地址
如
org 100h为从100h处安排数据或程序
org $+10 使偏移地址+10,即跳过10字节空间
(2)EVEN
EVEN使当前偏移地址指向偶数地址
(3)ALIGN n (n为2的乘方)
ALIGN 将当前偏移地址指针指向n的整数倍的地址
3.变量和标号的属性
标号和名字一经定义便具有以下属性:
(1)地址属性:标号和名字对应存储单元的逻辑地址
(2)类型属性:标号,子程序名的类型可以是NEAR/FAR
变量名的类型可以是BYTE,WORD,DWORD等
(1)地址操作符
offset 名字/标号 ;取得偏移地址
seg 名字/标号 ;取得段地址
(2)类型操作符
1)类型名 PTR 名字/标号
类型名可以为BYTE,WORD,DWORD,FWORD,QWORD,TBYTE
或是NEAR,FAR
还可以是由STRUCT,RECORD,UNION,TYPEDEF定义的类型
例:
mov al,bytr ptr w_var
2)THIS类型名
this创建使用当前地址,但是类型不同的操作数
b_var que this w_var ;b_var和w_var的地址相同,但是按字节访问
w_var dw 10 dup(0)
注:LABEL等同于EQU THIS
3)TYPE 名字/标号 (返回类型)
类似:
SIZEOF返回整个变量占用的字节数,LENGTH返回数据项数
故SIZEOF=LENGTH*TYPE
三、程序段的定义和属性
1.DOS的程序结构
2.简化段定义的格式
(1)存储模型伪指令
.MODEL语句,格式为:
.model存储模型[,语言模型][,操作系统模型][,堆栈选项]
存储模型有:
tiny
small
compact
medium
huge
large
flat
(2)简化段定义伪指令
1)栈段stack
.stack [大小] ;段名为"stack"
2)数据段data
.data ;段名为"_DATA",定义有初值变量
.data? ;段名为"_BSS",定义无初值变量(在程序运行时才分配空间).const ;段名为"CONST";建立只读的常量数据段
.FARDATA ;建立有初值的远调用数据段
.FARDATA? ;建立无初值的远调用数据段
3)代码段code
.code [段名]
若未给出段名,则为默认(TINY,SMALL,COMPACT,FLAT模型下默认为"_TEXT",MEDIUM,LARGE,HUGE模型下默认为"模块名_TEXT")
(3)程序开始伪指令
.STARTUP伪指令按照给定的CPU类型,根据.MODEL语句选择的存储模型、操作系统和对战模型,产生程序开始执行的代码,同时指定程序开始执行的起始点
(4)程序终止伪指令
.EXIT [返回数码]
通常返回数码为0表示无异常
.EXIT 0代码为:
mov ax,4c00h
int 21h
(5)汇编结束伪指令
end [标号]
标号用于指定程序开始执行点
(6)属性
3.完整段定义的格式
(1)完整段定义伪指令segment ends
段名 segment [定位][组合][段字]['类别']
...
段名 ends;注:堆栈段要采用stack组合类型,代码段应具有'code'类别
1)段定位(Align)——指定逻辑段在主存储器中的边界
byte:段开始为下一个可用的字节地址,属性为1
word:段开始为下一个可用的偶数地址,属性为2
dword:段开始为下一个可用的4倍数地址,属性为4
para:段开始为下一个可用的节地址,属性为16
page:段开始为下一个可用的页地址,属性为256
简化段定义伪指令的代码和数据段默认采用WORD定位,堆栈段默认采用PARA定位
完整段定义伪指令的默认定位属性是PARA,偏移地址从0处开始
2)段组合(Combine)——指定多个逻辑段之间的关系
private(完整段定义默认):本段与其他段没有逻辑关系,不与其他段合并,每段都有自己的段地址
public(简化段定义默认):连接程序把本段与所有同名类型的其他段相邻地连接在一起,然后为所有这些段指定一个共同的段地址,即合成一个物理段
stack(堆栈段必须具有的组合):连接程序将所有stack段按照与public相同的方式进行合并
common:连接程序把所有同名同类型逻辑段制定统一地址,后面的同名同类型将覆盖前面的段,主要用于共享数据
3)段字(Use)——为支持32位段而设置的属性
16位x86CPU默认16位段,即USE16
32位x86CPU默认32位段,即USE32,但可以使用USE16制定标准的16位段
4)类别(Class)——连接程序组织段时,所有同类别段相邻分配
类名位于单引号中
大部分MASM用'code','data','stack'
(2)指定段寄存器伪指令assume
assume 段寄存器名:段名[,段寄存器名:段名]
段名参数可以是:
1.以段定义位置了设置的段名
2.以GROUP伪指令设置的组名
3.保留字NOTHING(表示取消指定的段寄存器与段名的关系)
4.用SEG操作符返回的段地址
汇编程序会根据数据所在的逻辑段,在需要时自动插入段超越前缀
!注:assume不为段寄存器设定初值
(3)段组伪指令group
组名 gruop 段名[,段名...]
段名还可以有 "SEG 变量名/标号名" 形式
段组内各段统一为一个段地址,各段定义的变量和标号的偏移地址相对于段组基地址计算
(4)段顺序伪指令
段在主存中的实际顺序可以设置:
.seg 按照源程序的隔断排序
.dosseg 按照其他微软的程序设计语言使用的标准DOS规定
.alpha 按照段名的字母顺序
完整段定义格式默认.seg,简化段定义默认.dosseg
四、复杂数据结构
1.结构
结构类型定义:
结构名 struct
...
结构名 ends
结构变量定义:
变量名 结构名 <字段初值表>
引用:
结构变量名.结构字段名
例:
student struct
sid dw ?
sname db 'abcdefgh'
math db 0
english db 0
student ends
stu1 student<1,'zhang',85,90>
mov stu1.math,95
2.记录
(1)记录类型说明
记录名 record 位段[,位段……]
位段格式:
位段名:位数[=表达式]
记录长度小于8位时,汇编成1字节
记录长度为8-16位时,汇编成1个字
位段从地位对齐,不用的位为0
person record year:4,sex:1=0,marriage:1=1
(2)记录变量定义
记录变量名 记录名 <段初值表>
zhang person <1000b,1,0> ;值为00100010b=22h
(3)记录变量的引用和记录操作符
变量名:直接引用变量
记录位段名:该位段移位到最低位D0的移位次数
width 记录名/记录位段名:返回记录或记录位段所占的位数
mask 记录位段名:返回记录或记录位段所占的次数
mov al,zhang ;al<--22h
mov bl,year ;bl<--2
mov cl,width person ;cl<--6
mov cl mask sex ;dl<--00000010b=02h