实验
- 编写以下汇编源程序
t1.asm
并进行汇编、连接、运行、调试。
assume cs:code # 1
code segment # 2
mov ah, 2 # 3
mov dl, 3 # 4
add dl, 30h # 5
int 21h # 6
# 7
mov ah, 2 # 8
mov dl, 6 # 9
add dl, 30h # 10
int 21h # 11
# 12
mov ah, 4ch # 13
int 21h # 14
code ends # 15
end # 16
汇编、连接、运行的结果如下图所示:
可见该程序输出了
36
,并结束程序返回了当前目录。我将 # 4 的
3
和 # 9 行的6
改为了1
和1
,并汇编、连接、运行,结果如下图所示:这次程序的运行结果变成了
11
。下面用
debug
对T1.exe
调试:用
r
命令查看cx
、ds
和cs
的值cx
中存放的指令的字节数,下面用u
命令验证,如下图所示:可见从偏移地址
0000
到0015
内存中的内容是程序的汇编指令,正好是16H
个字节,和cx
中的值相同。除此之外,还可以发现
(cs) = (ds) + 10H
,而这10H
的空间存放了程序段前缀 (Program Segment Prefix (PSP)),它是 DOS 系统中用于存储程序状态的数据结构。用
e
命令查看 PSP 的头两个字节,验证是否为CD 20
,如下图所示:验证的结果是肯定的,
CD 20
对应的是int 20h
操作码,它的作用是当cs
指向 PSP 时,程序可以通过跳转到此位置来结束。对于正常情况, 应使用int 21
和函数代码4ch
。用
t
命令和p
命令单步调试,如下图所示:我在本次实验中使用的
debug32
(DOS 中的debug
也是虚拟的 8086 位环境,实际上是 32 位环境,不能运行 masm 中的 16 位debug
。又因为文件夹下的debug
与系统的环境变量debug
重名,且优先运行文件夹下的,才用了debug32
(其实是懒得换路径)) 与真正的debug
有一点区别。执行到这时输出了
1
,如下图所示:继续单步调试:
到这里又输出
1
,且程序结束。
事实上,想要输出字符,只需将所需的字符加载到 dl
中,然后在 ah
中使用函数代码 2
调用中断;想要退出,只需将返回代码 (正常退出为零,错误为非零) 加载到 al
,然后在 ah
中使用函数代码 4ch
调用中断。
- 编写以下汇编源程序
t2.asm
并进行汇编、连接、运行、调试。
mov
指令对内存单元有以下几种形式 (本表引自老师的课件 第3章 内存访问)
mov指令形式 实例 mov 内存单元, 常数 mov [1], byte ptr 3 mov 内存单元, 寄存器 mov [1], ax mov 内存单元, 段寄存器 mov [1], ds 常数需要写清楚类型,以免歧义。
assume cs:code # 1
code segment # 2
mov ax, 0b800h # 3
mov ds, ax # 4
# 5
mov bx, 0 # 6
mov cx, 0433h # 7 ; # 7 行和 # 8 行也可写作
mov [bx], cx # 8 ; mov word ptr [bx], 0433h
# 9
add bx, 2 # 10
mov cx, 0436h # 11 ; # 11 行和 # 12 行也可写作
mov [bx], cx # 12 ; mov word ptr [bx], 0436h
# 13
mov ax, 4c00h # 14
int 21h # 15
code ends # 16
end # 17
汇编、连接、运行的结果如下图所示:
右上角出现了红色的
36
现在将 # 7 行的
0433h
改为0432h
, # 11 行的0436h
改为0439h
,并汇编、连接、运行,结果如下图所示:这次变成了红色的
29
,可以确信参数的后两位是输出字符的ASCII
码值。现在将 # 7 行的
0433h
改为0333h
, # 11 行的0436h
改为0336h
,并汇编、连接、运行,结果如下图所示:右上角出现了青色的
36
,可以确定前两位与字符的颜色有关。这里我把该实验与实验 1 的任务 4 一起讨论:
我用
debug
对T2.EXE
调试,先使用g
命令跑完程序,再用d
命令查看从0b800:0000
开始的地址单元,结果如下图所示:可以发现程序中的
0436h
和0336h
倒序存储在内存中,也就是说程序中参数是按照先颜色后字符写的,而内存是先字符后颜色存储。而且0b800:0000
是显存的首地址,地址代表了在屏幕上的位置。现在再用
debug
直接在屏幕左上角输出青色36
,结果如下图所示:发现也是可行的,这样的话实验 1 的任务 4 的现象就解释的通了。
还有一点,由于这个实验使用了
ax
, 所以在退出时使用mov ax, 4c00h
将al
的值改回了0
,不然系统会报错,这与之前的解释也是一致的。
尾巴
这两个实验都是在屏幕上输出字符,前一个是调用了系统函数;而后一个是直接修改显示内存,从而达到看似输出字符的目的,是非常危险的操作。
可能是我的兴趣吧,我可能花很久的是时间来写一篇博客。我知道每个人都很忙,我自己也很忙,但我愿意为我所热爱的挤出那么点时间,那是一种放松而又享受的感觉,无论最终结果怎样,但总不会差吧。
Invictus maneo.