找回密码
 register

QQ登录

只需一步,快速开始

查看: 53|回复: 0

[汇编语言] [零基础入门学习]·25·[BX]和loop指令·在Debug中跟踪用loop实现的循环程序

[复制链接]

[汇编语言] [零基础入门学习]·25·[BX]和loop指令·在Debug中跟踪用loop实现的循环程序

[复制链接]
  • 打卡等级:热心大叔
  • 打卡总天数:91
  • 打卡月天数:14
  • 打卡总奖励:91
  • 最近打卡:2025-01-15 02:59:34
Waylee

主题

0

回帖

1万

积分

仙帝

积分
11890
Waylee 2025-1-2 15:00 | 显示全部楼层 |阅读模式 | Google Chrome | Windows 10

马上注册,查看网站隐藏内容!!

您需要 登录 才可以下载或查看,没有账号?register

×

5.3 在Debug中跟踪用loop指令实现的循环程序

考虑这样一个问题,计算ffff:0006单元的数乘以3,结果存储在dx中。

我们分析一下。

(1)运算后的结果是否会超过dx所能存储的范围?
ffff:0006单元中的数是一个字节型的数据,范围在0~255之间,则用它和3相乘结果不会大于65535,可以在dx中存放下。

(2)用循环累加来实现乘法,用哪个寄存器进行累加?
将ffff:0006单元中的数赋值给ax,用dx进行累加。先设(dx)=0,然后做3次(dx)=(dx)+(ax)。

(3)ffff:6单元是一个字节单元,ax是一个16位寄存器,数据长度不一样,如何赋值?
注意,我们说的是“赋值”,就是说,让ax中的数据的值(数据的大小)和ffff:0006单元中的数据的值(数据的大小)相等。8位数据01H和16位数据0001H的数据长度不一样,但它们的值是相等的。

那么我们如何赋值?设ffff:0006单元中的数据是XXH,若要ax中的值和ffff:0006单元中的相等,ax中的数据应为00XXH。所以,若实现ffff:0006单元向ax赋值,应该令(ax)=0,(al)=(ffff6H)

想清楚以上的3个问题之后,编写程序如下。

程序 5.3

assume cs:code
code segment
    mov ax,0ffffh
    mov ds,ax
    mov bx,6        ;以上,设置ds:bx指向ffff:6

    mov al,[bx]
    mov ah,0        ;以上,设置(al)=((ds*16)+(bx)),(ah=0)

    mov dx,0        ;累加寄存器清0

    mov cx,3        ;循环3次
s:  add dx,ax
    loop s          ;以上累加计算(bx)*3

    mov ax,4c00h
    int 21h         ;程序返回
code ends
end

注意程序中的第一条指令 mov ax,offffh。我们知道,大于9FFFh的十六进制数据A000H、A001H...C000H、c001H...FFFEH、FFFFH等,在书写的时候都是以字母开头的。而在汇编源程序中,数据不能以字母开头,所以要在前面加0。比如,9138h在汇编源程序中可以直接写为“9138h”,而A000h在汇编源程序中要写为“0A000h”。
下面我们对程序的执行过程进行跟踪。首先,将它编辑为源程序文件,文件名定位p3.asm;对其进行编译连接后生成p3.exe;然后再用Debug对p3.exe中的程序进行跟踪。

用Debug加载p3.exe后,用r命令查看寄存器中的内容,如图5.3所示。

5.3.webp

图5.3中(ds)=0B2DH,所以,程序在0B3D:0处(如果读者还不清楚这是什么,可以复习4.9节的内容)。我们看一下,(cs)=0B3DH,(IP)=0,CS:IP正指向程序的第一条指令。再用u命令看一下被Debug加载入内存的程序,如图5.4所示。
5.4.webp

可以看到,从0B3D:0000~0B3D:001A是我们的程序,0B3D:0014处是源程序中的指令loop s,只是此处loop s中的标记s已经变为一个地址0012H。如果在执行“loop 0012”时,cx减1后不为0,“loop 0012”就把IP设置为0012H,从而使CS:IP指向0B3D:0012处的add dx,ax,实现转跳。
我们开始跟踪,如图5.5所示。
5.5.webp

图5.5中,前3条指令执行后,(ds)=ffffh,(bx)=6,ds:bx指向ffff:6单元。Debug显示出当前要执行的指令“mov al,[bx]”,因为是读取内存的指令,所以Debug将要访问的内存单元中的内容也显示出来,可以看到屏幕最右边显示的“ds:0006=32”,由此,我们可以方便地知道目标单元(ffff6)中的内容是32H。

继续执行,如图5.6所示。

5.6.webp

图5.6中,这两条指令执行后,(ax)=0032h,完成了从ffff:6单元向ax的赋值。

继续,如图5.7所示

5.7.webp

图5.7中,这两条指令执行后,(dx)=0,完成对累加寄存器的初始化;(cx)=3,完成对循环计数寄存器的初始化。

下面将开始循环程序段的执行。我们继续,如图5.8所示。

