0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

汇编中的循环

程序员cxuan 来源:程序员cxuan 作者:程序员cxuan 2022-04-25 10:30 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

汇编系列其实也在一直更新,只不过更新的频率会挺慢的。。。由于白天一直忙于工作,空闲时间还要看书、学习各种技术栈,早上也要抽时间早期健身,晚上回家还要陪家人 + 学习,时间安排的满满当当,所以我就慢慢写,各位读者也别太着急,我其实真想再分一个自己出来。

之前的文章中介绍过 [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 ,存储字型数据,示意图如下

e596c552-c42c-11ec-bce3-dac502259ad0.png

inc bx 就是将寄存器 bx 的值加 1,此处有两条 inc 指令,所以执行完成后 bx = 1002H,此处段基址:偏移地址为 2000H:1002H。

然后下面 (第七行指令)mov [bx],ax 就是将 ax 中的数据送入到 [bx] 中,也就是 1002H 处,指令执行后,2000:1002 单元的内容为 BE,2000:1003 单元的内容为 00,存放字型数据,执行完成后的示意图如下

e5a21d3a-c42c-11ec-bce3-dac502259ad0.png

继续执行第 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 ,如下示意图所示

e5c1a7d6-c42c-11ec-bce3-dac502259ad0.png

接下来执行第 11 行指令,inc bx,执行完成后 bx = 1005H,mov [bx],al 是把 al 中的数据送入内存 2000:1005 处,指令执行完成后,2000:1005 处的单元内容为 BE,如下示意图所示

e5e455d8-c42c-11ec-bce3-dac502259ad0.png

继续执行指令,第13、14 行指令和 11 、12 行指令一样,它的意思就是将 bx 的值加1之后,将 al 的值送入到指定地址处,执行完成后的 ds = 2000H,bx = 1006H,所以 2000:1006 处的内容是 BE(al 存储的数据),示意图如下

e61467b4-c42c-11ec-bce3-dac502259ad0.png

想必大家跟完上面的流程后,应该对 [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

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    31

    文章

    5589

    浏览量

    129057
  • 汇编
    +关注

    关注

    2

    文章

    214

    浏览量

    27154

原文标题:原来汇编中的循环是这么玩儿的

文章出处:【微信号:cxuangoodjob,微信公众号:程序员cxuan】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    编写简单高效单片机汇编程序

    :按键去抖和按键事件处理可以用一个中断和简单的逻辑实现,而不是每个按键都独立编写逻辑。 2、指令优化与循环结构 在汇编循环和条件跳转往往会消耗更多指令周期,因此优化
    发表于 11-24 07:00

    内联汇编的妙用

    它数据相关,于是借助循环变量i,做累加操作,但结果还是不对。 3、内联汇编(结果正确) 一觉醒来,突然想到内联汇编,决定一试:既然编译器不能如我所愿,那可以把想要的部分先自己编译。各种架构在线编译
    发表于 10-31 06:28

    简单的内联汇编介绍

    前言1、在程序我们可以嵌入汇编直接对我们加入的硬件进行相应的操作 2、在RISC-V架构定义的CSR寄存器需要使用特殊的 CSR 指令进行访问,如果在 C/C++程序需要使用 C
    发表于 10-30 08:04

    RISC-V的工具链GCC内联汇编

    具体实现方法和步骤 在RISC-V架构定义的CSR寄存器需要使用特殊的CSR指令进行访问,如果C、C++程序需要访问CSR寄存器,只能使用内嵌汇编指令的方法。在C、C++程序嵌入
    发表于 10-30 06:59

    蜂鸟自定义指令软件讲解和内联汇编(一)

    使用“ %数字”的方式进行隐含指定。 “数字”从 0 开始,依次表示输出操作数和输入操作数。假设包含“输出操作数”列表中有 2 个操作数,“输入操作数”列表中有 2 个操作数,则汇编程序%0 表示
    发表于 10-24 10:51

    GCC内联汇编

    GCC内联汇编 在蜂鸟内核的NICE协处理器扩展demo的insn.h文件存在下面一段指令,用于定义对协处理器调用指令,demo协处理器支持三条指令:lbuf从内存load数据
    发表于 10-24 07:46

    人工智能行业如何使用for循环语句进行循环

    人工智能行业可以使用以下是关于for循环在不同编程语言中的基本用法说明: Python的for循环: 主要用于遍历序列(列表、元组、字符串等) 典型结构:for item in sequence
    的头像 发表于 09-10 12:55 392次阅读

    基础篇3:掌握Python的条件语句与循环

    在Python编程语言中,条件语句和循环是构成复杂逻辑和数据处理的基石。本篇基础教程将帮助您深入了解Python的条件语句和循环结构,让您能够更好地控制程序流程。 条件语句 条件语句允许程序根据
    发表于 07-03 16:13

    汇编语言教学中文资料

    电子发烧友网站提供《汇编语言教学中文资料.rar》资料免费下载
    发表于 06-30 15:15 7次下载

    温度(湿热)循环试验箱在锂硫电芯测试的应用

    温度(湿热)循环试验是一种环境加速老化试验方法,通过交变的高温、低温与高湿条件,模拟锂硫电芯在极端环境的热胀冷缩、湿度应力、电解液反应等多因素影响。该试验有助于提前揭示电芯结构、材料体系或工艺
    的头像 发表于 06-04 09:14 230次阅读
    温度(湿热)<b class='flag-5'>循环</b>试验箱在锂硫电芯测试<b class='flag-5'>中</b>的应用

    循环风控温装置在半导体设备高低温测试的深度应用解析

    循环风控温装置在半导体设备高低温测试能够为用户提供一个受控、恒温均匀的温控环境,同时具备直接加热、制冷、辅助加热、辅助制冷的功能,实现全量程范围内的温度准确控制。一、循环风控温装置技术参数在半导体
    的头像 发表于 04-01 16:35 663次阅读
    <b class='flag-5'>循环</b>风控温装置在半导体设备高低温测试<b class='flag-5'>中</b>的深度应用解析

    技术干货驿站 ▏深入理解C语言:嵌套循环循环控制的底层原理

    大家好!在上一节,我们学习了C语言中的基本循环语句,如for、while和do...while循环。今天,我们将进一步探讨嵌套循环循环
    的头像 发表于 02-21 18:26 1039次阅读
    技术干货驿站  ▏深入理解C语言:嵌套<b class='flag-5'>循环</b>与<b class='flag-5'>循环</b>控制的底层原理

    汽轮机热力循环分析

    汽轮机热力循环是热力工程的重要部分,以下是对其进行的分析: 一、热力循环概述 热力循环是指工质从某一状态点开始,经过一系列状态变化又回到原来这一状态点的封闭变化过程。在这个过程
    的头像 发表于 02-06 16:52 1743次阅读

    可靠性温度循环试验至少需要几个循环

    温度循环作为自然环境的模拟,可以考核产品在不同环境条件下的适应能力,常用于产品在开发阶段的型式试验、元器件的筛选试验。一、温度循环测试介绍温度循环试验,也称为热循环试验、高低温
    的头像 发表于 01-23 15:26 988次阅读
    可靠性温度<b class='flag-5'>循环</b>试验至少需要几个<b class='flag-5'>循环</b>?

    深入理解C语言:循环语句的应用与优化技巧

    在程序设计,我们常常需要重复执行某一段代码。为了提高效率和简化代码,循环语句应运而生。C语言作为一门经典的编程语言,提供了多种循环控制结构,帮助程序员高效地实现重复操作。掌握循环语句
    的头像 发表于 12-07 01:11 1065次阅读
    深入理解C语言:<b class='flag-5'>循环</b>语句的应用与优化技巧