《汇编语言(第四版)》 . 王爽著 . 清华大学出版社 . 2019
¶实验 5 编写、调试具有多个段的程序
实现功能:利用栈,将程序中定义的数据逆序存放
在代码段中使用数据和栈
1 | cs:codesg |
我们用 dw
在程序中写入了 16 个字型数据,即开辟了 32 个字节的内存空间(可以通过定义数据来取得一定容量的内存空间),在之后的程序中,我们设置 ss:sp
指向 cs:30
,把这段内存空间(cs:10 ~ cs:2F
)当作栈空间,注意 ss:sp
指向的是栈底,入栈时,栈顶从高地址向低地址方向增长
我们知道,在单任务系统中,可执行文件中的程序执行过程如下:
- 由其他的程序(Debug、command 或其他程序)将可执行文件中的程序加载入内存
- 设置
CS:IP
指向程序的第一条要执行的指令(即程序的入口),从而使程序得以运行 - 程序运行结束后,返回到加载者
我们在程序中用伪指令 end
指明程序的入口在何处,end start
即说明程序的入口在标号 start
处,通过这种方式使得 CS:IP
能够正确地指向程序的入口
在 8086 模式下,一个段的容量不能大于 64 KB,再者,将所有的数据、栈和代码都放在同一个段中使得程序显得混乱,考虑用多个段来存放数据、代码和栈
实现功能:利用栈,将程序中定义的数据逆序存放
将数据、代码、栈放入不同的段
1 | cs:code,ds:data,ss:stack |
在一个段中,数据的段地址可由段名代表,程序中对段名的引用将被编译器处理为一个表示段地址的数值,因此在编写程序时不能将其直接送入段寄存器,数据的偏移地址取决于它在段中的位置
注意,伪指令 assume
并不能使 CPU 将 cs
指向 code
、ds
指向 data
、ss
指向 stack
,CPU 到底如何处理我们定义的段中的内容,是当作指令执行,当作数据访问,还是当作栈空间,完全是由程序中具体的汇编指令和其对 CS:IP
、SS:SP
、DS
等寄存器的设置来决定的
¶实验任务(1)
将下面的程序编译、连接,用 Debug 加载、跟踪,然后回答问题
1 | cs:code, ds:data,ss:stack |
data
段的数据入栈再出栈,在顺序上也对应,因此不会改变 data
段数据的值CPU 执行程序,程序返回前,data 段中的数据为多少?
CPU 执行程序,程序返回前,cs = ____ ss = ____ ds = ____。
设程序加载后,code 段的段地址为 X, 则 data 段的段地址为 ____ ,stack 段的段地址为 ____。
data 段中的数据未改变
cs = 076EH, ss = 076DH, ds = 076CH
code 段的段地址为 X,则 data 段的段地址为 X-2, stack 段的段地址为 X-1
¶实验任务(2)
将下面的程序编译、连接,用 Debug 加载、跟踪,然后回答问题
1 | cs:code,ds:data,ss:stack |
CPU 执行程序,程序返回前,data 段中的数据为多少?
CPU 执行程序,程序返回前,cs = ____ ss = ____ ds = ____。
设程序加载后,code 段的段地址为 X, 则 data 段的段地址为 ____ ,stack 段的段地址为 ____。
对于如下定义的段:
1 | name |
如果段中的数据占 N 个字节,则程序加载后,该段实际占有的空间为 ____。
data 段中的数据未改变
cs = 076EH, ss = 076DH, ds = 076CH
code 段的段地址为 X,则 data 段的段地址为 X-2, stack 段的段地址为 X-1
修改程序,改变数据与栈的长度
用 Debug 跟踪修改后的程序的运行,观察到 data
段的起始地址为 076C:0
,stack
段的起始地址为 076E:0
,code
段的起始地址即程序第一条指令的起始地址为 0770:0
,发现虽然 data
段中只存放了 24 个字节、stack
段也只开了 20 个字节作为栈空间,但实际上,两个段都占有 32 个字节的空间
可以得出,实际占有空间为 $⌈\dfrac{N}{16}⌉ · 16$ ( ⌈…⌉ 为向上取整 )
¶实验任务(3)
将下面的程序编译、连接,用 Debug 加载、跟踪,然后回答问题
1 | cs:code,ds:data,ss:stack |
CPU 执行程序,程序返回前,data 段中的数据为多少?
CPU 执行程序,程序返回前,cs = ____ ss = ____ ds = ____。
设程序加载后,code 段的段地址为 X, 则 data 段的段地址为 ____ ,stack 段的段地址为 ____。
data 段中的数据未改变
cs = 076CH, ss = 0770H, ds = 076FH
code 段的段地址为 X,则 data 段的段地址为 X+3, stack 段的段地址为 X+4
¶实验任务(4)
如果将(1) (2) (3)中的最后一条伪指令 end start
改为 end
(也就是说,不指明程序的入口),则哪个程序仍然可以正确执行?请说明原因。
(3) 仍可以正确执行
end start
改为 end
后,cs:ip
指向程序的首地址,只有 (3) 中的程序加载后 cs:ip
指向的是代码段
¶实验任务(5)
程序如下,编写 code 段的代码,将 a 段和 b 段中的数据依次相加,将结果存到 c 段中。
1 | cs:code |
完整程序如下
1 | cs:code |
在编写程序时,我们通过前面的实验知道了如何推算一个段具体占有多少内存空间,那么当我们知道 a
段的起始地址为 a:0
时,我们就可以推出 b
段的起始地址为 a:0+16
,c
段的起始地址为 a:0+32
,从而使得在我们的程序中只需要用寄存器取一个段地址即可
注意,dw
的含义是定义字型数据,dw
即 define word
,字型数据可以直接放入寄存器中去,因为数据寄存器的大小也是一个字的大小,而 db
的含义是定义字节型数据,db
即 define byte
,字节型数据应该使用数据寄存器的高 8 位或是低 8 位进行存放
¶实验任务(6)
程序如下,编写 code 段的代码,用 push 指令将 a 段中的前 8 个字型数据,逆序存储到 b 段中。
1 | cs:code |
完整程序如下
1 | cs:code |
将 b
段视为栈空间,将 a
段中的前 8 个字型数据在循环中顺序压入栈中即可
¶汇编语言实验合集
实验 1 查看 CPU 和内存,用机器指令和汇编指令编程
实验 2 用机器指令和汇编指令编程
实验 3 编程、编译、连接、跟踪
实验 4 [bx] 和 loop 的使用
实验 5 编写、调试具有多个段的程序
实验 6 实践课程中的程序
实验 7 寻址方式在结构化数据访问中的应用
实验 8 分析一个奇怪的程序
实验 9 根据材料编程
实验 10 编写子程序
课程设计 1
实验 11 编写子程序
实验 12 编写 0 号中断的处理程序
实验 13 编写、应用中断例程
实验 14 访问 CMOS RAM
实验 15 安装新的 int9 中断例程
实验 16 编写包含多个功能子程序的中断例程
实验 17 编写包含多个功能子程序的中断例程
课程设计 2