5.8.webp

图5.8中,CPU执行0B3D:0012处的指令“add dx,ax”后,(IP)=0014h,CS:IP指向0B3D:0014处的指令“loop 0012”。CPU执行“loop 0012”,第一步先将(cx)减1,(cx)=2;第二步因(cx)不等于0,将IP设为0012。指令“loop 0012”执行后,(IP)=0012,CS:IP再次指向0B3D:0012处的指令“add dx,ax”,这条指令将再次得到执行。注意,“loop 0012”执行后(cx)=2,也就是说,“loop 0012”还可以进行两次循环。
接着,将重复执行“add dx,ax”和“loop 0012”,直到(cx)=0位置,如图5.9所示。
5.9.webp

注意图5.9中,最后一次执行“loop 0012”的结果。执行前(cx)=1,CPU执行“loop 0012”,第一步,(cx)=(cx)-1,(cx)=0;第二步,因为(cx)=0,所以loop指令不转跳,(IP)=0016h,CPU向下执行0B3D:0016处的指令“mov ax,4c00”。
在完成最后一次“add dx,ax”后,(dx)=96h,此时dx中为累计计算(ax)*3的最后结果。
我们继续,将程序执行完,如图5.10所示。
5.10.webp

图5.10中,执行完最后两条指令后,程序返回到Debug中。注意“int 21”要用p命令执行。
上面,我们通过对一个循环程序的跟踪,更深入一步地讲解了loop指令实现循环的原理。下面,我们将程序5.3改一下,计算ffff:0006单元的数乘以123,结果存储在dx中。
这很容易完成,只要将循环的次数改成123就可以了。程序如下。

程序 5.4

assume cs:code
code segment
    mov ax,0ffffh
    mov ds,ax
    mov bx,6        ;以上,设置ds:nx指向ffff:6

    mov al,[bx]
    mov ah,0        ;以上,设置(al)=((ds*16)+(bx)),(ah)=0

    mov dx,0        ;累加寄存器清0

    mov cx,123      ;循环123次
s:  add dx,ax
    loop s          ;以上累计计算(ax)*123

    mov ,ax,4c00h   ;程序返回
    int 21h
code ends
end

我们用Debug对这个程序的循环程序段进行跟踪,现在有这样一个问题:前面的7条指令,即标号s前的指令,已经确定在逻辑上完成正确,我们不想再一步步地跟踪了,只想跟踪循环的过程。所以希望可以一次执行完标号s前的指令。可以用一个新的(对我们来说是新的,因为以前没有用过)Debug命令g来达到目的。
下面来实际操作一下,我们用程序5.4生成最终的可执行文件“c:\masm\p4.exe”,用Debug加载p4.exe,然后看一下程序在内存中的情况,如图5.11所示。
在5.11中,循环程序段从CS:0012开始,CS:0012前面的指令,我们不想再一步步地跟着,希望能够一次执行完,然后从CS:0012处开始跟踪。可以这样来使用g命令,“g 0012”,它表示执行程序到当前代码段(段地址在CS中)的0012H。也就是说“g 0012”将使Debug从当前的CS:IP指向的指令执行,一直到(IP)=0012为止。具体情况如图5.12所示。

5.11.webp

在图5.12中,Debug执行“g 0012”后,CS:0012前的程序段被执行,从各个相关的寄存器中的值,我们可以看出执行的结果。

下面我们对循环的过程进行跟踪,如图5.13所示。

图5.13中,我们跟踪了两次循环的过程。其次,通过这两次循环过程,已经可以确定循环程序段在逻辑上是正确的。我们不想再据需一步步地观察循环的过程了,怎样让程序向下执行呢?据需像从前那样使用t命令?显然这是不可行的,因为还要进行121((cx)=79h)次循环,如果像前两次那样使用t命令,我们得使用121*2=242次t命令才能循环出来。

5.13.webp

这里的问题是,我们希望将循环一次执行完。可以使用p命令来达到目的。再次遇到loop指令时,使用p命令来执行,Debug就会自动重复执行循环中的指令,直到(cx)=0为止。具体情况如图5.14所示。
5.14.webp

图5.14中,在遇到“loop 0012”时,用p命令执行,Debug自动重复执行“loop 0012”和“add dx,ax”两条指令,直到(cx)=0。最后一次执行“loop 0012”后,(cx)=0,(IP)=0016H,当前指令为CS:0016处的“mov ax,4c00”。

当然,也可以用g命令来达到目的,可以用“g 0016”直到执行到CS:0016处。具体情况如图5.15所示。

5.15.webp

您需要登录后才可以回帖 登录 | register

本版积分规则

雪舞知识库 | 浙ICP备15015590号-1 | 萌ICP备20232229号|浙公网安备33048102000118号 |天天打卡

GMT+8, 2025-1-15 13:31 , Processed in 0.107783 second(s), 9 queries , Redis On.

Powered by XueWu Licensed

Copyright © Tencent Cloud.

快速回复 返回顶部 返回列表