实验2 汇编源程序编写与汇编、调试

一、实验目的

 

  1. 理解并掌握汇编源程序组成与结构
  2. 掌握汇编语言源程序编写→汇编→链接→调试的工具和方法
  3. 理解汇编源程序中地址表示、段寄存器的用法
  4. 理解和掌握寄存器间接寻址方式[bx]
  5. 通过汇编指令loop的使用理解编程语言中循环的本质

 

二、实验准备

 

  1. 学习/复习第5章使用[bx]和loop实现循环的编程应用示例(教材5.5节,5.8节)
  2. 复习第3章「栈」的知识
  3. 结合第4章课件,复习完整汇编源程序编写→汇编→连接→运行→调试的方法
  4. 复习8086汇编中内存单元地址的表示,以及段寄存器DS, SS, ES, CS的用途

 

三、实验内容

  (省略,见“四、实验步骤与结论”)

 

四、实验步骤与结论

实验任务1


 ① 打开DOSBox,通过EDIT命令进入文本编辑器,编辑ex1.asm文件并保存:

 使用masm命令进行汇编:

 

使用link进行链接,得到可执行文件:

 查看文件生成情况:

 

运行ex1,看到输出的4个图案:

 

使用debug命令调试可执行文件ex1.exe

② 先用r命令查看各寄存器的值,可以发现CX的值为0031h,

说明可执行文件的机器码长度为0031h;

我们还发现CS=DS+10h,这里的10h的内容就是PSP(程序段前缀),

也就是说程序中最为核心的指令部分从CS:IP指向的内存单元开始。

 

程序加载后,ds中存放着程序所在内存区的段地址,这个内存区的偏移地址为0,

所以程序所在内存区的地址为ds:0;而这个内存区的前256个字节存放的PSP,

用来和程序通信;这个256字节之后的空间存放程序;

 

③ d命令一次默认查看128字节的数据,连续查看两次,得到256字节的数据,

  即PSP的信息:

 

④ CS=076Ah,IP=0000,CS:IP指向程序的第一条指令;

  又因为CX=0031,所以从076Ah:0到076A:0030

  都是程序的机器码,使用u命令进行精确反汇编:

 

⑤使用g命令执行到程序退出之前,可以看到结果是程序正常退出:

 

 

实验任务2


① 打开DOSBox,通过EDIT命令进入文本编辑器,编辑ex2.asm文件并保存:

使用masm命令进行汇编:

使用link进行链接,得到可执行文件:

查看文件生成情况:

运行ex2,发现显示出了符号

 

使用debug命令调试可执行文件ex2.exe

②先用r命令查看各寄存器的值,可以发现CX的值为001Ch,

 说明可执行文件的机器码长度为001Ch;我们还发现CS=DS+10h,

 这里的10h的 内容就是PSP(程序段前缀),也就是说程序中最为核心的指令

部分从CS:IP指向的内存单元开始(也就是下一条要执行的指令)。

 

③ CS=076Ah,IP=0000,

 CS:IP指向程序的第一条指令;

 又因为CX=001C,所以从076Ah:0到076A:001C

 都是程序的机器码,使用u命令进行精确反汇编:

 

④ 灵活使用t命令、p命令、g命令,对ex2.exe进行调试:

首先执行了g 0016后,076A:0016前的程序段被执行,

也就是loop指令前的程序段被执行了。

这个时候我们看到出现了一个蓝色的图案,是执行的结果。

 

下一条指令是loop指令,用p命令执行,Debug自动重复执行:

loop 000E

mov [BX],AX

add BX,2

add AX,101H

一共循环4次(mov CX,0004)。并且看到了一开始直接执行exe文件得到的结果。

最后一次t命名单步调试最后的INT中断。

 

⑤ 把ex2.asm中line9 mov cx, 4 改成mov cx, 8 :

保存后重新汇编、链接、运行并观察结果:

明显的可以看到结果图案发生了变化:在原来的4个图案之后又新增了4个图案。

而这正是因为loop 多循环了4次后,AX的值按照101H递增4次对应的图案。

 


结合上述实验和观察,分析、对比ex2.asm和ex1.asm,它们实现的是相同的功能和效果,

即把从101H开始,以101H递增的4个值存入到075A(DS的值)开始的连续的4个字节空间中

并且因为存入在了显卡的内存中,所以可以直接将值对应的图案显示在屏幕上。

