目录

  • 一、[bx]与loop基本描述
  • 二、[BX]
  • 三、Loop指令
  • 四、在Debug中跟踪用loop指令实现的循环程序
  • 五、Debug和汇编编译器masm对指令的不同处理
  • 六、loop和[bx]的联合使用
  • 七、段前缀
  • 八、一段安全的空间
  • 九、段前缀的使用

一、[bx]与loop基本描述

[bx]也表示一个内存单元,它的偏移地址在bx中,如下指令:
mov ax, [bx]将一个内存单元中的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址在bx中,段地址在ds中

之后为了描述上的见解,我们用()来表示一个寄存器或是一个内存单元中的内容,比如(ax)表示ax中的内容,(al)表示al中的内容,(20000H)表示内存20000单元的内容

可以看看(X)的应用:

  1. ax中的内容是0010H,可以描述为(ax)= 0010H
  2. 2000:1000处的内容为0010H,可以描述为(21000H)= 0010H
  3. mov ax, [2]的功能,可以描述为:(ax)= ((ds)* 10H + 2)
  4. add ax, 2的功能:(ax)= (ax)+ 2
  5. push ax的功能:(sp)= (sp)- 2,((ss)*10H+(SP))

(al)、(bl)等所得到的数据为字节型,(ds)、(ax)等得到的数据是字型

之后用idata表示常量

mov ax, [idata]代表:mov ax, [1]、mov ax, [2]、mov ax, [3]


二、[BX]

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

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

inc bx的含义是bx中的内容加1mov bx, 1
inc bx
执行后bx = 2

分析:

  1. 先看程序的前三条指令:
mov ax, 2000H
mov ds, ax
mov bx, 1000H

结束后,ds = 2000H,bx = 1000H

  1. 接下来,第4条指令:
mov ax, [bx]

将内存2000:1000处的字型数据送入ax中,执行后ax = 00beH

  1. 接下来,第5、6条指令
inc bx
inc bx

执行前bx = 1000H,执行后,bx = 1002H

  1. 接下来,第7条指令
mov [bx], ax

执行后

  1. 接下来,第8、9条指令
inc bx
inc bx

执行结束,bx = 1004H

  1. 接下来,第10条指令
mov [bx], ax

  1. 接下来,第11条指令
inc bx

此时bx = 1005H

  1. 接下来,第12条指令
mov [bx], al

al中的数据送入
接下来几条指令同理,最终结果如图所示


三、Loop指令

loop指令的格式是:loop 标号,cpu执行到loop指令的时候,要进行两步操作:

  1. (cx)= (cx)- 1;
  2. 判断cx中的值,不为0则跳转至标号处执行程序,为0则向下执行

可以看出,cx中的值影响着loop指令的执行结果,通常用loop指令来执行循环功能,cx中存放循环次数,下面通过一个具体的程序来看一下loop指令的具体应用

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 21H
code ends
end

2. 计算2^3,结果存在ax中

分析: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 21H
code ends
end

3. 计算2^12,结果存在ax中

分析:2 ^ 12 = 2 * 2 * 2 * 2… * 2, 设(ax)= 2,可以计算(ax)= (ax)* 2 * 2 * … * 2,最后(ax)中的结果为2^12的值,N*2可用N + N来实现

assume cs:codecode segmentmov ax, 2; 做11次 add ax, axmov ax, 4c00Hint 21H
code ends
end

显然是有11条重复的指令add ax,ax。我们显然不希望这样子来编写程序,我们可以用loop来简化我们的程序

assume cs:code
code segmentmov ax, 2mov cx, 11
s:  add ax, axloop smov ax, 4c00hint 21hcode ends
end

分析:

  1. 标号
    在汇编语言中,标号代表一个地址,程序中有一个标号s,他标示了一个地址,这个地址处有一条指令:add ax, ax

  2. loop s
    CPU在执行loop s的时候,需要进行两步操作
    (a)(cx)= (cx)- 1;
    (b)判断cx中的值,不为0则转至标号s所标示的地址处执行,如果为0执行下一条指令(mov ax,4c00h)

  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指令相配合实现循环的功能框架如下:

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

编程:用加法计算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 21h
code ends
end

改进:上述程序循环了236次加法,我们可以将236加123次,这样子效率就提高了许多


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

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

  1. 运算后的结果是否会超出dx所能存储的范围?

