实验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、实验任务1

使用任意一款文本编辑器,编写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

源程序编写完以后,使用masm、link对ex1.asm进行汇编、链接,得到可执行文件ex1.exe,并运行该可执行文件。该源程序的汇编、链接的命令以及运行结果的截图如下:实验2 汇编源程序编写与汇编、调试使用debug加载可执行ex1.exe后,使用d命令查看程序段前缀PSP所占的256个字节,如下图所示:实验2 汇编源程序编写与汇编、调试使用r命令查看寄存器,并结合可执行文件中寄存器CX的值,使用u命令对ex1.exe进行精确反汇编,反汇编的结果如下图所示:实验2 汇编源程序编写与汇编、调试使用g命令执行到程序退出执行之前(即源代码文件中line16之前),观察结果。(程序的结果并未输出到显示器上)实验2 汇编源程序编写与汇编、调试

 

2、实验任务2

使用任意一款文本编辑器,编写8086汇编程序ex2.asm。源代码如下:

 1 ; ex2.asm
 2 assume cs:code
 3 code segment
 4         mov ax, 0b810h
 5         mov ds, ax
 6 
 7         mov bx, 0
 8         mov ax, 101H
 9         mov cx, 4
10 s:    mov [bx], ax
11         add bx, 2
12         add ax, 101H
13         loop s
14 
15         mov ah, 4ch
16         int 21h
17 code ends
18 end

源程序编写完以后,使用masm、link对ex1.asm进行汇编、链接,得到可执行文件ex1.exe,并运行该可执行文件。该源程序的汇编、链接的命令以及运行结果的截图如下:实验2 汇编源程序编写与汇编、调试使用r命令查看寄存器,并结合可执行文件中寄存器CX的值,使用u命令对ex2.exe进行精确反汇编,反汇编的结果如下图所示:实验2 汇编源程序编写与汇编、调试灵活使用t命令/p命令、g命令,对ex2.exe进行调试。例如,先用t命令执行前2条指令,完成对DS的赋值;再用g命令进行调试,直接执行到CS:0016;此时,下一条指令即为循坏指令loop,所以使用p命令进行调试,跳过循坏体内部,直接得到循环的结果。执行过程的命令如下图:实验2 汇编源程序编写与汇编、调试最后再用t命令执行程序返回的两条指令。实验2 汇编源程序编写与汇编、调试重新调试这段源程序,并且最后用p命令执行中断指令int 21,发现执行后,显示出“Program terminated normally”,返回到debug中。执行结果如下图:实验2 汇编源程序编写与汇编、调试把ex2.asm中line9mov cx,4改成mov cx,8,保存后重新汇编、链接、运行,所得结果如下图所示:实验2 汇编源程序编写与汇编、调试

结合上述实验和观察,分析、对比ex2.asm和ex1.asm,它们实现的是否是相同的功能和效果?在具体实现上有什么不同?

由上述实验结果可知,ex2.asm与ex1.asm具有相同的功能和效果,都是向b810:0~7中写入了1 1 2 2 3 3 4 4,并在屏幕上输出4个相同的图案。不同的是ex1.asm是直接对显存地址进行赋值,而ex2.asm是通过寄存器间接赋值,并且对于多次重复的赋值操作,采用了loop用循环来实现。

 

3、实验任务3

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

assume cs:code
code segment
    
    mov ax,0b800h  ;在汇编源程序中,数据不能以字母开头,所以要在前面加0
    mov ds,ax
    
    mov bx,07b8h
    mov cx,16

s:    mov [bx],0237h
    inc bx
    inc bx
    loop s

    mov ax,4c00h
    int 21h

code ends
end

对该汇编源程序进行汇编和连接,如下图:实验2 汇编源程序编写与汇编、调试

使用cls命令清屏后,运行该源程序,运行如下图:实验2 汇编源程序编写与汇编、调试

把填充的字数据,从0237H改成0239H,再次保存后,进行汇编、连接和运行,结果如下图:实验2 汇编源程序编写与汇编、调试

把填充的字数据,从0237H改成0437H,再次保存后,进行汇编、连接和运行,结果如下图:实验2 汇编源程序编写与汇编、调试

 猜测并分析,这个字数据中高位字节里存放的是什么信息,低位字节里存放的是什么信息。

当填充的字数据为0237H时,运行结果是16个绿色的”7“;改变低位字节,把填充的字数据改成0239H后,运行结果是16个绿色的”9“,颜色没变,但数字变了。再改变高位字节,把填充的字数据改成0437H后,运行结果是16个红色的”7“,即数字没变,但颜色变了。所以猜测这个字数据的高位字节存放输出信息的颜色,低位字节存放输出信息的内容。在该猜测下,我先把填充的字数据改成0238H,运行结果如下:实验2 汇编源程序编写与汇编、调试

发现改了低位字节后,运行结果果然是改变了输出信息的内容,没改变颜色。再改变高位字节,将填充的字数据改成0638H,运行结果如下:实验2 汇编源程序编写与汇编、调试

 

4、实验任务4

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

assume cs:code
code segment
    
    mov ax,0020h
    mov ds,ax
    
    mov bx,0
    mov cx,64

s:  mov [bx],bx
    inc bx
    loop s

    mov ax,4c00h
    int 21h

code ends
end

源程序编写完成以后,进行汇编和连接,操作过程如下图:实验2 汇编源程序编写与汇编、调试

然后用debug工具进行调试,用r命令查看寄存器,并根据寄存器CX的值对该程序进行反汇编。用g命令直接执行到循环之前:实验2 汇编源程序编写与汇编、调试

再用p命令执行到循环结束。在程序退出之前,用d命令查看内存0:200~0:23F,确认是否将0~3F传送至此段内存中。结果如下图:实验2 汇编源程序编写与汇编、调试

 选做:利用栈的特性,综合使用loop,push实现以上内容。