(如果是修改后的ex2,则是8个

但是在具体实现上,ex1是直接寻址方式,而ex2是使用了[bx]进行间接寻址。

 

实验任务3


综合使用loop,[bx],编写完整汇编程序,实现向内存b800:07b8开始的连续16个字单元重复填充字数据0237H

① 编写汇编源程序如下:

首先将0b800h送入ds中,并将偏移地址07b8送入bx中;

之后就是利用loop实现循环,因为是连续的字单元,使用inc将bx每次递增1。

得到文件:

 

② 经过masm汇编、link链接后运行得到结果:

 

 

③ 把填充的字数据,从0237H 改成0239H,再次保存后,汇编、链接、运行,

  观察结果:

 

 

④ 把填充的字数据,从0237H 改成0437H,再次保存后,汇编、链接、运行,

  观察结果:

 

 

 

 

根据结果对比,猜测并分析:

这个字数据中高位字节里存放的是数据信息,低位字节里存放的是颜色信息。

 

实验任务4


编写完整汇编源程序,实现向内存0:200~0:23F依次传送数据0~63(3FH)。

 

① 内存0:200到0:23F是3Fh个单元,需循环64次mov操作,同时对应着数据0~63

  也是64个,所以bx初值设为0,每次递增1,

  然后将bx的值存入到偏移地址是bx的内存单元中。

  综合使用[bx]和loop,编写汇编源程序如下:

 

得到文件:

 

② 经过masm汇编、link链接之后运行ex4.exe,

 但因为此程序只完成数据传输,

 并没有相应的代码负责结果输出,故屏幕上未显示任何内容。

③ 然后通过debug命令调试,先通过r命令查看CS、IP以及CX的值用于确定程序

  代码段开始的地址以及长度,便于u命令精确反汇编,得到结果如下:

 

为了确认是否成功传送数据到指定内存单元中,

需要在loop指令执行完后,程序退出前查看指定内存单元。

所以首先通过g命令,将loop前的程序执行完;

④ 然后对loop指令,使用p命令,整体执行;

 

⑤ 现在可以使用d命令查看指定内存单元了:

可以看到成功向内存0:200~0:23F依次传送数据0~63。

 

 

需要提及的是,在做到实验任务4时,为了以后使用DOSBox更整洁,

我将创建虚拟盘的masm文件中的汇编、链接、调试用的文件全部复制到masm下的新文件夹exercise中,

同时将实验例子也在exercise文件夹下进行练习(在汇编前,先cd exercise即可)。

 

 

实验任务5


 教材P121 实验4(3)

下面的程序的功能是将“mov ax,4c00h”之前的指令复制到内存0:200处。

补全程序、上机调试、追踪运行结果。

assume cs:code
code segment
    mov ax,______
    mov ds,ax
    mov ax,0020h
    mov es,ax
    mov cx,______
s: mov al,[bx]
    mov es:[bx],al
    inc bx
    loop s
    mov ax,4c00h
    int 21h
code ends
end

这道练习,本质仍然是复制,只不过复制的是自身代码。

第一个空是要将使得内存单元的段地址变为当前将要执行指令的段地址,即CS的值。

第二个填空的关键是,如何确定复制多少字节,我们可以通过寄存器CX的值来确定,

先随便在第二个空输入一个值,进行debug,然后通过r命令得到CX为19h,

而int 21h是我们不需要的,所以要复制17h字节的数据。

 

同时,我们可以看到,使用u命令进行反汇编,

可以确定我们到mov ax,4c00h的代码长度是17h个字节,无误。

 

① 补全代码后:

② 经过masm汇编、link链接,并进行debug调试。

③ 到第一次循环仍然使用t命令单步调试,进行追踪:

 

 

 

 

④ 之后用p命令,将之后的循环执行完毕;最后用g命令,程序正常退出:

 

五、实验总结

1、结合第4章课件,复习完整汇编源程序编写→汇编→连接→运行→调试的方法

① 编写汇编源程序时,默认是十进制。对于十六进制,需手动添加H。如: mov ax, 30H。而debug工具中默认是十六进制,不要混淆。

② 使用debug调试时,调试的必须是可执行文件,并且要带扩展名。即: debug ××.exe

③ 使用debug ××.exe调试时,首次进入调试界面时,寄存器CX中存放的是可执行文件长度。

  可以通过u命令,结合CS、IP、CX的值,对  *.exe文件反汇编,得到汇编源程序。单步调试时,调试到int 21h这条时,使用p命令。
④ 对×××.asm文件进行汇编时,语句末尾是有分号的:masm  ×××.asm ;如果有错,根据出错提示信息,回到.asm文件中修改。

 

2、在汇编语言源程序中,包含两种指令:一种是汇编指令,一种是伪指令。

① 汇编指令是有对应的机器码的指令,可以被编译为机器指令,最终为CPU所执行。

② 伪指令没有对应的机器指令,最终不被CPU执行。

③ segment和ends是一对成对使用的伪指令这是在写可被编译的汇编程序时,必须要用到的一对伪指令。

  segment和ends的功能是定义一个段,segment说明一个段开始,ends说明一个段结束。一个段必须有一个名称来标识。

④ end是一个汇编程序的结束标记,编译器在编译汇编程序的过程中,如果碰到伪指令end就结束对源程序的编译。

⑤ assume是伪指令,它假设某一段寄存器和程序中的某一个segment...ends定义的相关联。

  通过assume说明这种关联,在需要的情况下,编译源程序可以将段寄存器和某一个具体的段相联系。

 

3、我复习了第5章使用[bx]和loop实现循环的编程应用示例,温习这些知识点:

① [bx]是一种寻址方式,是内存单元的间接表示

② loop指令用来实现循环,需要和寄存器cx配合使用,其格式是:loop 标号;之后CPU执行指令的过程是:

  1. (cx) ← (cx) - 1
  2. 判断cx的值是否为0。
  3. 如果(cx) ≠ 0,跳转到标号处执行;
  4. 如果(cx) = 0, 执行loop后面的其它指令。

而如果是使用debug命令进行调试的话:

  • t命令
    •   单步执行;
    •   遇loop会进入循环内部继续单步执行;
    •   遇int会进入中断程序内继续单步执行;
  • p命令
    •   单步执行;
    •   遇loop或int会当做整体执行,不进入内部单步
  • g命令
    • 执行到指定地址;或者,遇程序结束或int,则终止执行

 

posted @ 2020-10-30 11:25  Liu_Wei  阅读(881)  评论(3)    收藏  举报