原来汇编中的循环是这么玩儿的(汇编循环指令有哪些)
haoteby 2025-05-05 15:50 32 浏览
汇编系列其实也在一直更新,只不过更新的频率会挺慢的。。。由于白天一直忙于工作,空闲时间还要看书、学习各种技术栈,早上也要抽时间早期健身,晚上回家还要陪家人 + 学习,时间安排的满满当当,所以我就慢慢写,各位读者也别太着急,我其实真想再分一个自己出来。
之前的文章中介绍过 [0] 表示的是内存单元,它一般存储在 ds 寄存器中,偏移地址为 0 。比如下面的指令
mov ax,[0]
就是将一个内存单元的内容送入 ax,这个内存单元的长度为 2 个字节,正好存放一个字型数据,偏移地址为 0 ,段地址在 ds 中。这种寻址方式相当于是直接寻址。
比如下面代码
mov al,[0]
就是将一个内存单元的地址送入 al 中,这个内存单元的长度是 1 字节,存放字节型数据,偏移地址位 0 ,段地址在 ds 中。
所以要描述一个完整的一个内存单元,应该需要两种信息:即内存单元的地址和内存单元的长度。
比如我们要读取一个 10000H 的数据,你可能会需要下面这段代码。
mov bx,10000H
mov ds,bx
mov al,[0]
上面这三条指令就把 10000H 读取到了 al 中。
但是表示内存地址的方式不只有直接指定其内存地址,还可以用一种间接寻址的方式,比如 [bx],它表示的是一种寄存器间接寻址,也是一种偏移地址,同样的,比如我们要读取一个 10000H 的数据,使用 [bx] 这种方式的代码如下(假设 ds = 1000H)
mov bx,1
mov ax,[bx]
这样计算机就会寻找段地址为 1000H,偏移地址为 0001H 的数据放入到 ax 中。
它的中文解释就是 把 [bx] 指向的地址中的内容,送入 ax 寄存器中。
比如下面这段代码
mov ax,[bx]
它表示的就是将偏移地址为 bx 的数据,送入到 ax 中,送入的内存单元地址是 2 个字节,存放字型数据。
又比如下面这段代码
mov al,[bx]
它表示的就是将偏移地址为 bx 的数据,送入到 al 中,送入的内存单元地址是 1 个字节,存放字节型数据。
[bx] 这种间接寻址的好处就是每次偏移地址不是固定的,这为我们接下来的循环指令奠定了基础。
为了更方便的描述后面,我们后面使用 () 来表示一个寄存器或者内存单元中的内容。
这里需要注意一下,() 内的表示的元素一般有三种类型:
寄存器名,比如 (ax) 就表示 ax 中的内容,(al) 就表示 al 中的内容。段寄存器名,比如 (ds) 就表示段寄存器 ds 中的内容。内存单元的物理地址,比如 ((ds) * 16 + (bx)),一个 20 位的数据。
我们知道,寄存器存储的数据类型有两种,字型和字节型,字型数据一般用 ax 这类寄存器来存储,字节型数据一般用 ah 、al 这种寄存器来存储。
同样的,() 内的数据类型也有两种,字型和字节型。比如 (al)、(bl)、(cl) 这种表示的数据就是字节型,而 (ax)、(bx)、(cx) 表示的数据就是字型。
在了解完上述的这些知识点后,我们就可以来正式看一下 [bx] 了。
[BX]
再来啰嗦一下 [bx] 的寻址方式,比如下面代码
mov ax,[bx]
bx 中存放的数据作为一个偏移地址,这里用 EA 表示(没有其他意思,只是单纯地表示偏移地址),段地址在 ds 中,用 SA 表示(同 EA 的解释),将 SA:EA 处的数据送入 ax 中,即 (ax) = ((ds) * 16 + (bx))。
可以将内存单元送入寄存器中,也可以将寄存器的数据送入到内存单元中,如下代码所示
mov [bx],ax
就是将 ax 中的数据送入到 SA:EA 处,即 ((ds) * 16 + (bx)) = (ax)。
为了让大家加深对 [bx] 的认识,我们通过一些汇编指令来认识一下程序的执行过程,代码如下
mov ax,2000H
mov ds,ax
mov bx,1000H
mov ax,[bx]
inc bx
inc bx
mov [bx],ax
inc bx
inc bx
mov [bx],ax
inc bx
mov [bx],al
inc bx
mov [bx],al
下面我们就按照每一行指令来分析一下
首先,mov ax,2000H 就是将 2000 送入 ax 中,mov ds,ax 就是将设置段地址为 2000 H,mov bx,1000H 就是将 1000 送入 bx 中,mov ax,[bx] 就是将 2000:1000 处的地址送入到 ax 中(因为段基址为 2000,偏移地址 dx 为 1000),2000H:1000H 处的指令是 00be,所以 ax = 00BEH ,存储字型数据,示意图如下
inc bx 就是将寄存器 bx 的值加 1,此处有两条 inc 指令,所以执行完成后 bx = 1002H,此处段基址:偏移地址为 2000H:1002H。
然后下面 (第七行指令)mov [bx],ax 就是将 ax 中的数据送入到 [bx] 中,也就是 1002H 处,指令执行后,2000:1002 单元的内容为 BE,2000:1003 单元的内容为 00,存放字型数据,执行完成后的示意图如下
继续执行第 8、9 行的指令,inc bx ,执行完成后 bx = 1004H,然后执行第 10 行指令 mov [bx],ax ,指令执行前: ds = 2000H,bx = 1004H,mov [bx],ax 相当于是把 ax 中的数据送到 2000:1004 处,指令执行完成后,2000:1004 的单元内容为 BE,2000:1005 的单元内容为 00 ,如下示意图所示
接下来执行第 11 行指令,inc bx,执行完成后 bx = 1005H,mov [bx],al 是把 al 中的数据送入内存 2000:1005 处,指令执行完成后,2000:1005 处的单元内容为 BE,如下示意图所示
继续执行指令,第13、14 行指令和 11 、12 行指令一样,它的意思就是将 bx 的值加一之后,将 al 的值送入到指定地址处,执行完成后的 ds = 2000H,bx = 1006H,所以 2000:1006 处的内容是 BE(al 存储的数据),示意图如下
想必大家跟完上面的流程后,应该对 [bx] 这个间接寻址方式有了比较深刻的认识。
下面想个问题,使用汇编编程计算 2 * 2 ,并将结果存储在 ax 寄存器中。
这个思路还是比较简单的,直接将 2 放在 ax 寄存器中,然后执行 ax 的 add 操作就可以了,下面是汇编代码
assume cs:codesg
codesg segment
mov ax,2
add ax,ax
mov ax,4c00h
int 21h
codesg ends
end
上面这段代码中的计算量还比较低,但是如果要让你计算 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 呢,你难道要写 n 个 add ax,ax 吗?
assume cs:codesg
codesg segment
mov ax,2
add ax,ax
add ax,ax
add ax,ax
add ax,ax
。。。
mov ax,4c00h
int 21h
codesg ends
end
这就很繁琐啊,所以不能这么玩,那该怎么搞呢?这里就需要一种能够循环之星 add ax,ax 的指令了,这个指令就是 Loop。
Loop 指令
Loop 指令能够循环判断是否执行指定的指令,它的执行流程就相当于我们 Java 中的 for 循环。
我们先来使用 Loop 改写一下上面 n 个 2 相乘的代码,然后再讲解一下 Loop 的使用。
assume cs:codesg
codesg segment
mov ax,2
mov cx,8
s: add ax,ax
loop s
mov ax,4c00h
int 21h
codesg ends
end
可以看到,我们使用 8 个 2 相乘的代码被优化的这么简单,这就是 loop 指令的精髓所在。
其实关键代码就是三条指令,即
- mov cx,8
- s: add ax,ax
- loop s
翻译过来的意思就是将 8 放在 cx 中,然后给 add ax,ax 处设置一个标号,然后执行 s 循环。
loop 指令的格式是:loop 标号,CPU 执行 loop 指令的时候,要进行两步操作,第一步:(cx) = (cx) - 1,第二步:判断 cx 的值,不为 0 则转至标号(上面代码是 s)处继续执行指令,如果为 0 则向下执行(上面代码中乡下继续执行就是 mov ax,4c00h)。上面代码中,我们把 8 送入了 cx 中,也就是说,cx 中存储的就是执行次数。
下面我们详细介绍一下上面这段程序的执行过程,从中体会一下 cx 和 loop s 是如何配合实现循环的。
(1) 执行 cx,8 ,设置 cx = 8
(2) 执行 add ax,ax(第 1 次)
(3) 执行 loop s 将 cx 的值 - 1,此时 (cx) = 7,(cx) != 0 ,所以转至 s 处
(4) 执行 add ax,ax(第 2 次)
(5) 执行 loop s 将 cx 的值 - 1,此时 (cx) = 6,(cx) != 0 ,所以转至 s 处
(6) 执行 add ax,ax(第 3 次)
(7) 执行 loop s 将 cx 的值 - 1,此时 (cx) = 5,(cx) != 0 ,所以转至 s 处
(8) 执行 add ax,ax(第 4 次)
(9) 执行 loop s 将 cx 的值 - 1,此时 (cx) = 4,(cx) != 0 ,所以转至 s 处
(10) 执行 add ax,ax(第 5 次)
(11) 执行 loop s 将 cx 的值 - 1,此时 (cx) = 3,(cx) != 0 ,所以转至 s 处
(12) 执行 add ax,ax(第 6 次)
(13) 执行 loop s 将 cx 的值 - 1,此时 (cx) = 2,(cx) != 0 ,所以转至 s 处
(14) 执行 add ax,ax(第 7 次)
(15) 执行 loop s 将 cx 的值 - 1,此时 (cx) = 1,(cx) != 0 ,所以转至 s 处
(16) 执行 add ax,ax(第 8 次)
(15) 执行 loop s 将 cx 的值 - 1,此时 (cx) = 0,(cx) == 0 ,所以转至 s 处
(16) 执行 mov ax,4c00h(循环结束)
从上面这个过程中,我们可以总结处用 cx 和 loop 指令相配合实现循环功能的 3 点注意事项:
- 在 cx 中存放循环次数。
- loop 指令中的标号所标识的地址要在前面
- 要循环执行的程序段,要写在标号和 loop 指令的中间。
所以综上所述,使用 Loop 和 cx 相配合实现的循环功能的结构如下:
mov cx,循环次数
s:
循环执行的程序段
loop s
比如我们想用 Loop 循环计算出 123 * 456 这个值,就可以使用这种方式
assume cs:codesg
codesg segment
mov ax,0
mov cx,456
s:add ax,123
loop s
mov ax,4c00h
int 21h
codesg ends
end
如果文章对你有帮助,小伙伴们三连走起呀!
相关推荐
- DIY桌面激光雕刻机#是时候展现真正的技术了
-
激光雕刻机。这期视频我们来看一下我是如何DIY一台桌面激光雕刻机。前几天在水池子边上发现了一台旧电脑,我看这电脑上还有一些东西可以利用到,比如光驱上面拆出了步进电机和滑轨。所以本期视频我将用这些废品去...
- 100000块多米诺骨牌拼成超级马里奥,这款机器人1天就完成了
-
智东西(公众号:zhidxcom)编译|王健恩编辑|高歌智东西7月30日消息,美国工程师兼YouTube博主MarkRober创造出了一个可以自动摆放多米诺骨牌的机器人。这个机器人被命名为D...
- 这个3D打印机器人可以在30秒内打开密码锁
-
密码锁看似很安全?也许曾经是,但现在你可要当心了!这是因为一台3D打印制造的机器人就可以在半分钟内打开你的密码锁。上周四,知名黑客萨米·卡姆卡尔(SamyKamkar)在自己的网站上公布了一个称之为...
- 密码锁也不安全 这款机器人30秒即可自动打开
-
大学生和体育爱好者们要注意了,千万不要再把贵重物品存放在公共储物柜里。因为现在已经出现了一种3D打印的机器人,据说世界上各大锁商推出的大部分密码锁,它都能够在30秒之内打开。著名黑客山米·卡姆卡(Sa...
- 硬件单片机模拟器,再也不用买开发板了...
-
#头条创作挑战赛#记得2006年在凌阳科技(sunplus)工作的时候,凌阳科技开发了自己的编译器/集成开发环境(unspIDE),那个IDE除了有keil那样的编辑器、编译器、链接器、调试器、下载...
- 3D打印机分哪几部分构成?(3d打印机结构组成及系统分析)
-
3D打印机的构成根据技术类型(如FDM、SLA、SLS等)有所不同,但以最常见的FDM(熔融沉积成型)3D打印机为例,其核心组成部分可分为以下模块:1.机械结构框架提供整体支撑和稳定性,常见材质为金...
- 初学者学伺服都需要什么?石家庄诺仕通
-
#初学者学伺服都需要什么?#对于初学者学习伺服系统,需要从...
- arduino(arduino是单片机吗)
-
arduino学习笔记arduino学习笔记1-什么是arduino?...
- 自制写字机,你需要的全套资料都在这里
-
小编之前发过《用废旧光驱制作迷你绘图仪》,很多读者都成功制作了自己的绘图仪。但是该方法的缺点是gcode要在inkscape软件中生成,然后通过grbl-controller这个没有界面的程序发送画图...
- 自己动手DIY3D打印机 瞬间效果出现桌面时,大家都惊呆了!
-
3D打印机,对数码产品比较了解的朋友都知道,但是真正玩过的童鞋可能就不多了。其实3D打印机离我们并不远,随着3D打印技术越来越成熟,3D打印机的学习资料也越来越多,这让自己动手做一台桌面3D打印机也成...
- 机器人仅用24小时将十万块多米诺骨牌拼出马里奥,创下世界纪录
-
十万块多米诺骨牌倒下是个啥场面?等等,十万块?那得搭多久啊?...
- 如何制作一个机器人?(制作机器人的方法)
-
1.简单机械机器人(例如自动小车)2.智能机器人(带有人工智能或计算机视觉)3.工业机器人(用于生产自动化)4.人形机器人(类人结构,可以行走、对话)...
- CrowPi2树莓派4学习套件评测第1部分–开箱和首次启动
-
文章来源:CNXSoftware中文站2020年6月,我曾写过一篇关于深圳易科诺...
- 基于 Arduino UNO 的蓝牙汽车(arduino智能小车蓝牙控制app)
-
HC-05蓝牙模块HC-05是一款易于使用的蓝牙SPP模块,针对流畅的串行无线通信配置进行了优化。串口蓝牙模块是完全合格的蓝牙V2.0+EDR(增强数据速率)3Mbps调制,具有总2.4...
- 电机驱动设计方案带你初识机电一体化
-
在直流电机驱动电路的设计中,主要考虑以下几点:功能:电机是单向还是双向转动?需不需要调速?...