要使用一段安全的空间,第五章中我们说0:200~0:2ff是相对安全的。可这段代码容量只有256个字节。
合法地通过操作系统取得的空间都是安全的。
程序取得所需空间的方法有两种,一是加载程序的时候程序分配,再就是程序在执行的过程中向系统申请。
对于使用多个段的问题,我们将讨论:
(1)在一个段中存放数据、代码、栈,我们先来体会一下不使用多个段时的情况;
(2)将数据、代码、栈放入不同的段中。
考虑这样一个问题,编程计算以下8个数据的和,结果存在ax寄存器中:
0123h、0456h、0789h、0abch、0defh、0fedh、0cbah、0987h
我们如何去寻找这个内存段的空间呢?(这里有代码段和数据段)
从规范的角度来讲,我们不能自己随便决定哪段空间可以使用,应该由系统来分配。我们可以在程序中,定义我们希望处理的数据,这些数据就会被编译、连接程序作为程序的一部分写到可执行文件中。当可执行文件中的程序被加载入内存时,这些数据也同时被加载入内存中。与此同时,我们要处理的数据也就自然而然地获得了存储空间。
看具体程序:
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
编译、连接这段程序后,我们看到如下:
显然,我们程序从cs:ip开始,而cs开始部分就是数据部分。明显是我们程序在代码段的dw影响了这段代码开始执行的位置(更准确的说,是我们没有定义数据段)。
那么,我们怎样让程序正确的(或说cs:ip)指向程序入口呢?如下:
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。
可执行文件中的程序执行过程如下:
完成下面的程序,利用栈,将程序中定义的数据逆序存放。
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
?
mov ax,4c00h
int 21h
code ends
end
程序思路:定义的数据存放在cs:0~f单元中,我们只要将数据依次入栈,再依次出栈就可以逆序存放了。
问题是:我们首先要有一段可当作栈的内存空间。如下:
assume cs:code
code segment
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
;用dw定义16个字型数据,在程序加载后,将取得16个字的
;内存空间,存放这16个数据。后面的程序段中将这段空间
;当作栈来使用
start: mov ax,cs
mov ss,ax
mov sp,30h ;将设置栈顶ss:sp指向cs:30
mov bx,0
mov cx,8
s: push cs:[bx]
add bx,2
loop s ;将代码段0~15单元中的8个字型数据依次入栈
mov bx,0
mov cx,8
s0: pop cs:[bx]
add bx,2
loop s0
mov ax,4c00h
int 21h
code ends
end start
自此,我们的程序段定义并且使用了,发现很麻烦。
检测点 6.1
(1)下面程序实现依次使用内存0:0~0:15单元中的内容改写程序中的呃数据,完成程序:
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
start: mov ax,0
mov ds,ax
mov bx,0
mov cx,8
s: mov ax,[bx]
mov cs:[bx],ax ;题目这段代码为空,需要自己填写
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
(2)下面的程序实现依次内存0:0~0:15单元中的内容改写程序中的数据,数据的传送用栈来进行。栈空间设置在程序内。完成程序:
assume cs:code
code segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
dw 0,0,0,0,0,0,0,0
start: mov ax,cs ;题目ax后面为__
mov ss,ax
mov sp,20h ;题目ss后面为__
mov ax,0
mov ds,ax
mov bx,0
mov cx,8
s: push [bx]
pop cs:[bx] ;题目为________
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start
在前面的内容中,我们在程序中用到了数据和栈,将数据、栈和代码都放在了一个段里面。
这样做显然有两个问题:
(1)把它们放在一个段中使程序显得混乱
(2)前面程序中处理的数据很少,用到的栈空间也很小,加上没有很长的代码,放到一个段里面没有问题。但如果数据、栈和代码需要的空间超过64KB,就不能放在一个段中。
所以,应该考虑用多个段存放数据、栈和代码。如下所示:
assume cs:code,ds:data,ss:stack
;数据段
data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,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 ;设置栈顶ss:sp指向stack:20
mov ax,data
mov ds,ax
mov bx,0 ;设置ds:bx指向data段的第一个单元
mov cx,8
s: push [bx]
add bx,2
loop s ;以上将data段中的0~15单元中的8个字型数据一次入栈
mov bx,0
mov cx,8
s0: pop [bx]
add bx,2
loop s0 ;以上依次出栈8个字型数据到data段的0~15单元中
mov ax,4c00h
int 21h
code ends
end start
程序说明:
(1)定义多个段的方法
定义一个段的方法和前面所讲的定义代码段的方法没有区别,只是对于不同的段,要有不同的段名。
(2)对段地址的引用
现在,程序中有多个段了,如何访问段中的数据呢?当然要通过地址,而地址是分为两部分,即段地址和偏移地址。如何指明要访问的数据的段地址呢?在程序中,段名就相当于一个标号,它代表了段地址。(形如:mov ax,data)
(3)“代码段”、“数据段”、“栈段”完全是我们的安排
–
(1)将下面的程序编译连接,用Debug加载、跟踪,然后回答这个问题。
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
data ends
stack segment
dw 0,0,0,0,0,0,0,0
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00h
int 21h
code ends
end start
1.CPU执行程序,程序返回前,data段的数据为多少?
2.CPU执行程序,程序返回前,cs=?、ss=?、ds=?。
3.设置程序加载后,code段的段地址为X,则data段的段地址为?,stack段的段地址为?。
code=X、data=X-20、stack=X-10。
(2)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
assume cs:code,ds:data,ss:stack
data segment
dw 0123h,0456h
data ends
stack segment
dw 0,0
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[0]
mov ax,4c00h
int 21h
code ends
end start
1.CPU执行程序,程序返回前,data段中的数据为多少?
2.CPU执行程序,程序返回前,cs=?、ss=?、ds=?。
3.设程序加载后,code段的段地址为X,则data段的段地址为?,stack段的段地址为?。
cs = X , ds = X-20, ss = X-10。
4.对于如下定义的段:
name segment
···
name ends
如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为?。
N/256取上整
(3)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
assume cs:code,ds:data,ss:stack
code segment
start: mov ax,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
push ds:[0]
push ds:[2]
pop ds:[2]
pop ds:[2]
mov ax,4c00h
int 21h
code ends
data segment
dw 0123h,0456h
data ends
stack segment
dw 0,0
stack ends
end start
1.CPU执行程序,程序返回前,data段中的数据为多少?
2.CPU执行程序,程序返回前,cs=?、ss=?、ds=?。
3.设程序加载后,code段的段地址为X,则data段的段地址为?,stack的段地址为?。
code=X , data=X+(code指令字节数/256)取上整+1 , stack = data + 1。
(4)如果将(1)(2)(3)题中的最后一条伪指令“end start”改为“end”(也就是说,不指名程序的入口),则哪个程序仍然可以正确执行?请说明原因。
第3个可以,首先是指令从何处开始,3可以正确的指向指令开始出,而其他两个不行;其次,是指令结束,3个都可以正常结束,因为只要遇到mov ax,4c00h和int 21h执行完后,程序就返回了。
(5)程序如下,编写code段中的代码,将a段和b段中的数据依次相加,将结果存到c段中。
assume cs:code
a segment
db 1,2,3,4,5,6,7,8
a ends
b segment
db 1,2,3,4,5,6,7,8
b ends
c segment
db 0,0,0,0,0,0,0,0
c ends
;题目code需要自己编写
code segment
start:
mov ax,c
mov ds,ax
mov bx,0
mov ax,a
mov es,ax
mov cx,8
s: mov dl,0
add dl,es:[bx]
add dl,es:[bx+16]
mov [bx],dl
inc bx
loop s
mov ax,4c0h
int 21h
code ends
end start
实验结果如下:
(6)程序如下,编写code段中的代码,用push指令将a段中的前8个字型数据,逆序存储到b段中。
assume cs:code
a segment
dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0fh,0ffh
a ends
b segment
dw 0,0,0,0,0,0,0,0
b ends
;题目代码段需要自己编写
code segment
start:
mov ax,b
mov ss,ax
mov sp,16
mov ax,a
mov ds,ax
mov bx,0
s: push [bx]
add bx,2
loop s
mov ax,4c00h
int 21h
code ends
end start