ffff:0006单元中的数是一个字节型的数据,范围在0 ~ 255之间,则用它和3相乘的结果不会大于65535,可以在dx中存放下

  1. 用循环累加来实现乘法,用哪一个寄存器来进行累加?

将ffff:0006单元中的数赋值给ax,用dx进行累加。先设(dx)= 0,然后做3次dx = (dx)+ (ax)

  1. ffff:6单元是一个字节单元,ax是一个16位寄存器,数据的长度不一样,如何赋值?

ffff:6是一个字节单元,单元中的数据为XXH,若要让ax中的值和ffff:6单元中的值相等,则应当让ax中的数据为00XXH,所以若要实现ffff:0006单元向ax赋值,应该令(ah)= 0,(al)= (ffff6H)

程序如下

assume cs:code
code segmentmov ax, 0ffffh mov ds, axmov bx, 6 ;设置ds:bx指向ffff:6mov al, [bx]mov ah, 0 ; 设置(al)= ((ds*16)+(bx))mov dx, 0mov cx, 3 ; 循环3次s:  add dx, axloop smov ax, 4c00hint 21hcode ends
end

这里程序的第一条指令mov ax, 0ffffh 是因为在汇编源程序中,数据不能以字母开头,所以要在前面加0
接下来我们对程序的执行过程进行跟踪:

这里我们是要debug 它的exe程序

这里(ds)= 075A,所以程序在076A:0处。(cs)= 076A,(IP)= 0,CS:IP指向程序的第一条指令,再用u命令查看被Debug加载入内存的程序,如图所示:

接下来我们开始跟踪:

前三条指令执行后,(ds)= FFFFH,(bx)= 6,ds:bx指向ffff:6单元。
最后一个-t,表明当前要读取的指令是mov al, [bx],因为是读取内存的指令,所以debug将要访问的内存单元中的内容也显示出来,可以看到屏幕最右边显示的是"ds:0006 = 32"由此我们可以知道此时目标单元(ffff6)的内容是31h


执行后,(ax) = 0031h,完成了赋值

…接着-t指令,就可以执行完所有

拓展:我们将单元中的数乘以123,结果存储在dx中
我们需要将循环改为123次就可以

assume cs:code
code segmentmov ax, 0ffffh mov ds, axmov bx, 6 ;设置ds:bx指向ffff:6mov al, [bx]mov ah, 0 ; 设置(al)= ((ds*16)+(bx))mov dx, 0mov cx, 123 ; 循环123次s:  add dx, axloop smov ax, 4c00hint 21hcode ends
end

我们在这里不想再一步一步的进行跟踪了,只想跟踪循环过程,希望可以一次执行标号s前的指令,可以用一个新指令:g命令达到目的。


我们想让程序从CS:0012处开始跟踪,我们就可以使用g命令,执行g 0012后,CS:0012前的程序段被指向


如果我们想让循环一次执行完,可以使用p命令达到目的,再次遇到loop指令的时候,使用p命令来执行,debug就将自动重复执行循环中的指令,直到(cx)= 0为止。

也可以使用g命令跳转至mov ax, 4c00h


五、Debug和汇编编译器masm对指令的不同处理

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

但是在汇编源程序中,指令mov ax, [0]会被编译器当作指令mov ax, 0处理

下面通过具体例子来看Debug和汇编编译器masm对这类指令的不同处理:

将内存2000:0、2000:1、2000:2、2000:3单元中的数据送入al,bl,cl,dl中

(1)在Debug中编程实现:

(2)将汇编源程序存储为.asm,用masm和link生成.exe,用Debug加载.exe

可以看到:Debug将[idata]看为是一个内存单元,idata是偏移地址,而编译器直接将[idata]视为idata
因此mov al, [0]的含义是(al)= 0,将常量0送给al,即al = 0(与mov al, 0含义相同)

总结:

  1. 在汇编源程序中,如果指令访问一个内存单元,则在指令中必须用[…]来表示一个内存单元,如果在[]里用一个常量idata直接给出内存单元的偏移地址,就要在[]的前面显示的给出段地址所在的段寄存器
    比如:mov al, ds:[0](含义是(al)=((ds)*16 + 0)将内存单元中的数据送入al)
    如果没有在[]前面显示给出段地址所在的段寄存器,比如
    mov al, [0]编译器就将他视为mov al, 0

  2. 如果在[]里面用寄存器,比如bx,则是间接给出内存单元的偏移地址,则段地址默认在ds中,当然也可以显示给出段地址所在的段寄存器


