第六章 包含多个段的程序
第六章 包含多个段的程序程序取得所需空间的两个方法:在加载程序的时候为程序分配、执行过程中向系统申请(动态内存申请)
6.1 在代码段中使用数据
1.伪指令dw(define word)用于字型数据,每个数据之间以逗号分隔
dd(define dword)用于定义双字数据,db(define byte)用于定义字节型数据
2. 程序的开始处偏移地址为0,dw定义的数据的地址依次递增。
*写汇编程序时,前面写的地址就靠前,后面写的地址靠后
3. 程序默认以CS:0为入口
4. 伪指令 end 标号可以设置程序的入口为某一标号
总结:在代码段使用数据的程序的架构
assume cs:code
code segment
数据
start:;程序入口
代码
code ends
end start
6.2在代码段中使用栈
注:mov 段寄存器,段寄存器 是非法指令
检测点6.1
(1)下面的程序实现依次用内存0:0~0:15单元中的内容改写程序中的数据,完成程序:
Program test-6-1
assume cs:codesg
codesg 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
codesg ends
end start
(2)下面的程序实现依次用内存0:0~0:15单元中的内容改写程序中的数据,数据的传送用栈来进行。栈空间设置在程序内。完成程序:
Program test-6-1
assume cs:codesg
codesg segment
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
dw 0,0,0,0,0,0,0,0,0,0
start: mov ax, codesg ;或mov ax, cs
mov ss,ax
mov sp, 24h ;或mov sp, 36
mov ax,0
mov ds,ax
mov bx,0
mov cx,8
s: push [bx]
pop cs:[bx] ;或 pop ss:[bx]
add bx,2
loop s
mov ax,4c00h
int 21h
codesg ends
end start
6.3将数据、代码、栈放入不同的段
1. assume指令可以这样写:assume cs:code,ds:data,ss:stack,es:extra
此时data为数据段stack为栈段,extra为附加段,分别与对应的段关联起来
2. 引用段地址:程序中段名相当于段地址,若程序的assume指令为上面的样子,则mov ax,data将数据段地址送入ax
3. 汇编源程序可以定义许多段,CPU对段中内容的处理取决于汇编代码
实验5 编写、调试具有多个段的程序
(1)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
program ex-5-1
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
①CPU执行程序,程序返回前,data段中的数据 不变 。
②CPU执行程序,程序返回前,CS= 0C88H ,SS= 0C87H ,DS= 0C86H 。
③设程序加载后,CODE段的段地址为X,则DATA段的段地址为 X-2 ,STACK段的段地址为 X-1 。
(2)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
Program ex-5-2
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
①CPU执行程序,程序返回前,data段中的数据 不变 。
②CPU执行程序,程序返回前,CS= 0C88H ,SS= 0C87H ,DS= 0C86H 。
③设程序加载后,CODE段的段地址为X,则DATA段的段地址为 X-2 ,STACK段的段地址为 X-1 。
④对于如下定义的段:
name segment
……
name ends
如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为 ((N+15)/16)*16 。
④解析:
N分为被16整除和不被16整除。
当N被16整除时: 占有的空间为(N/16)*16
当N不被16整除时: 占有的空间为(N/16+1)*16,N/16得出的是可以整除的部分,还有一个余数,余数肯定小于16,加上一个16。
程序加载后分配空间是以16个字节为单位的,也就是说如果不足16个字节的也分配16个字节。
两种情况总结成一个通用的公式:((N+15)/16)*16
(3)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
Program ex-5-3
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:[0]
mov ax,4c00h
int 21h
code ends
data segment
dw 0123h,0456h
data ends
stack segment
dw 0,0
stack ends
end start
①CPU执行程序,程序返回前,data段中的数据 不变 。
②CPU执行程序,程序返回前,CS= 0C86H ,SS= 0C8AH ,DS= 0C89H 。
③设程序加载后,CODE段的段地址为X,则DATA段的段地址为 X+3 ,STACK段的段地址为 X+4 。
(4)如果将(1)、(2)、(3)题中的最后一条伪指令“end start”改为“end”(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明原因。
答:第三条程序仍然可以正确执行,如果不指明入口位置,则程序从所分配的空间开始执行,前2个是数据段,只有从第3条开始是指令代码。
(5)程序如下,编写code段中代码,将a段和b段中的数据依次相加,将结果存到C段中。
Program ex-5-4-1
;程序一:两次循环
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 segment
start: mov ax,a
mov ds,ax
mov ax,b
mov es,ax
mov bx,0
mov cx,8
s: mov al,[bx]
add es:[bx],al
inc bx
loop s
mov ax,c
mov ds,ax
mov bx,0
mov cx,8
s0: mov al,es:[bx]
mov [bx],al
inc bx
loop s0
mov ax,4c00h
int 21h
code ends
end start
Program ex-5-4-2
;程序二:一次循环
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 segment
start: mov ax,a
mov ds,ax;ds指向a段地址
mov ax,b
mov es,ax;es指向b段地址
mov bx,0
mov cx,8
s: mov al,[bx]
add al,es:[bx]
mov dx,c
mov ds,dx;ds指向c段地址
mov [bx],al
mov ax,a
mov ds,ax;重新将ds指向a段(好像此处还能改进)
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end start
Program ex-5-4-3
;程序三:程序二的改进版
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 segment
start:
mov ax,a
mov ds,ax
mov ax,b
mov es,ax
mov ax,c
mov ss,ax
mov bx,0
mov cx,8
s: mov ax,[bx]
mov ss:[bx],ax
mov ax,es:[bx]
add ss:[bx],ax
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end start
自己的做法
Program ex-5-4-4
mov ax,a
mov ds,ax
mov ax,b
mov es,ax
mov ax,c
mov ss,ax
mov bx,0
mov cx,8
s:mov ax,ds:[bx]
add ax,es:[bx]
mov ss:[bx],ax
inc bx
loop s
mov ax,4c00h
int 21h
(6)程序如下,编写code段中代码,用PUSH指令将A段中的前8个字型数据,逆序存储到B段中。
Program ex-5-5-1
assume cs:code
a segment
dw 1,2,3,4,5,6,7,8
a ends
b segment
dw 0,0,0,0,0,0,0,0
b ends
code segment
start: mov ax,a
mov ds,ax;ds指向a段
mov ax,b
mov bx,0;ds:bx指向a段的第1个单元
mov ss,ax
mov sp,16;设置栈顶指向b:16
mov cx,8
s: push [bx]
add bx,2
loop s;将a段中0~16个单元逆次入栈
code ends
end start
自己的做法:
Program ex-5-5-2
mov ax,a
mov ds,ax
mov ax,b
mov ss,ax
mov sp,16
mov dx,0
mov cx,8
s:push ds:[dx]
add dx,2
loop s
mov ax,4c00h
int 21h
