第 6 章:包含多个段的程序
检测点 6.1
(1)下面的程序实现依次用内存 0:0~0:15 单元中的内容改写程序中的数据 , 完成程序:
(2)下面的程序实现依次用内存 0:0~0:15 单元中的内容改写程序中的数据,数据的传送用栈来进行。栈空间设置在程序内。完成程序:
参考链接
汇编语言(王爽第三版)检测点6.1 - 筑基2017 - 博客园
实验 5:编写、调试具有多个段的程序
(1)将下面的程序编译 、连接,用 Debug 加载、跟踪,然后回答问题。
① CPU 执行程序,程序返回前,data 段中的数据为多少?
答案:程序返回前,data 段的数据未发生变化,为:
② CPU 执行程序,程序返回前,cs=____、ss=____、ds=____。
答案:程序返回前,cs = 0B4A、ss=0B49、ds=0B48。(总之递减 1)
③ 设程序加载后,code 段的段地址为 X,则 data 段的段地址为____,stack 段的段地址为____。
答案:code 段地址为 X,data 段地址为 X-2,stack 段地址为 X-1。
(2)将下面的程序编译、连接,用 Debug 加载、跟踪,然后回答问题。
① CPU 执行程序,程序返回前,data 段中的数据为多少?
答案:虽然我们在 data 段和 stack 段中只定义初始化了4个字节的内存,但在汇编中,会直接分配 16 个字节的空间,不足的用 00 补全。故 data 段中数据为:
② CPU 执行程序,程序返回前,cs=____、ss=____、ds=____。
答案:程序返回前,cs = 0B4A、ss=0B49、ds=0B48。(总之递减 1)
③ 设程序加载后,code 段的段地址为 X,则 data 段的段地址为____,stack 段的段地址为____。
答案:code 段地址为 X,data 段地址为 X-2,stack 段地址为 X-1。
④ 对于如下定义的段:
如果段中的数据占 N 个字节,则程序加载后,该段实际占有的空间为____。
(3)将下面的程序编译、连接,用 Debug 加载、跟踪,然后回答问题。
① CPU 执行程序,程序返回前,data 段中的数据为多少?
答案:同(2)①:
② CPU 执行程序,程序返回前,cs=____、ss=____、ds=____。
答案:这次将 data 和 stack 段放到了 code 段后面,因此需要注意它们段地址的变化。
程序返回前,cs = 0B48、ss=0B4C、ds=0B4B。(总之递减 1)
③ 设程序加载后,code 段的段地址为 X,则 data 段的段地址为____,stack 段的段地址为____。
答案:code 段地址为 X,data 段地址为 X+3,stack 段地址为 X+4。
那么,为什么 stack 和 data 的段地址和 code 的相差是这个数?
看 cx 的值,程序加载时,我们发现 cx=0044h,其含义是:此程序所有机器码占用的空间是44h=68 字节。由于定义的 data 和 stack 都小于 16 个字节,一律按照 16 个字节分配空间,其余补 00;剩余的 68-32=36 个字节就是 code 段真正的可执行的机器码。code 段的真实大小为 (36/16+1)*16 = 48 字节,因此 data 的地址为 X+3。另外,code 段剩下的字节补 00。
(4)如果将 (1) 、 (2) 、 (3) 题中的最后一条伪指令 “end start” 改为 “end”(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明原因。
答案:都能正常运行,但只有(3)的程序可以正确执行。因为只有它的可执行代码在内存中是在最前面。
如果不指明程序入口,程序会从加载进内存的第一个单元起开始执行,前 2 题中,定义的是数据,而 CPU仍会将数据当做指令代码执行。只不过程序执行时逻辑上是错误了。
如果指明了程序入口,CPU 会直接从入口处开始执行真正的机器码,直到遇到中断指令返回。此种方式能够确保程序逻辑上的正确。因此有必要为程序指明入口。
(5)程序如下,编写 code 段中的代码,将 a 段和 b 段中的数据依次相加,将结果存到 c 段中。
1、这个题目一下子搞出 3 个数据段了。呵呵,貌似我们段寄存器不够用了。cs(代码段),ss(栈段),这二个千万别碰!那只有 ds 和 es 了。思路:将 a 和 b 段我们用一个段地址表示,存储在 ds 中;c 段我们存储在 es 中。这种方式好吗?不太好。
2、上面已经体会了,当一个数据段不足 16 个字节时,按 16 个字节分配内存空间,其余的补 0。我们发现 a、b 段都是定义了 8 个字节的数值。并且是相邻的(肯定是的),那么 a 段的地址我们使用 [bx+idata] 表示,b 段我们也使用 [bx+idata] 表示。这种方式没有把 a 段和 b 段分开。
3、最终决定:将 es 指向 c 段,ds 分开分别的指向 a 段和 b 段,这样我们在一个循环内完成所有的工作了;程序中使用了栈保存了 ds 的值;
结果分析:
1、ds 段寄存器在程序中可以存储不同的内存段的段地址,并不是唯一存储一个段地址,es 也是如此。
2、合理利用系统自动创建的栈空间,利用栈空间来保存暂存的数据。注意压栈和弹栈的顺序,确保操作的是一个数据对象。
3、在遇到多个数据段的情况下,这种方式可以利用一个段寄存器来对多个内存段寻址。
4、在实际工程中,在程序中保存的数据,都是程序的一些必须的初始化的数据,其他的数据都应保存在磁盘文件中,需要时才读入内存中。此例中的 a、b、cz 段都是其他的数据,在这里就是演示。
(6)程序如下,编写 code 段中的代码,用 push 指令将 a 段中的前 8 个字型数据,逆序存储到 b 段中。
1、理解掌握栈的原理,先进后出,从高地址向低地址发展。也就是说先压栈的数据在栈底,最后被 pop 出。
2、对于数据段,我们定义 2 个,ds 指向 a 段,ss 指向 b。ss 指向了 b 段,也就意味着 b 段是人工创建的一个栈结构了。
3、对于 push 和 pop 指令:操作的是一个栈帧或栈单元,它的操作数是一个字,在 8086CPU 中是一个字,2 个字节,这个在 a、b 段定义时我们应该发现,它们都是定义的字。如果定义的是 db 字节呢?一样的。
参考链接
汇编语言(王爽第三版)实验5 编写、调试具体多个段的程序 - 筑基2017 - 博客园
Last updated