在我们一开始写的汇编源程序时,只有一个代码段,现在有一个问题是,如果程序需要用其他空间来存放数据,使用哪里呢?在总结第二提到过0:200~0:2FF是相对安全的,可这段空间容量只有256个字节,如果我们需要的空间超过256个字节该怎么办?
在操作系统的环境中,合法地通过操作系统取得的空间都是安全的,因为操作系统不会让一个程序所用的空间和其他程序以及系统自己的空间相冲突。在操作系统允许的情况下,程序可以取得任意容量的空间。
程序取得所需空间的方法有两种,一是在加载程序的时候为程序分配,再就是程序在执行的过程中向系统申请。
我们在这只讨论第一种方法。
我们若要一个程序在被加载的时候取得所需的空间,则必须要在源程序中做出说明。我们通过在源程序中定义段来进行内存空间的获取。
将数据、代码、栈放入不同的段中。
(一)在代码段中使用数据
编程计算以下8个数据的和,结果存在ax寄存器中:
0123h、0456h、0789h、0abch、0defh、0fedh、0cbah、0987h
我写的代码如下:
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
mov bx,0
mov ax,0
mov cx,8
s: add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end
测试如下:
对上述汇编代码作如下说明:
- dw的含义是定义字型数据,dw即“define word”,在这里使用dw定义了8个字型数据,它们所占的内存空间的大小为16个字节。
- 这8个数据到底放在哪呢?程序在运行的时候CS中存放的是代码段的段地址,所以可以从CS中得到它们段地址,那它们的偏移地址是多少呢?因为用dw定义的数据处于代码段的最开始,所以偏移地址为0,这8个数据就在代码段的偏移0、2、4、6、8、A、C、E处。程序运行时,它们的地址就是CS:0、CS:2、CS:4、CS:6、CS:8、CS:A、CS:C、CS:E。
- 用bx存放加2递增的偏移地址,用循环来进行累加。在循环开始前,设置(bx)=0,cs:bx指向第一个数据所在的单元。每次循环中(bx)=(bx)+2,cs:bx指向下一个数据所在的单元。
- 通过上图,我们知道DS=0B3A,在前面我已经为大家提到过,在SA:0的前256个字节为PSP区,即SA+10H:0处开始存放代码,PSP区是DOS和程序进行通讯的,具体你可以去了解DOS工作原理。所以CS的值为CS=0B4A。
- 为什么没看到程序中的指令呢?实际上用u命令从0B4A:0000查看到的也是程序中的内容,只不过不是源程序中的汇编指令所对应的机器码,而是源程序中,我们可以用d命令更加清楚地查看一下程序中前16个字节的内容,如下:
可以从0B4A:0010查看程序中要执行的机器指令,如下:
是不是和我之前写的一样?
想一想,这样写是不是很完美?我个人认为这并不是我想要的结果。为什么呢?因为程序的入口处不是我们所希望执行的指令。那如何可以在系统中直接运行呢?我们可以在源程序中指明程序的入口所在,我将代码改动如下:
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
start:mov bx,0
mov ax,0
mov cx,8
s: add ax,cs:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
我在原来的基础上加了start这个标号,通知编译器程序的入口在什么地方。那编译是如何知道哪条指令是第一条执行的指令呢?答案在于end start这条,它指明了程序的入口点,被转化为一个入口地址,存储在可执行文件的描述信息中,当加载后,设置CS:IP,这样CPU就从我们希望的地址处开始执行。
(二)在代码段中使用栈
以下都是通过代码来说明
assume cs:codesg
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
start:mov ax,cs
mov ss,ax
mov sp,30h
mov bx,0
mov cx,8
s:push cs:[bx]
add bx,2
loop s
s0:pop cs:[bx]
add bx,2
loop s0
mov ax,4c00h
int 21h
codesg ends
end start
(三)将数据、代码、栈放入不同的段
对上面代码进一步优化
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h,0789h,0abch,0defh,0cbah,0987h
data ends
stack segment
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
stack ends
code segment
start:mov ax,stack
mov ss,ax
mov sp,20h
mov ax,data
mov ds,ax
mov cx,8
s:push [bx]
add bx,2
loop s
mov bx,0
mov cx,8
s0:pop [bx]
add bx,2
loop s0
mov ax,4c00h
int 21h
code ends
end start
总结完毕!