当前位置: 首页 > news >正文

【汇编语言】[BX]和loop指令(一)—— 初识[BX]和loop指令

在这里插入图片描述

文章目录

  • 前言
  • 1. 概念引入
    • 1.1 [bx]和内存单元的描述
      • 1.1.1 示例1
      • 1.1.2 示例2
      • 1.1.3 示例3
      • 1.1.4 示例4
    • 1.2 loop
    • 1.3 描述性的符号:“()”
    • 1.4 约定符号idata表示常量
  • 2. [BX]
    • 2.1 示例1
    • 2.2 示例2
    • 2.3 问题
    • 2.4 问题分析与解答
  • 3. Loop指令
    • 3.1 基本用法介绍
    • 3.2 任务1:编程计算 2^2,结果存在ax中
    • 3.3 任务2:编程计算 2^3
    • 3.4 任务3:编程计算 2^12
    • 3.5 改进后的程序
      • 3.5.1 标号
      • 3.5.2 loop s
      • 3.5.3 循环指令的执行
    • 3.6 问题一及分析与解答
    • 3.7 问题二及分析与解答
  • 结语

前言

📌

汇编语言是很多相关课程(如数据结构、操作系统、微机原理)的重要基础。但仅仅从课程的角度出发就太片面了,其实学习汇编语言可以深入理解计算机底层工作原理,提升代码效率,尤其在嵌入式系统和性能优化方面有重要作用。此外,它在逆向工程和安全领域不可或缺,帮助分析软件运行机制并增强漏洞修复能力。

本专栏的汇编语言学习章节主要是依据王爽老师的《汇编语言》来写的,和书中一样为了使学习的过程容易展开,我们采用以8086CPU为中央处理器的PC机来进行学习。

1. 概念引入

1.1 [bx]和内存单元的描述

[bx]是什么呢?

和[0]有些类似,[0]表示内存单元,它的偏移地址是0。比如在下面的指令中(但是注意这个是在 Debug 中使用的方式):

1.1.1 示例1

mov ax, [0]

将一个内存单元的内容送入 ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址为0,段地址在ds中。

1.1.2 示例2

mov al, [0]

将一个内存单元的内容送入al,这个内存单元的长度为1字节(字节单元),存放一个字节,偏移地址为0,段地址在ds中。

要完整地描述一个内存单元,需要两种信息:①内存单元的地址;②内存单元的长度(类型)。

用[0]表示一个内存单元时,0表示单元的偏移地址,段地址默认在ds中,单元的长度(类型)可以由具体指令中的其他操作对象(比如说寄存器)指出。

[bx]同样也表示一个内存单元,它的偏移地址在bx中,比如下面的指令:

1.1.3 示例3

mov ax, [bx]

将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址在bx中,段地址在ds中。

1.1.4 示例4

mov al, [bx]

将一个内存单元的内容送入 al,这个内存单元的长度为1字节(字节单元),存放一个字节,偏移地址在bx中,段地址在ds中。

1.2 loop

英文单词“loop”有循环的含义,显然这个指令和循环有关。

我们在这一章的学习中,会讲解[bx]和 loop 指令的应用、意义和相关的内容。

1.3 描述性的符号:“()”

为了描述上的简洁,在以后的内容中,我们将使用一个描述性的符号“()”来表示一个寄存器或一个内存单元中的内容

比如:

  1. (ax)表示 ax 中的内容、(al)表示 al 中的内容;

  2. (20000H)表示内存20000H单元的内容(括号中的是内存单元的地址为物理地址);

  3. ((ds)*16+(bx))表示:ds 中的内容为 ADR1,bx中的内容为 ADR2,内存 ADR1*16+ADR2 单元的内容。也可以理解为:ds中的ADR1作为段地址,bx中的ADR2作为偏移地址,内存ADR1:ADR2 单元的内容。

❗注意,“()”中的元素可以有3种类型:

①寄存器名;②段寄存器名;③内存单元的物理地址(一个 20位数据)。

比如:

(ax)、(ds)、(al)、(cx)、(20000H)、((ds)*16+(bx))等是正确的用法;

(2000:0)、((ds):1000H)等是不正确的用法。




“(X)”所表示的数据有两种类型:①字节;②字。

是哪种类型由寄存器名或具体的运算决定,比如:

  • (al)、(bl)、(cl)等得到的数据为字节型

  • (ds)、(ax)、(bx)等得到的数据为字型

  • (al)=(20000H),则(20000H)得到的数据为字节型

  • (ax)=(20000H),则(20000H)得到的数据为字型

1.4 约定符号idata表示常量

我们在 Debug 中写过类似的指令:mov ax,[0],表示将 ds:0处的数据送入 ax中。

指令中,在“[…]”里用一个常量 0表示内存单元的偏移地址。以后,我们用 idata 表示常量。比如:

mov ax,[idata]:代表mov ax,[l]、mov ax,[2]、mov ax,[3]等mov bx,idata:代表mov bx,1、mov bx,2、mov bx,3等mov ds,idata:代表mov ds,1、mov ds,2等,它们都是非法指令。

