程序段

通常情况下,一个正常的程序至少也要有代码段、数据段和栈段。下面我们学习如何在MASM中使用伪指令定义这三个段并使用。

数据段和代码段的定义和使用

assume cs:codeseg,ds:dataseg

dataseg segment
dw 0,0,0,0
dataseg ends

codeseg segment

start:

;设置数据段寄存器DS
mov ax,dataseg
mov ds,ax

mov cx,4
mov bx,0
loop1:  mov word ptr ds:[bx],0ffffh
        add bx,2
        loop loop1

mov ax,4c00h
int 21h

codeseg ends

end start

assume和segment伪指令

该指令告诉MASM汇编器程序中定义的段。

例如assume ds:dataseg,那么后面我们就可以用segment...ends定义一个段了,而且我们还可以用mov ax,dataseg的形式获得段的起始地址。

end伪指令

end伪指令一般和一个标签配合使用,通常写为start...end start,其中start处为程序开始的地方,end为结束的地方。该信息存放在EXE的描述信息中,起始地址用于设置CS:IP寄存器,结束地址用于程序返回。

栈段的定义和使用

栈段的定义和数据段是一样的,这里就不多说了,有关栈的知识将在后续章节详细介绍。

assume cs:codeseg,ss:stackseg

stackseg segment
dw 0,0,0,0
stackseg ends

codeseg segment

start:

;设置栈段寄存器SS
mov ax,stackseg
mov ss,ax
mov sp,8

mov ax,0ffffh
push ax
pop bx

mov ax,4c00h
int 21h

codeseg ends

end start

栈段定义的一些问题

虽然王爽的《汇编语言》书上栈段是如上方式定义的,但是我发现这样定义链接时会有一个警告:

LINK:warning L4021:no stack segment

我们明明定义了栈段,但是为什么还是会报出这个警告呢?因为EXE中本来可以存放栈段的地址,而我们使用的方式是通过汇编指令指定SS寄存器,手动指定栈段地址。

stackseg segment stack
dw 0,0,0,0
stackseg ends

使用上面代码的方式定义栈段,操作系统就可以根据EXE的描述信息给SS寄存器指定一个正确的值,SP则会自动设置到栈底的前一个元素,代码可以简化为下面的形式:

assume cs:codeseg,ss:stackseg

stackseg segment stack
dw 0,0,0,0
stackseg ends

codeseg segment

start:

;不再需要手动设置栈信息了
;mov ax,stackseg
;mov ss,ax
;mov sp,8

mov ax,0ffffh
push ax
pop bx

mov ax,4c00h
int 21h

codeseg ends

end start

当然,第一种方式比较通用,万一我们使用的操作系统的可执行文件格式不支持定义栈段地址,那么我们还是得手动指定。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap