实验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

要求:

  • 使用8086汇编程序编写、汇编、链接、运行、调试方法,对ex1.asm进行汇编、链接、运行,使用debug工具调试可执行文件。

  使用masm、link对ex1.asm进行汇编、链接,得到可执行文件ex1.exe,运行并观察结果。

  • 使用debug工具对程序进行调试
    • 使用debug加载可执行文件ex1.exe后,使用d命令查看程序段前缀PSP所占的256个字节。
    • 结合可执行文件中寄存器CX的值,使用u命令对ex1.exe进行精确反汇编。
    • 使用g命令执行到程序退出执行之前(即源码文件中line16之前),观察结果。

2. 实验任务2
使用任意一款文本编辑器,编写8086汇编源程序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 ends
end

要求:使用8086汇编程序编写、汇编、链接、运行、调试方法,对ex2.asm进行汇编、链接、运行,使用debug工具调试可执行文件。

  • 使用masm、link对ex2.asm进行汇编、链接,得到可执行文件ex2.exe,运行并观察结果。
  • 使用debug工具对程序进行调试。
    • 结合可执行文件中寄存器CX的值,使用u命令对ex2.exe进行精确反汇编
    • 灵活使用t命令、p命令、g命令,对ex2.exe进行调试。(不一定要单步,有些地方可以用g命令,一次执行多行汇编指令)


注意:单步调试时,对于循环指令loop, 中断指令int,使用t命令和p命令单步调试的区别。 

  • 把ex2.asm中line9  mov cx, 4  改成  mov cx, 8 ,保存后重新汇编、链接、运行并观察结果。
  • 结合上述实验和观察,分析、对比ex2.asm和ex1.asm,它们实现的是否是相同的功能和效果?在 具体实现上有什么不同?

3. 实验任务3

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

要求:

  • 编写汇编源程序
  • 给出运行结果截图

   如程序编写正确,预期结果如图所示。(运行前先使用 命令清屏,更便于观察运行结果)


  • 把填充的字数据,从0237H 改成0239H,再次保存后,汇编、链接、运行,观察结果。

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

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

4. 实验任务4
  • 编写完整汇编源程序,实现向内存0:200~0:23F依次传送数据0~63(3FH)。
    • 必做
      • 综合使用[bx]和loop,编写汇编源程序灵活使用debug的t命令、g命令、p命令调试。在程序退出前,用d命令查看 0:200~0:23F,确认是否将0~3F传送至此段内存区域。
    • 选做*
      • 利用栈的特性,综合使用loop,push实现(限定仅使用8086中已学过指令实现),编写源程序
      • 灵活使用debug的t命令、g命令、p命令调试。在程序退出前,用d命令查看 0:200~0:23F,确认是否将0~3F传送至此段内存区域。

 

Tips:

这道练习,本质上就是把一组连续的字节数据(常数),送到指定的连续的字节单元。如果利用栈实现,借助push和loop实现连续入栈操作。需要注意:

  1. 初始时ss和sp的设置
  2. 8086的入栈操作,是从高地址单元→低地址单元方向的;
  3. 8086的入栈操作,只能以字为单元。但这里是字节数据,如何灵活处理?

5. 实验任务5
 
教材实验4(3)(P121)
Tips: 这道练习,本质仍然是复制,只不过复制的是自身代码。填空的关键是,如何确定复制多少字节。

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

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

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


; example.asm
glogal _start
section .data
msg db "a simple test", 0xa len equ $ - msg
section .text _start:
    mov eax, 4
    mov ebx, 1
    mov ecx, msg
    mov edx, len
    int 0x80 ; 调用linux下的int 0x80中断的4号子功能,输出字符串
    mov eax, 1
    mov ebx, 0
    int 0x80 ; 调用linux下的int 0x80中断的1号子功能,退出

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

nasm -f elf32 example.asm
  • 选项 - f 表示指定目标文件格式。这里指定目标文件格式是elf32格式 

如汇编成功,会生成目标文件example.o。执行nasm命令后,可以使用 ls 命令查看。

如果希望将来使用gdb工具对可执行文件进行调试,则使用nasm汇编时还需要增加一个选项 -g ,目的 是向目标文件中增加符号和调试的相关信息。即:

nasm -f elf32 example.asm -g

 

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

ld -m elf_i386 example.o -o example
  • 选项-m指定仿真模式。这里指定仿真intel 32位的模式。
  • 选项-o用于指定可执行文件的名称。这里指定生成的可执行文件名是example 

如链接成功,会生成可执行文件example。

 

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

./example

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

echo $?

显示返回值0,对应源码文件中line18寄存器ebx的值。

把example.asm中line18行中寄存器ebx的值改成别的数值,比如7。重新汇编、链接、运行。再次使用 echo $? 查看返回值,观察这次返回值是什么。

 

注*:

1. 汇编指令与硬件相关,因此,指令集有x86的汇编指令集,也有MIPS汇编指令集;书写风格既有intel 风格,也有AT&T风格。linux下默认是AT&T风格的。此外,可用的工具也种类繁多。这里仅列出一个简单示例,请根据个人情况自行探索实践。

2. 使用gdb调试时,也需要掌握类似于debug下很多命令,比如list(查看代码)、b(break, 设置断点)、 r(run, 运行)、查看寄存器(info registers),等等。这里没有进一步提供使用gdb调试的方法和步骤。请自行检索相关工具文档,辅助尝试。

 

四、实验结论 

1. 实验任务1

ex1.asm源代码:

对源代码进行汇编,链接,生成可执行文件,执行结果为:

 用debug对程序的执行过程进行跟踪,用r命令查看各寄存器的设置情况,根据CX的值用u命令进行反汇编,用d命令查看程序段前缀PSP所占的256个字节:

使用g命令执行到程序退出之前:

 

 

2. 实验任务2

ex2.asm源代码:

 使用masm,link对ex2.asm进行汇编,链接,运行,调试:

 使用debug工具对程序进行调试,介乎额可执行文件中寄存器CX的值,使用u命令进行精确返回百年,使用t命令,p命令,g命令,对ex2.exe进行调试:

用g命令调试到循环位置,紧接着用p命令直接执行完循环的内容,再用t去进行单步调试,再遇到int 21时,用p命令退出该调试:

 

用g命令调试到循环位置,此时用t命令进行单步调试,不会自动执行完循环的内容,而是一步步执行:

 

 

 

 

将ex2.asm中的mov cx,4改成mov cx,8,进行汇编,链接,执行,得到的结果为:

 ex1.asm进行汇编,链接,执行的结果为:

 显示出的结果不相同,我将ex2.asm中的mov cx,8继续改回到mov cx,4,进行汇编,链接,执行得到的结果为:

 

通过对比发现,ex2.asm和ex1.asm以及ex2.asm改变前后的结果不同可能是由于循环的次数不相同,mov cx,4所表示的意思是将循环进行4次,mov cx,8是将循环进行8次,一个得出的是4个图案,另一个得出的是8个图案,同样的ex1.asm也循环了四次,因此出现的也是4个图案。

3. 实验任务3

源代码:

向内存b800:07b8开始的连续16个字单元重复填充字数据0237H:

 

向内存b800:07b8开始的连续16个字单元重复填充字数据0239H:

向内存b800:07b8开始的连续16个字单元重复填充字数据0437H:

 

猜想:字数据中高位字节存放的是颜色,低位字节存放的是内容 

通过对比发现,当高位字节改变时,运行结果的颜色进行了改变,当低位字节改变时,运行结果的内容进行了改变。

 

4. 实验任务4

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

(1)必做:综合使用[bx]和loop,编写汇编源程序

代码:

 

 对该源程序进行汇编,链接并用debug进行跟踪调试,用t命令,g命令,p命令进行调试,并用d命令查看是否将0~3F传送到了0:200~0~23F中:

 

5. 实验任务5

源代码为:

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

由于程序的起始地址由CS:IP指定,因此 mov ax,__处填写CS,CS表示的是代码的段寄存器;

第九行填写mov cx,offset s1-offset s0;

本题要求的是将mov ax,4c00h之前的代码段复制到0:200处,首先根据上述代码进行汇编,链接,并进行调试

通过精确的反汇编可以发现,mov ax,4c00这条指令在076A:0017处,mov ax,cs也就是代码段的起始地址是076a:0000,通过观察可以发现在.asm中写的mov cx,offset s1-offset s0在debug中进行调试反汇编的时候变成了mov cx,0017H,因此我们知道mov ax,4c00h之前的可执行文件长度为17h个字节,因此也可以将要填空的代码直接改为mov cx,17H

用d命令查看,发现已经mov ax, 4c00h之前的指令复制到指定内存

 

 

 

posted @ 2020-11-02 13:01  xiqingyu  阅读(360)  评论(1)    收藏  举报