在操作系统的环境中,合法地通过操作系统取得的空间都是安全的,因为操作系统不会让一个程序所用的空间和其它程序以及系统自己的空间相冲突,在操作系统允许的情况下,程序可以取得任意容量的空间
程序取得所需空间有两种方法,一是在加载程序时为程序分配,再就是程序在执行的过程中向系统申请,主要考虑第一种
6.1 在代码段中使用数据
考虑将下面8个数据的和的结果存在ax寄存器中:
0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
通过循环累加的方式完成时,我们需要为这些数据分配一组地址连续的内存单元,我们不能随意决定使用哪段内存空间,系统会自动分配
可以在程序中,定义我们需要处理的数据,这些数据就会被编译,连接程序作为程序的一部分写入到可执行文件中,当可执行文件中的程序被加载到内存时,这些数据也同时被加载到内存
示例1:
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
//dw的含义是定义 字型数据
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
那么这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
将程序加载进内存后,所占内存空间的前16的单元存放在源程序中用dw定义,后面的单元存放源程序中汇编指令所对应的机器指令
但执行该程序时,需将IP设置为10h,改变CS:IP使其指向程序第一条指令,因为程序的入口处不是我们希望执行的指令,需要在源程序中指明程序的入口所在
程序1:
为了指明程序的入口,在程序的第一条指令的前面加上了一个标号 start,在末尾end除了通知编译器程序结束外,还可以通知编译器程序的入口在哪里,用end指令指明了程序的入口在start处
如何知道哪一条指令是程序的第一条要执行的指令?
由可执行文件中的描述信息指明的,可执行文件由描述信息和程序组成,程序来自于源程序中的汇编指令和定义的数据,描述信息则主要是编译,连接程序对源程序中相关伪指令进行处理所得到的信息
end start,指明了程序的入口,被转为一个入口地址,存储在可执行文件的描述信息中,在程序1生成可执行文件后,这个入口地址的偏移地址为:10h,当程序被加载到内存中后,加载者从程序的可执行文件的描述信息中读到程序的入口地址,设置cs:ip,这样CPU就可以从我们希望的地址处开始执行
6.2 在代码段中使用栈
考虑用栈将0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h逆序存放进原来的为止
思路:程序运行时,定义的数据存放在cs:0-cs:f单元中,共8个字单元,依次将这8个字单元中的数据入栈,然后再依次出栈到这8个字单元中,从而实现数据的逆序存放
示例2:
定义这些数据的目的是通过它们取得一定容量的内存空间,所以dw的作用可以说用它定义数据,也可以说用它开辟内存空间
6.3 将数据,代码,栈放入不同的段
将数据,栈,代码都放到一个段里面有两个明显的问题:
1,把它们放到一个段中使程序显得混乱
2,如果数据,栈,代码需要的空间超过64kb,就不能放到同一个段中(64kb是8086模式的限制)
所以应该使用多个段来存放数据,代码和栈
对示例2分段:
说明
1,定义多个段的方法
定义一个段的方法和之前并无不同,只是对于不同的段,要有不同的段名
2,对段地址的引用
程序中有多个段,要通过地址访问段中的数据,地址由段地址和偏移地址组成,如 mov ax,data的含义就是将名称为data的段的段地址送入ax中,编译器将data处理为一个表示段地址的数值,一个段中的数据的段地址可以由段名代表,偏移地址就要看它在段中的位置,data段中 0abch 的地址就是 data:6
3,代码段,栈段,数据段 是我们的安排
(1)程序中,用将存放数据的段命名为data,存放代码的段命名为code,用作栈空间的段命令为stack,但CPU并不会执行code中的内容,处理data中的数据,将stack当作栈,命名只是为了程序便于阅读,这些名称同 start,s,s0一样,仅在源程序中存在,CPU并不知道它们
(2)在程序中使用assume cs:code,ds:data,ss:stack将cs,ds,ss分别和code,data,stack相连,CPU不会将cs指向code,ds指向data,ss指向stack,因为assume是伪指令,由编译器执行,仅在源程序中存在,CPU并不知道它,只需要知道assume用来将你定义的具有一定用途的段和相关的寄存器联系起来就可以了
(3)用end start说明了程序的入口,这个入口将被写入可执行文件的描述信息,可执行文件中的程序被加载入内存后,CPU的CS:IP被设置指向这个入口,从而开始执行程序的第一条指令
CPU将我们定义的段中的内容,当作指令执行还是当作数据访问还是当作栈空间,完全靠程序中具体的汇编指令指示和汇编对应的CS:IP,SS:IP,DS等寄存器的设置来决定的