由于8086CPU的入栈操作是从高地址到低地址单元方向,所以入栈时从所传送数据的最大值开始,即应该将3fH最先进栈。又因为8086CPU的入栈和出栈操作都是以字为单位进行的,所以在传送数据的时候,必须将相邻的两个数据一起入栈。将3f3eH放到寄存器bx中,同时进栈,则接下来应该将3d3cH入栈,所以需要将bx的低8位寄存器bl和高8位寄存器bh都减2,依此类推。

汇编源程序如下:

assume cs:code
code segment
    
    mov ax,0020h
    mov ss,ax
    mov sp,0040h
    
    mov bx,3f3eh
    mov cx,64

s: push bx sub bl,2 sub bh,2 loop s mov ax,4c00h int 21h code ends end

对上面的源程序进行汇编和连接,再用debug工具进行调试。用r命令查看寄存器,并根据寄存器CX的值,对源程序进行反汇编:实验2 汇编源程序编写与汇编、调试

直接用g命令执行到程序结束之前,再用d命令查看0:200~0:23f,确认将数据0~3F传送到此段内存区域中,查看结果如下图:实验2 汇编源程序编写与汇编、调试

 

5、实验任务5

 完成教材实验4(3)(P121)

下面的程序的功能是将“mov ax,4c00h"之前的指令复制到内存0:200处,补全程序。上机调试,跟踪运行结果。

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

提示:

(1)复制的是什么?从哪里到哪里? (2)复制的是什么?有多少个字节?你如何知道要复制的字节的数量? 该程序实现的功能是将“mov ax,4c00h”之前的指令复制到内存0:200处,即复制从第4行开始到第16行结束的指令的机器码。由已给出的代码“mov ax 0020h”和“mov es,ax”可知,应该是用段寄存器es存放目标内存空间的段地址。那么要实现程序的复制,还需要获得代码段的段地址,所以代码“mov ax,____"和"mov ds,ax"应该是将代码段的段地址赋给段寄存器ds,因为代码段的段地址在cs中,所以该空应该填”cs“。寄存器cx中应该存放循环的次数,由于一开始不知道这段代码有多少个字节,所以可以先填”0“,然后将该源程序进行汇编和连接,再用debug工具进行反汇编,得到正确的机器码的字节数,再修改cx的值,具体操作如下图: 实验2 汇编源程序编写与汇编、调试从以上的反汇编可知,该源程序有0017h个字节,所以cx的值为0017h。修改cx的值以后,重新对源程序进行汇编、连接,并用debug工具调试。 将源程序反汇编,并用g命令直接执行到中断程序之前,然后用d命令查看内存0:200中的内容,发现内存0:200中的前17h个字节中的内容已经变成了源程序的机器码。实验2 汇编源程序编写与汇编、调试实验2 汇编源程序编写与汇编、调试实验2 汇编源程序编写与汇编、调试  

6、实验任务6(选做*)

 在Linux环境下,编写、汇编、运行、调试一个32位的Intel风格的x86汇编程序。

第1步,使用vim或其他任意文本编辑器,编写一个32位的Intel风格的x86汇编程序example.asm。

 1 ; example.asm
 2 
 3 global _start
 4 
 5 section .data
 6     msg db "a simple test", 0xa
 7     len equ $ - msg
 8 
 9 section .text
10 _start:
11     mov eax, 4
12     mov ebx, 1
13     mov ecx, msg
14     mov edx, len
15     int 0x80             ; 调用linux下的int 0x80中断的4号子功能,输出字符串
16 
17     mov eax, 1
18     mov ebx, 0
19     int 0x80             ; 调用linux下的int 0x80中断的1号子功能,退出

在Linux环境下,使用vim编辑器编写以上源程序,如下图:实验2 汇编源程序编写与汇编、调试

 第2步,使用nasm,对example.asm进行汇编。

nasm -f elf32 example.asm

其中,选项-f表示指定目标文件格式。这里指定目标文件格式是elf32格式。

一开始用以上命令进行编译时,出现了错误example.asm:1:error:parser:instruction expected,后来发现是老师给的代码中用于定义全局变量的”global“打成了”glogal“,由于无脑抄代码,所以没有发现。修改以后,源程序就可以被成功编译了(上面截图的代码是修改前的,不想重新截图了)。

编译成功后,用ls命令查看目录中是否生成了目标文件example.o,编译及查看结果如下图:实验2 汇编源程序编写与汇编、调试

第3步,使用ld,用example.o进行链接。

ld -m elf_i386 example.o -o example

其中,选项-m指定仿真模式。这里指定仿真Intel 32的模式。选项-o用于指定可执行文件的名称。这里指定生成的可执行文件名是example。

链接成功以后会生成可执行文件example,链接和用ls命令查看的结果如下:实验2 汇编源程序编写与汇编、调试

注:第一次用ld进行链接时并没有成功,而是被系统提示sudo apt install binutils,后来查了一下知道ld是GNU binutils工具集下的一个重要工具,执行安装命令以后,就可以成功链接了。

第4步,执行可执行文件example。

./example

执行后,在shell命令终端查看返回值:

echo $?

执行结果和查看结果如下图:实验2 汇编源程序编写与汇编、调试

echo $?的返回值是0,对应源码文件中line18寄存器ebx的值。

将example.asm中line18行中寄存器ebx的值改成别的数值,比如7。重新汇编、链接、运行。用echo $?查看返回值,发现这次返回值为7,如下图:实验2 汇编源程序编写与汇编、调试

 

 

四、实验总结

 

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

 

上一篇:【汇编】求100以内的素数asm


下一篇:Oracle ASM磁盘组迁移指导手册