一、源程序格式
- 由段组成
- 包含若干code segment, data segment, extra segment(?), stack segment. Order is not concerned.
- 需独立运行的程序必须有:一个代码段,指示程序执行的起始点(一个程序只有一个起始点)
- 所有可执行性语句必须位于某一个代码段内;说明性语句可根据需要位于任一段内
- 通常程序还需要一个堆栈段
二、语句格式
(1)executable code/执行性语句
- 表达处理器指令(硬指令)/Machine code ——使CPU产生动作、并在程序执行时才处理的指令;与具体的processor有关,与assembler无关
- 汇编后对应一条指令代码
- 由处理器指令组成的代码序列——程序设计的主体
- Label: Instruction Operand, Operand ;comment
- Label(标号):硬指令位置(逻辑地址)和属性的标识符,跟冒号
- Operand: immediate data, register, memory
(2) descriptive code/说明性语句
- 表达伪指令 / Directive ——不产生CPU动作、在程序执行前由Assembler处理的说明性指令;与Processor无关、与assembler有关
- 指示源程序如何汇编、变量怎样定义、过程怎么设置等
- Name Directive Parameter,Parameter,... ;comment
- Name(名字):伪指令位置(逻辑地址)和属性的标识符,无冒号
- Parameter: constant, variable, expression
(3)标识符(Identifier)
(4)保留字(Reserved Word)/关键字——汇编程序已经利用的标识符
- Instruction: MOV, ADD
- Directive: DB, DW
- Operator: OFFSET, PTR
- Register: AX, CS
- 预定义符号:@data
(5) MASM支持续行符“/"
(6)简化段定义格式
.model small ;定义程序的存储模式(小型模式)
.stack ;定义堆栈段(默认是1kb空间)
.data ;定义数据段
... ;数据定义
.coder ;定义代码段
start: mov ax,@data ;程序起始点
mov ds,ax ;设置DS指向用户定义的数据段
... ;程序代码
mov ax,4c00h
int 21h ;程序结束点,返回dos
... ;子程序代码
end start ;汇编结束,同时指明程序起始点start
关于程序的开始:
- 在start后;
- Linker会根据程序起始点正确地设置CS和IP值,根据程序大小和堆栈段大小设置SS和SP;
- Linker没有设置DS和ES值。程序如果使用数据段或附加段,必须明确给DS或ES赋值;
关于程序终止和汇编结束:
- 程序终止:mov ax,4c00h int 21h
- 汇编结束:将源程序翻译成目标模块代码的过程结束:end start
- 二者不同
(7)完整段定义格式
- 利用segment和ends一对伪指令定义逻辑段
- 同时配合assume伪指令,指明逻辑段是代码段、堆栈段、数据段、还是附加段
- 优点:指明逻辑段的定位、组合、类别等属性
An example (identify which are states, which are directive)
Define a code segment at 0F800h
dumcod segment at 0f800h <Directive
org 9h <Directive
dumst label far <Directive
dumcod ends
;
;--------------Code Segment Here---------------;
;f8000-fffff for program <Directive
code_seg segment <Directive
assume cs:code_seg <Directive
;--------------Main Program here----------------;
start:
mov ax,data_seg <STATE
mov ds,ax ;initialize DS <STATE
assume ds:data_segment <Directive
mov ax,stack_seg <STATE
mov ss,ax ;initialize SS <STATE
assume ss:stack_seg <Directive
mov sp,top_of_stack ;initiaize SP<STATE
loop1: nop <STATE
jmp loop1 <STATE
;---------------Setup the Reset Vector----------;
org 07ff0h <Directive
jmp dumst <STATE
code_seg ends <STATE
end start <STATE
(8) 可执行程序的结构
两种可执行程序
.exe: 可以有多个代码段、数据段,程序长度可超过64kb;
.com: 只有一个逻辑段,程序长度不超过64kb.
三、数据
1. 常量
(1). 常数
(2). 字符串(DB)
其数值时每个字符对应的ASCII码值
'AB'=4142H
(3). 符号常量
EQU,'='
不占内存空间
(4). 数值表达式
2. 变量——可读写的内存单元——地址不变,数据可变
先定义,后使用
Define--DB, DW, DD
定义时,变量名有时可以缺省;
?表示未赋初值
DUP
符号地址:表示初值表首元素的逻辑地址
变量定义的实例:
DB
;data_seg
X db 'a',-5,?
db 2 dup(100)
Y db ’ABC’
array db 2 dup(2,3,2 dup(4))
mov al, X
dec X+1
mov Y, al
DW
;data_seg
count dw 8000h,?,'AB'
maxint equ 64h
number dw maxint
array dw maxint dup(0)
DD
可以是有符号或无符号的32bits整数
也可以用来表达 16bit段地址和16bit的偏移地址的远指针
vardd DD 0,?,12345678h
farpoint DD 00400078h
练习:输出下列代码执行后的结果
;data_seg
bvar1 db 100,01100100b,64h,'d'
minint = 5
bvar2 db -1,minint,minint+5
db ?,2 dup(20h)
wvar1 dw 2010h, 4*4
wvar2 dw ?
dvar dd 12347777h,87651111h,?
abc db 'a','b','c',?
maxint equ 0ah
string db 'ABCDEFGHIJ'
crlfs db 13,10,'$'
array1 dw maxint dup(0)
array db 2 dup(2,3,2 dup(4))
;code_seg
mov dl,bvar1
dec bvar2+1
mov abc[3], dl
mov ax, word ptr dvar[0]
mov dx, word ptr dvar[2]
add ax, word ptr dvar[4]
adc dx, word ptr dvar[6]
mov word ptr dvar[8], ax
mov word ptr dvar[10], dx
mov cx, maxint
mov bx,0
again: add string[bx],3
inc bx
loop again
lea dx,abc
mov ah,9
int 21h
四、变量的定位
Assembler按照指令的先后顺序,一个接一个的分配存储空间;
按照段定义伪指令规定的边界定位属性,确定每个逻辑段的起始位置(包括偏移地址);
ORG 参数 ;控制数据或代码所在的偏移地址
将当前的偏移地址指针指向参数表达的偏移地址
e.g.:
1. org 100h ;从100h处安排数据或程序
2. org $+10 ;偏移地址加10,即跳过10个字节空间
$表示当前偏移地址值
五、名字和标号的属性
Name and Label
一经使用便具有两种属性
1. 什么属性?
2. 如何获取这些属性?
1. 逻辑地址属性——名字和标号对应存储单元的逻辑地址,含段地址和偏移地址;
类型属性——
变量名(name):byte/word/dword
标号(label)、段名(name)、子程序名(name):near/far
(near: 段内调用;far: 段间调用)
2. 使用操作符
地址操作符:
[]
$
: 段前缀,采用指定的段地址寄存器
OFFSET name/label
SEG name/label
类型操作符:
对名字或标号的类型属性进行设置
类型名(byte/word/dword/near/far) PTR name/label
对变量:lengthof(获知某变量名指向多少个数据项),sizeof(获知它占用多少字节空间)