DATAS SEGMENT
FIVE DB 5
DATAS ENDS
STACKS SEGMENT
DB 128 DUP (?);定义堆栈段长度为128 无初始化 对全局变量赋值为0
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
MOV AL,FIVE
ADD AL,3
ADD AL,30H
MOV DL,AL
MOV AH,2
INT 21H
MOV AH,4CH
INT 21H
CODES ENDS
END START
堆栈段详解
堆栈段是一个特殊的段,在程序中可以定义它,也可以不定义。除了要生成COM型执行文件的源程序外,一个完整的源程序一般最好定义堆栈段。如果在程序中不定义堆栈段,那么,操作系统在装入该执行程序时将自动为其指定一个64K字节的堆栈段。
在程序没有定义堆栈段的情况下,在由连接程序生成执行文件时,将会产生一条如下的警告信息,但程序员可以不理会它,所生成的执行文件是可以正常运行的。
warning xxxx: no stack segment (其中:xxxx是错误号)
在源程序中,可用以下方法来定义堆栈段。
方法1:
STACK1SEGMENT
DB256 DUP(?) ;256是堆栈的长度,可根据需要进行改变
TOPLABEL WORD
STACK1ENDS
以上堆栈段的定义如图6.1所示。由于堆栈是按地址从大到小的存储单元顺序来存放内容的,所以,在堆栈存储单元说明语句之后,再说明一个栈顶别名,这样,对栈顶寄存器SP的赋值就很方便。
在源程序的代码段中,还要添加如下程序段,才能把段STACK1当作堆栈段来使用。
图6.1堆栈段定义示意图
…
ASSUMESS:STACK1;可在代码段的段指定语句中一起说明
CLI;禁止响应可屏蔽中断
MOVAX, STACK1
MOVSS, AX
MOVSP, offset TOP;给堆栈段的栈顶寄存器SP赋初值
STI;恢复响应可屏蔽中断
…
方法2:
STACK1SEGMENTSTACK;定义一个堆栈段,其段名为STACK1
DB256 DUP(?)
STACK1ENDS
上述段定义说明了该段是堆栈段,系统会自动把段寄存器SS和栈顶寄存器SP与该堆栈段之间建立相应的关系,并设置其初值,而不用在代码段对它们进行赋值。
除了以上二种方法外,还有一种更简洁的方法来定义堆栈段,有关内容请见第6.4.2节中的叙述。
源文档 <http://www.shandong-china.com/jiemitech/581.html>
伪指令dd、dup
前面对于数据的定义:db:定义字节型数据(8位);dw:定义字型数据(16位)。
dd定义dowrd(double word,双字)型数据。比如:
data segment
db 1
dw 1
dd 1
data ends
解释:
在data段总定义了3个数据:
第一个数据为01H,在data:0处,占一个字节;
第二个数据为0001H,在data:1处,占1个字(2个字节);
第三个数据为00000001H,在data:3处,占2个字(4个字节)。
用div计算data段中第一个数据除以第二个数据后的结果,商存放在第三个数据的存储单元中。
data segment
dd 100001
dw 100
dw 0
data ends
分析:data段中的第一个数据是被除数,为dword型(32位)。在做除法之前,用dx和ax进行存储。将data:0字单元中的低16位存储在ax 中,data:2字单元中的高16位存储在dx中。
mov ax, data
mov ds, ax
mov ax, data:[0] ;ds:0字单元中的低16位存储到ax中
mov dx, data:[2] ;ds:2字单元中的高16位存储到16中
div word ptr ds:[4] ;用dx:ax中的32位数据除以ds:4字单元中的数据
mov ds:[6], ax ;将商存储到ds:6字单元中
dup是一个操作符,在汇编语言中同db、dw、dd等一样,也是由编译器识别处理的符号。它是和db、 dw、dd等数据定义伪指令配合使用的,用来进行数据的重复。
db 3 dup (0):定义了3个字节,它们的值都是0,相当于db 0, 0, 0。
db 3 dup (0,1,2);定义了9个字节,它们是0,1,2,0,1,2,0,1,2,相当于:db 0,1,2,0,1,2,0,1,2。
db 3 dup ('abc', 'ABC');定义了18个字节,他们'是abcABCabcABCabcABC',相当于:db 'abcABCabcABCabcABC'。
dup的使用格式如下:
db 重复的次数 dup (重复的字节型数据)。
dw 重复的次数 dup (重复的字型数据)。
dd 重复的次数 dup (重复的双字数据)。
dup是一个十分有用的操作符,比如我们要定义一个容量为200个字节的栈段,如果不用dup,则需要大量的代码来进行定义。如果用dup的话:
stack segment
db 200 bup (0)
stack ends
源文档 <http://hi.baidu.com/%CA%AE%C6%DF%C8%D5%D4%C2/blog/item/62fa484536b3543386947326.html>
伪指令 DUP 与数组
; Test5_1.asm
.386
.model flat, stdcall
include msvcrt.inc
includelib msvcrt.lib
.data
szFmt db '%d', 0DH, 0AH, 0
;声明并初始化有五个元素的 DWORD 数组; 该数组每个元素是 4 字节
val dd 11,22,33,44,55
.code
start:
invoke crt_printf, addr szFmt, val ;11
invoke crt_printf, addr szFmt, val+4 ;22
invoke crt_printf, addr szFmt, val+8 ;33
invoke crt_printf, addr szFmt, val+12 ;44
invoke crt_printf, addr szFmt, val+16 ;55
ret
end start
上面的例子也可以这样写:
; Test5_2.asm
.386
.model flat, stdcall
include msvcrt.inc
includelib msvcrt.lib
.data
szFmt db '%d', 0DH, 0AH, 0
val dd 11
dd 22
dd 33,44,55
.code
start:
invoke crt_printf, addr szFmt, val[0] ;11
invoke crt_printf, addr szFmt, val[4*1] ;22
invoke crt_printf, addr szFmt, val[4*2] ;33
invoke crt_printf, addr szFmt, val[4*3] ;44
invoke crt_printf, addr szFmt, val[4*4] ;55
ret
end start
使用伪指令 DUP:
; Test5_3.asm
.386
.model flat, stdcall
include msvcrt.inc
includelib msvcrt.lib
.data
szFmt db '%d', 0DH, 0AH, 0
;声明有五个元素的 DWORD 数组, 并把每个元素初始化为 6
v1 dd 5 dup(6)
;声明有五个元素的 DWORD 数组, 无初始化; 对全局变量, 没有初始化的将用 0 填充
v2 dd 5 dup(?)
.data?
;声明有五个元素的 DWORD 数组
v3 dd 5 dup(?)
.code
start:
invoke crt_printf, addr szFmt, v1[0] ;6
invoke crt_printf, addr szFmt, v1[4*1] ;6
invoke crt_printf, addr szFmt, v1[4*2] ;6
invoke crt_printf, addr szFmt, v1[4*3] ;6
invoke crt_printf, addr szFmt, v1[4*4] ;6
invoke crt_printf, addr szFmt, v2[0] ;0
invoke crt_printf, addr szFmt, v2[4*1] ;0
invoke crt_printf, addr szFmt, v2[4*2] ;0
invoke crt_printf, addr szFmt, v2[4*3] ;0
invoke crt_printf, addr szFmt, v2[4*4] ;0
invoke crt_printf, addr szFmt, v3[0] ;0
invoke crt_printf, addr szFmt, v3[4*1] ;0
invoke crt_printf, addr szFmt, v3[4*2] ;0
invoke crt_printf, addr szFmt, v3[4*3] ;0
invoke crt_printf, addr szFmt, v3[4*4] ;0
ret
end start
源文档 <http://tech.ddvip.com/2010-04/1270458232149799.html>
; Test15_4.asm
.386
.model flat, stdcall
include msvcrt.inc
includelib msvcrt.lib
.data
szText db 'Hi', 0
v1 dd 4096 dup(?) ;未初始化变量在 .data 段, 生成的 exe 文件会根据大小分配内存
.code
start:
invoke crt_printf, addr szText
ret
end start
; ------------------------------------------------------
; 上面的程序的 exe 是 18944 字节
; 下面的程序的 exe 是 2560 字节
; 它们刚好相差 4096*4 个字 节
; 结论: 不需要初始化的变量应该声明在 .data? 段
; ------------------------------------------------------
; Test15_5.asm
.386
.model flat, stdcall
include msvcrt.inc
includelib msvcrt.lib
.data
szText db 'Hi', 0
.data?
v1 dd 4096 dup(?) ;未初始化变量在 .data? 段
.code
start:
invoke crt_printf, addr szText
ret
end start
继续 dup 的例子:
; Test5_6.asm
.386
.model flat, stdcall
include msvcrt.inc
includelib msvcrt.lib
.data
szFmt db '%d', 0DH, 0AH, 0
val dd 2 dup(11,22,33)
.code
start:
invoke crt_printf, addr szFmt, val[0] ;11
invoke crt_printf, addr szFmt, val[4*1] ;22
invoke crt_printf, addr szFmt, val[4*2] ;33
invoke crt_printf, addr szFmt, val[4*3] ;11
invoke crt_printf, addr szFmt, val[4*4] ;22
invoke crt_printf, addr szFmt, val[4*5] ;33
ret
end start
源文档 <http://tech.ddvip.com/2010-04/1270458232149799_2.html>
; Test5_7.asm
.386
.model flat, stdcall
include msvcrt.inc
includelib msvcrt.lib
.data
szFmt db '%d', 0DH, 0AH, 0
val dd 2 dup(3 dup(1,2))
.code
start:
invoke crt_printf, addr szFmt, val[0] ;1
invoke crt_printf, addr szFmt, val[4*1] ;2
invoke crt_printf, addr szFmt, val[4*2] ;1
invoke crt_printf, addr szFmt, val[4*3] ;2
invoke crt_printf, addr szFmt, val[4*4] ;1
invoke crt_printf, addr szFmt, val[4*5] ;2
invoke crt_printf, addr szFmt, val[4*6] ;1
invoke crt_printf, addr szFmt, val[4*7] ;2
invoke crt_printf, addr szFmt, val[4*8] ;1
invoke crt_printf, addr szFmt, val[4*9] ;2
invoke crt_printf, addr szFmt, val[4*10] ;1
invoke crt_printf, addr szFmt, val[4*11] ;2
ret
end start
按多维数组的理念, 上一个例子也可以这样访问:
; Test5_8.asm
.386
.model flat, stdcall
include msvcrt.inc
includelib msvcrt.lib
.data
szFmt db '%d', 0DH, 0AH, 0
val dd 2 dup(3 dup(1,2))
.code
start:
invoke crt_printf, addr szFmt, val[4*0][4*0] ;1
invoke crt_printf, addr szFmt, val[4*0][4*1] ;2
invoke crt_printf, addr szFmt, val[4*0][4*2] ;1
invoke crt_printf, addr szFmt, val[4*0][4*0] ;2
invoke crt_printf, addr szFmt, val[4*0][4*1] ;1
invoke crt_printf, addr szFmt, val[4*0][4*2] ;2
invoke crt_printf, addr szFmt, val[4*1][4*0] ;1
invoke crt_printf, addr szFmt, val[4*1][4*1] ;2
invoke crt_printf, addr szFmt, val[4*1][4*2] ;1
invoke crt_printf, addr szFmt, val[4*1][4*0] ;2
invoke crt_printf, addr szFmt, val[4*1][4*1] ;1
invoke crt_printf, addr szFmt, val[4*1][4*2] ;2
ret
end start
源文档 <http://tech.ddvip.com/2010-04/1270458232149799_3.html>