实验5 编写、调试具有多个段的程序
(1)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
1 assume cs:code, ds:data, ss:stack 2 data segment 3 dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h 4 data ends 5 6 stack segment 7 dw 0, 0, 0, 0, 0, 0, 0, 0 8 stack ends 9 10 code segment 11 start mov ax,stack 12 mov ss, ax 13 mov sp,16 14 15 mov ax, data 16 mov ds, ax 17 18 push ds:[0] 19 push ds:[2] 20 pop ds:[2] 21 pop ds:[0] 22 23 mov ax,4c00h 24 int 21h 25 26 code ends 27 end start
编译、连接生成可执行文件:
用debug进行反汇编:
执行程序,但不返回:
(由反汇编中的ip偏移地址中看出,在至mov ax,4c00指令前的ip应指到001d,是故使用g 1d执行返回前的全部指令)
观看数据:
故①CPU执行程序,程序返回前,data段中的数据 如上,为:23 01 56 04 89 07 BC 0A EF 0F BA 0C 87 09 (H)。
②CPU执行程序,程序返回前,CS= 076CH ,SS= 076BH ,DS= 076AH 。
程序加载后,如下:
code的段地址即cs的段地址,data的段地址即为ds的段地址,从图中可看出两者相差2H,stack段地址为ss的段地址,两者则相差1H;
故:③设程序加载后,CODE段的段地址为X,则DATA段的段地址为 X-2 ,STACK段的段地址为 X-1 。
(2)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
1 assume cs:code, ds:data, ss:stack 2 data segment 3 dw 0123h, 0456h 4 data ends 5 6 stack segment 7 dw 0, 0 8 stack ends 9 10 code segment 11 start: mov ax,stack 12 mov ss, ax 13 mov sp,16 14 15 mov ax, data 16 mov ds, ax 17 18 push ds:[0] 19 push ds:[2] 20 pop ds:[2] 21 pop ds:[0] 22 23 mov ax,4c00h 24 int 21h 25 26 code ends 27 end start
编译连接:
执行观看,原理与任务(1)相似:
①CPU执行程序,程序返回前,data段中的数据 为23 01 56 04 00 00 00 ......H。
②CPU执行程序,程序返回前,CS= 076CH ,SS= 076BH ,DS= 076AH 。
③设程序加载后,CODE段的段地址为X,则DATA段的段地址为 X-2 ,STACK段的段地址为 X-1 。(此题同任务(1))
④对于如下定义的段:
name segment
……
name ends
如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为 ((N+15)/16)*16 。
(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 。
在8086CPU架构上,段是以paragraph(16-byte)对齐的。程序默认以16字节为边界对齐,
所以不足16字节的部分数据也要填够16字节。“对齐”是alignment,这种填充叫做padding。16字节成一小段,称为节】
更多讲解参考博客:https://blog.csdn.net/friendbkf/article/details/48212887
(3)将下面的程序编译连接,用Debug加载、跟踪,然后回答问题。
1 assume cs:code, ds:data, ss:stack 2 3 code segment 4 start: mov ax,stack 5 mov ss, ax 6 mov sp,16 7 8 mov ax, data 9 mov ds, ax 10 11 push ds:[0] 12 push ds:[2] 13 pop ds:[2] 14 pop ds:[0] 15 16 mov ax,4c00h 17 int 21h 18 19 code ends 20 data segment 21 dw 0123h, 0456h 22 data ends 23 24 stack segment 25 dw 0,0 26 stack ends 27 end start
编译连接:
执行查看:
①CPU执行程序,程序返回前,data段中的数据 23 01 56 04 00 00 00 ....H。
②CPU执行程序,程序返回前,CS= 076AH ,SS= 076EH ,DS= 076DH 。
程序执行后:
从图中可观察到,知cs与ds相差3H,cs与ss相差4H;故:
③设程序加载后,CODE段的段地址为X,则DATA段的段地址为 X+3 ,STACK段的段地址为 X+4 。
(4)如果将(1)、(2)、(3)题中的最后一条伪指令“end start”改为“end”(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明原因。
全部删去任务(1)-(3)程序end start后的start;重新编译连接,进行测试:
ex5_1:
ex5_2:
ex5_3:
经测试知,只有任务(3)仍可继续执行!
因为程序从所分配的空间开始执行,前2个是数据段,只有从第3条开始是指令代码,是故只有任务三正确执行。
(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 segment start: ;? code ends end start
写入程序如下:
编译连接:
反汇编:
执行查看数据:
执行前c段数据:
执行后:
由图可知任务完成。
本程序,分别使用ds,es,ss分别作为a,b,c的段地址,先行把b的内存单元加入a中,再把a中数据复制到c中,执行一个循环便可成功。
(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,0eh,0fh,0ffh a ends b segment dw 8 dup(0) b ends code segment start: ;? code ends end start
写入程序:
编译连接:
反汇编:
push操作前后数据对比:
由图中最终数据可知,实验成功。
程序中把a段视为ds段,b段视为ss段。