六、loop和[bx]的联合使用

计算ffff:0 ~ ffff:b单元中的数据和,结果存储在dx中
分析:

  1. 运算后的结果是否会超出dx所能存储的范围?

ffff:0 ~ ffff:b单元中的数是一个字节型的数据,范围在0 ~ 255之间,12个数相加的结果不会大于65535,可以在dx中存放下

  1. 用循环累加来实现乘法,用哪一个寄存器来进行累加?

不行,因为ffff:0 ~ ffff:b中的数据是8位的,不能直接加到16位寄存器dx

  1. 怎么将ffff:0 ~ ffff:b中的8位数据累加到16位寄存器中去?
    目前计算用一个16位寄存器作为中介。将内存单元中的8位数据赋值到一个16位寄存器ax,再将ax中的数据加到dx上去,从而使两个运算对象的类型匹配而且结果不会越界
assume cs:codecode segmentmov ax,0ffffhmov ds,axmov bx,0 ;初始化ds:bx指向ffff:0mov dx,0 ;初始化寄存器,(dx)=0mov cx,12s: mov al,[bx] ;ffff:0处的字节内容送给almov ah,0add dx,axinc bx ;ds:bx指向下一个单元loop smov ax,4c00hint 21hcode ends
end

七、段前缀

指令mov ax,[bx]中,内存单元中的偏移地址由bx给出,而段地址默认在ds中。我们可以在访问内存单元的指令中显示的给出内存单元的段地址所在的段寄存器:

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

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

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

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

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

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

这些出现在访问内存单元的指令中,用于显示的指明内存单元的段地址ds、cs、ss、es称为段前缀


八、一段安全的空间

随意向一段内存空间写入内容是很危险的,因为这段空间中可能存放着重要的系统数据或代码:

mov ax,1000h
mov ds,ax
mov al,0
mov ds:[0],al

这里如果1000:0处存放着重要的系统数据或代码,mov ds:[0],al将其改写将引发错误。

在DOS方式下,一般情况,0:200 ~ 0:2ff空间中没有系统或其他程序的数据或代码,以后我们就使用这段空间


九、段前缀的使用

将内存ffff:0 ~ ffff:b单元中的数据复制到0:200 ~ 0:20b单元中去
0:200 ~ 0:20b单元等同于0020:0 ~ 0020:b单元,他们描述的是同一段内存空间

思路:

  1. 初始化x = 0,循环十二次,将ffff:x单元中的数据送入0020:x(需要用一个寄存器中转)x = x + 1

  2. 在循环中,ffff:X和目标单元0020:X中的偏移地址X是变量,我们使用bx来存放

程序如下:

assume cs:codecode segmentmov bx,0mov cx,12s:    mov ax,0ffffhmov ds,axmov dl,[bx] ;将ffff:bx中的数据送入dlmov ax,0020hmov ds,ax ;ds = 0020hmov [bx],dl ;将dl中的数据送入0020:bxinc bxloop smov ax,4c00hint 21hcode ends
end

在这里我们可以进行改进,程序中我们设置了两个ds,我们可以使用两个段寄存器分别存放ffff:X和0020:X的段地址,这样子就可以省略重复做12次的设置ds程序段

assume cs:codecode segmentmov ax,0ffffhmov ds,ax ;ds=0ffffhmov ax,0020hmov es,ax ;es = 0020hmov bx,0 ;此时ds:bx指向ffff:0,es:bx指向0020:0mov cx,12s:  mov dl,[bx] ;将ffff:bx中的数据送入dlmov es:[bx],dl ;将dl中的数据送入0020:bxinc bxloop smov ax,4c00hint 21hcode ends
end