2. [BX]

看一看下面指令的功能。

2.1 示例1

mov ax, [bx]

功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将SA:EA处的数据送入 ax中。即:(ax)=((ds)*16+(bx))。

2.2 示例2

mov [bx], ax

功能:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将ax中的数据送入内存SA:EA 处。即:((ds)*16+(bx))=(ax)。

2.3 问题

程序和内存中的情况如下图所示,写出程序执行后,21000H-21007H单元中的内容。

在这里插入图片描述

思考后看分析。

注意,imc bx的含义是bx中的内容加1,比如下面两条指令:

mov bx, 1
inc bx

执行后,bx=2。

2.4 问题分析与解答

(1)先看一下程序的前3条指令:

mov ax, 2000H
mov ds, ax
mov bx, 1000H

这3条指令执行后,ds=2000H,bx=1000H。

(2)接下来,第4条指令:

mov ax, [bx]

指令执行前:ds=2000H,bx=1000H,则mov ax, [bx]将把内存2000:1000处的字型数据送入ax中。该指令执行后,ax=00beH。

(3)接下来,第5、6条指令:

inc bx
inc bx

这两条指令执行前 bx=1000H,执行后bx=1002H。

(4)接下来,第7条指令:

mov [bx], ax

指令执行前:ds=2000H,bx=1002H,则mov [bx], ax将把ax中的数据送入内存2000:1002处。指令执行后,2000:1002单元的内容为BE,2000:1003单元的内容为00。

(5)接下来,第8、9条指令:

inc bx
inc bx

这两条指令执行前 bx=1002H,执行后bx=1004H。

(6)接下来,第10条指令:

mov [bx], ax

指令执行前:ds=2000H,bx=1004H,则mov [bx], ax将把ax中的数据送入内存2000:1004处。指令执行后,2000:1004单元的内容为BE,2000:1005单元的内容为00。

(7)接下来,第11条指令:

inc bx

这条指令执行前 bx=1004H,执行后bx=1005H。

(8)接下来,第12条指令:

mov [bx], al

指令执行前:ds=2000H,bx=1005H,则mov [bx], al将把al中的数据送入内存2000:1005处。指令执行后,2000:1005单元的内容为 BE。

(9)接下来,第13条指令:

inc bx

这条指令执行前 bx=1005H,执行后bx=1006H。

(10)接下来,第14条指令:

mov [bx], al

指令执行前:ds=2000H,bx=1006H,则mov [bx],al将把al中的数据送入内存 2000:1006处。指令执行后,2000:1006单元的内容为 BE。

所有程序执行后,内存中的情况如下图所示。

在这里插入图片描述

3. Loop指令

3.1 基本用法介绍

loop指令的格式是:loop 标号。

CPU执行loop指令的时候,要进行两步操作:

①(cx)=(cx)-1;

②判断cx中的值,不为零则转至标号处执行程序,如果为零则继续向下执行。

从上面的描述中,可以看到,cx中的值影响着loop指令的执行结果。通常(注意,我们说的是通常)我们用loop指令来实现循环功能cx中存放循环次数

这里讲解loop指令的功能,关于loop指令如何实现转至标号处的细节,将在后面的内容中讲解。下面我们通过一个程序来看一下loop 指令的具体应用。

3.2 任务1:编程计算 2^2,结果存在ax中

分析:设(ax)=2,可计算(ax)=(ax)*2,最后(ax)中为 2^2 的值。N*2 可用 N+N 实现,程序如下。

assume cs:codecode segmentmov ax,2add ax, axmov ax,4c00hint 2lh
code endsend

3.3 任务2:编程计算 2^3

分析:2^3=2*2*2,若设(ax)=2,可计算(ax)=(ax)*2*2,最后(ax)中为 2^3 的值。N*2可用 N+N 实现,程序如下。

assume cs:codecode segmentmov ax,2add ax, axadd ax, axmov ax,4c00hint 2lh
code endsend

3.4 任务3:编程计算 2^12

分析:2^12=2*2*2*2*2*2*2*2*2*2*2*2,若设(ax)=2,可计算(ax)=(ax)*2*2*2*2*2*2*2*2*2*2*2,最后(ax)中为 2^12 的值。N*2 可用 N+N 实现,程序如下。

assume cs:codecode segmentmov ax,2;做11次add ax, axmov ax,4c00hint 2lh
code endsend

可见,按照我们的算法,计算 2^12需要11条重复的指令 add ax,ax。我们显然不希望这样来写程序,这里,可用loop来简化我们的程序

3.5 改进后的程序

assume cs:codecode segmentmov ax,2mov cx, 11
s:  add ax, axloop smov ax,4c00hint 2lh
code endsend

下面分析一下这个程序。

3.5.1 标号

在汇编语言中,标号代表一个地址,上面的程序中有一个标号s。它实际上标识了一个地址,这个地址处有一条指令:add ax, ax。

3.5.2 loop s

CPU执行loop s的时候,要进行两步操作:

  1. (cx)=(cx)-1;

  2. 判断cx中的值,不为0则转至标号s所标识的地址处执行(这里的指令是add ax,ax),如果为零则执行下一条指令(下一条指令是 mov ax, 4c00h)。

