汇编一日一学(2)--两个数的和(DUP,堆栈段)

 

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>

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值