[汇编语言][bx]和loop指令相关推荐

  1. 汇编语言[BX]和loop指令

    1.使用bx来描述内存单元 我们知道mov ax,[0],是将偏移0的地址的值给寄存器ax,我们可以使用寄存器bx来动态的访问,比如: mov ax,1000 mov ds,ax mov bx,000 ...

  2. 《汇编语言》第5章 [BX]和loop指令

    1.[bx]和内存单元的描述 [bx]是什么呢?和[0]有些类似,[0]表示内存单元,它的偏移地址是0.比如在下面的指令中(在debug中使用): mov ax,[0] 将一个内存单元的内容送入ax, ...

  3. [BX]和loop指令03 - 零基础入门学习汇编语言25

    第五章:[BX]和loop指令03 让编程改变世界 Change the world by program 从上边的课程中,我们可以总结出用cx和loop 指令相配合实现循环功能的三个要点: (1)在 ...

  4. [BX] 和 loop 指令---汇编学习笔记

    [BX] 和 loop 指令 [bx]和内存单元的描述 loop 我们定义的描述性的符号:"()","()"中的元素可以有3中类型:寄存器名.段寄存器名.内存单 ...

  5. [bx]与loop指令

    [bx]与loop指令 文章目录 [bx]与loop指令 1.[bx]与loop指令概念 2.[bx]和loop的联合应用 3.段前缀概念 4.包含多个段的程序案例 1.[bx]与loop指令概念 [ ...

  6. [bx]和loop指令编程

    [bx]和loop指令编程 一. 实验目的 二.实验内容 三. 实验步骤 四. 结果 五. 心得体会 六. 实验与思考 一. 实验目的 1.掌握[bx]和loop指令的用法. 2.结合已学知识灵活应用 ...

  7. 汇编语言知识点总结之五:第五章《[bx]和loop指令》

    1.[bx]和内存单元的描述 [0]表示内存单元,它的偏移地址是0.比如在Debug中使用,如下指令: mov ax, [0] 代表:将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元) ...

  8. 《汇编语言》第5章 [BX]和loop指令——实验4[bx]和loop的使用

    本篇是第5章的实验--[bx]和loop的使用 (1)编程,向内存0:200~0:23F依次传送数据0~63(3FH). 解答: assume cs:codesg codesg segmentmov ...

  9. 第五章 [BX]和loop指令

    5.1 [bx] [bx]是什么 和 [0] 有些类似,[0] 表示内存单元,它的偏移地址是 0. 例如: mov ax, [0] 内存以字节为单位:ax以字(16bit = 2Byte)为单位:al ...

最新文章

  1. 项目中遇到的问题—遍历对象里面的数组
  2. win7 64bit下最新Apahe2.4.18+php7.0.2+MySQL5.7.10配置
  3. 从无头单链表中删除节点 结构之法 4
  4. python35是什么意思_python -m是什么意思CentOS 升级 Python3 (附带: 一键升级脚本)...
  5. 【NLP】6种用于文本分类的开源预训练模型
  6. 业务安全通用解决方案——WAF数据风控
  7. linux交叉编译时报错:file not recognized: File format not recognized
  8. python中单例模式是什么_python中的单例模式
  9. 报名即将截止,“梧桐杯”大数据应用创新大赛,邀你进入大数据先锋阵营
  10. 蓝牙鼠标windows linux,Ubuntu下使用蓝牙无线鼠标[图]
  11. 四、物理优化(6)数据库引擎优化顾问
  12. kubernetes源码阅读笔记——Kubelet(之三)
  13. ACM模板——线段树树状数组ST表
  14. GIWAXS数据处理流程详细
  15. 计算机和信息系统安全保密管理规定,信息系统安全和保密管理制度
  16. Ansys2019R2安装失败,更改用户名后win10用户创建临时账户登录个人总结
  17. 电脑通话有回音解决方案 使用电脑通话时有回音(可以听到对方电脑中自己说话的声音)电脑通话回音解决方案【以Thinkpad Win10系统为例】
  18. 拼字法以及98五笔字根码元应用举例
  19. 西方经济学思想发展脉络
  20. 教你快速高效接入SDK——Unity统一接入渠道SDK(Android篇)

热门文章

  1. 亲身经历:3天解决网站被百度网址安全中心拦截的方法
  2. PMO和项目经理必须掌握的战略制定与执行的思路和方法
  3. 创始人专访 | Paul:听到自己的学员取得科研成功,是最大的幸福之一
  4. 读书笔记:《过程咨询 III》
  5. FZU 2181 快来买肉松饼(dfs)
  6. 读取EXCEL文件数据,再调用第三方接口,将第三方数据重新写入到EXCEL文件
  7. 如何停止胡思乱想,保持专注?
  8. win10彻底删除Ubuntu EFI分区及启动项
  9. 电子商务就是计算机技术在传统商务中的应用,第1章 电子商务概述 习题答案
  10. Error: Message failed: 554 5.2.0 STOREDRV.Submission.Exception:OutboundSpamException;