3.5.3 循环指令的执行

以下3条指令

	mov cx, 11
s:  add ax, axloop s

执行loop s时,首先要将(cx)减1,然后若(cx)不为0,则向前转至s处执行 add ax, ax。所以,可以利用 cx 来控制 add ax, ax 的执行次数。

下面我们详细分析一下这段程序的执行过程,从中体会如何用cx和loop s相配合实现循环功能。

(1)执行 mov cx, 11,设置(cx)=11;

(2)执行 add ax, ax(第1次);

(3)执行 loop s将(cx)减1,(cx)=10,(cx)不为0,所以转至s处;

(4)执行 add ax, ax(第2 次);

(5)执行 loop s将(cx)减1,(cx)=9,(cx)不为0,所以转至s处;

(6)执行 add ax, ax(第3 次);

(7)执行 loop s将(cx)减1,(cx)=8,(cx)不为0,所以转至s处;

(8)执行 add ax, ax(第4次);

(9)执行 loop s将(cx)减1,(cx)=7,(cx)不为0,所以转至s处;

(10)执行 add ax, ax(第5次);

(11)执行loop s将(cx)减1,(cx)=6,(cx)不为0,所以转至s处;

(12)执行 add ax, ax(第6次);

(13)执行 loop s将(cx)减1,(cx)=5,(cx)不为0,所以转至s处;

(14)执行 add ax, ax(第7次);

(15)执行 loop s将(cx)减1,(cx)=4,(cx)不为0,所以转至s处;

(16)执行 add ax, ax(第8次);

(17)执行loop s将(cx)减1,(cx)=3,(cx)不为0,所以转至s处;

(18)执行 add ax, ax(第9次);

(19)执行 loop s将(cx)减1,(cx)=2,(cx)不为0,所以转至s处;

(20)执行 add ax, ax(第 10 次);

(21)执行 loop s将(cx)减1,(cx)-1,(cx)不为0,所以转至s处;

(22)执行 add ax, ax(第11次);

(23)执行loop s将(cx)减1,(cx)=0,(cx)为0,所以向下执行。(结束循环)

从上面的过程中,我们可以总结出用cx和loop指令相配合实现循环功能的3个要点:
(1)在cx中存放循环次数;
(2)loop指令中的标号所标识地址要在前面;
(3)要循环执行的程序段,要写在标号和loop 指令的中间

用cx和loop指令相配合实现循环功能的程序框架如下。

mov cx, 循环次数
s:循环执行的程序段loop s

3.6 问题一及分析与解答

编程,用加法计算123*236,结果存在ax中。思考后看分析。

分析:
可用循环完成,将123加236 次。可先设(ax)=0,然后循环做236次(ax)=(ax)+123
程序如下。
程序:

assume cs:codecode segmentmov ax, 0mov cx, 236
s:  add ax, 123loop smov ax,4c00hint 2lh
code endsend

3.7 问题二及分析与解答

改进问题一答案的程序,提高123*236的计算速度。思考后看分析。

分析:

之前的程序做了236次加法,我们可以将236加123次。可先设(ax)=0,然后循环做123 次(ax)=(ax)+236,这样可以用123次加法实现相同的功能。

结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下。

也可以点点关注,避免以后找不到我哦!

Crossoads主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力!
在这里插入图片描述


http://www.mrgr.cn/news/64581.html

相关文章:

  • 基于 Spring Boot 和 Vue 的门票销售创新系统
  • sicp每日一题[2.65]
  • Chromium Mojo(IPC)进程通信演示 c++(1)
  • PHP露营地管理平台小程序系统源码
  • 入门react-native安装react-native-router-flux路由踩坑日记
  • 【原创分享】JVM服务调优实战
  • java项目之个人博客系统的设计与实现(springboot)
  • ARIMA时间序列预测模型详细讲解+Python案例演示
  • As Simple as One and Two
  • 算法学习(七)—— 分治
  • 棉花病害识别检测数据集(猫脸码客 第232期)
  • WorkFlow源码剖析——Communicator之TCPServer(上)
  • 深潜C语言的星辰大海:剖析那些鲜见却至关重要的关键字及其在实战中的运用
  • 2024年【危险化学品生产单位安全生产管理人员】最新解析及危险化学品生产单位安全生产管理人员找解析
  • 深入探索PostGIS
  • 有问必答: EMC Unity 存储系统root drive空间告警提醒
  • Rust常用属性及应用
  • Air780EP之RC522开发板,你了解吗?
  • C#/.NET/.NET Core拾遗补漏合集(24年10月更新)
  • 2024运维学习路线图
  • python-14-函数详解(定义、参数、返回值、高级函数、偏函数、装饰器)
  • 【JAVA毕业设计】基于Vue和SpringBoot的甘肃非物质文化网站
  • java项目之微服务在线教育系统设计与实现(springcloud)
  • 服务器虚拟化:构建高效弹性IT环境的基础
  • MYSQL学习笔记
  • 在Docker中安装和配置Nginx