[Assembly Language] 实验2 汇编源程序编写与汇编、调试

Task1 编写8086汇编源程序并进行汇编、链接、调试

ex1.asm 文件的内容如下:

;ex1.asm
assume cs:code
code segment
    mov ax, 0b810h
    mov ds, ax

    mov byte ptr ds:[0], 1
    mov byte ptr ds:[1], 1
    mov byte ptr ds:[2], 2
    mov byte ptr ds:[3], 2
    mov byte ptr ds:[4], 3
    mov byte ptr ds:[5], 3
    mov byte ptr ds:[6], 4
    mov byte ptr ds:[7], 4

    mov ah, 4ch
    int 21h
code ends
end

在DOSBox中使用masm命令对ex1.asm文件进行汇编,再对生成的.obj文件使用link命令生成.exe文件,具体指令为:

  • masm ex1.asm;
  • link ex1.obj;

(指令后面加分号可以略过一些细节参数的设置)

输入ex1.exe运行,发现窗口上方出现蜜汁字符,出现的原因参考实验1中相关内容。

在debug模式下,使用d命令查看程序段前缀PSP所占的256个字节。

 

 根据寄存器CX中的值(CX=0031),得知汇编指令占32字节,使用命令-u 0 31,对exe文件进行反汇编。

 

 使用g命令执行该汇编程序,得到结果如下(与直接运行exe文件效果相同):

 

(注:这里可能会出现蜜汁字符不显示的问题。原因是把字符打到指定位置后,由于-g命令的反馈信息,界面向下滚动了3行,导致原来的字符也向上滚了3行,正好在界面外。通过查看这些地址的值,发现已经被改变了,实际上这些值与界面中原字符对应位置的显示内容有关。因此只要让界面不滚动,就能完美地在指定位置输出蜜汁字符。)

 

Task2 编写8086汇编源程序并进行汇编、链接、调试(使用loop)

ex2.asm 文件的内容如下:

; ex2.asm
assume cs:code
code segment
    mov ax, 0b810h
    mov ds, ax

    mov bx, 0
    mov ax, 101h
    mov cx, 4
s:  mov [bx], ax
    add bx, 2
    add ax, 101h
    loop s
    
    mov ah, 4ch
    int 21h
code endss
end

使用masm、link命令汇编链接,运行ex2.exe,与ex1.exe的运行效果相同。

对ex2.exe使用debug工具,输入u命令进行精确反汇编。

 loop指令的地址为0016,输入-g 16,显示循环体第一次运行结果。 之后每个步骤的显示由于界面上滚,无法显示,因此对原代码修改内存的位置做出一点改动(初始DS改成B840),重新生成ex2.exe.

交替使用 -t 和 -g 16,显示出每一步打印在屏幕上的字符(不对齐的原因 task1 中已经说了)。

排除调试时屏幕滚动刷新的原因,直接执行ex1.asm和ex2.asm所产生的exe的效果是一致的。

代码书写上,ex1.asm采用顺序结构,ex2.asm采用循环结构。后者对于开发者而言书写的效率更高,但同时也让机器执行了更多的指令,时间上并不优于前者。

 

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

编写程序 ex3.asm 如下:

assume cs:code
code segment
    mov ax, 0b800h
    mov ds, ax
    
    mov bx, 07b8h
    mov ax, 0237h
    mov cx, 16
m:  mov [bx], ax
    add bx, 2
    loop m
    
    mov ah, 4ch
    int 21h
code ends
end

使用 masm 和 link 对 ex3 进行汇编、链接,运行生成的exe文件。

分别将填充的字数据改为 0239h 和 0437h,重新汇编链接过后,运行的结果如下:

猜测字数据的高位存储的是字符的颜色,低位存储的为字符的ASCII码。

共256种颜色,其中后128种有闪烁效果。

共256种字符样式,其中后128种为扩展ASCII码。

 

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

(1)使用loop,[bx]实现

代码如下:

assume cs:code
code segment
    mov ax, 0020h
    mov ds, ax
    
    mov bx, 0h
    mov cx, 40h
m:  mov [bx], bl
    add bx, 0001h
    loop m
    
    mov ah, 4ch
    int 21h
code ends
end

运行结果如下:

 

 

Task5 补全代码并调试

该程序的功能是将 "mov ax, 4c00h" 之前的指令复制到 0:200 处,待补全代码如下:

 1 assume cs:code
 2 code segment
 3     mov ax, _____
 4     mov ds, ax
 5 
 6     mov ax, 0020h
 7     mov es, ax
 8     mov bx, 0
 9     mov cs, _____
10 s:  mov al, [bx]
11     mov es:[bx], al
12     inc bx
13     loop s
14 
15     mov ax, 4c00h
16     int 21h
17 code ends
18 end

填入代码为:

(1)mov ax, cs

(2)mov cx, 17h

填入后在 debug 模式下运行,使用 -d 命令分别查看 0:200 和 076A:0 开始的数据。

该程序的功能是把从 076A:0 开始的若干字节数据放入 0:200 开始的若干地址,写入数据的量与具体填入的空有关。

如果一开始填入 mov ax, 076A,则有18h个字节数据;填入 mov ax, cs,则有17h个字节数据。原因是,mov 指令后如果是两个寄存器占用 2 个字节,如果是一个寄存器和一个立即数占用 3 个字节。(通过观察 -u 指令后每条指令所占空间可以推断出)

得知字节数量最简单的方法是,根据 CX 的值减去最后两条指令占的 5 个字节(再填入到第二个空中)。

 

posted @ 2020-11-02 18:47  Kusunoki  阅读(189)  评论(1编辑  收藏  举报