80806汇编(5)——[BX]和Loop指令

已经好久没写点东西了,国庆节就一直想弄个个人网站,这段时间一直在弄那个,虽然有现成的框架(Hexo),但是总想弄出自己的效果来,但是最后还是有些差强人意,只好打翻了有重来(强迫症表示难受),也懒得弄那么多了。好在最近差不多事情也理顺了,今天强迫自己静下来写了点东西。

[TOC]


简述

今天看了下汇编中的[BX]和Loop指令,Loop指令容易知道,一看就是用来做循环的指令,那么[BX]又是什么呢?

首先我们知道,要完整的描述一个内存单元,需要两种信息:

  • 内存单元的地址
  • 内存单元的长度(类型:字节或字等)

对于第一个——【内存单元的地址】,我们知道,用[addr]可以表示一个内存单元,其中addr表示这个内存单元的偏移地址,段地址默认在DS寄存器中。而单元的长度(类型)则可以由指令中的其他操作对象指出(如寄存器),就像下面这样:

mov ax, [0]

那么,在这里[BX]也表示一个内存单元,其偏移地址存于BX寄存器中,段地址默认在DS寄存器中。也把BX寄存器叫做基址寄存器

两个约定

为了方便后面的叙述,这里作两个约定,当然也是跟着书上的来啦,哈哈,不过我发现很多书上也都默认有这个叙述方法。

1. 描述性符号"( )"

用描述性符号“( )”表示一个寄存器或一个内存单元中的内容,如:

(ax) 表示寄存器AX中的内容,(al) 表示寄存器AL中的内容。
(addr) 表示物理地址为addr的内存单元中的内容。

因此"( )"中的元素类型有3种:

  1. 寄存器名;
  2. 段寄存器名;
  3. 内存单元的物理地址。

其所表示的数据类型有:

  1. 字节;
  2. 字。

具体是那种类型则由寄存器名或具体的运算符决定。

2. 常量符号"idata"

用idata表示一个常量。

如用mov ax, [idata]代表mov ax, [1]mov ax, [2]等。

如用mov bx, idata代表mov bx, 1mov bx, 2等。

[BX]

我们对[BX]的使用有如下用法:

mov ax, [bx]  ; bx中存放的数据作为偏移地址,段地址默认在ds中,(ax) = ((ds) * 16 + (bx))
mov [bx], ax  ; bx中存放的数据作为偏移地址,段地址默认在ds中,((ds) * 16 + (bx)) = (ax)

Loop指令

Loop指令用于实现循环功能,循环次数存于CX寄存器中 。

【格式】loop 标号

示例:

mov cx, 5      ; 设置循环次数
s:                  ; 标号
add ax, ax     ; 循环执行的程序段
loop s           ; Loop指令

Loop指令通常用于执行某些需要重复运行的指令,比如操作某一块连续的内存地址块。通常把循环次数存于CX寄存器中,CPU通过判断CX里面的值是否为零来决定是否执行循环。CPU执行Loop指令的描述如下:

1. (CX) = (CX) -1
2. (CX)不为零,转去标号处执行,反之不执行循环,向下执行指令

这里的标号"s"并不是固定的,你也可以指定其他的标号。在这里标号实际上是标识了一个地址,在该地址处存在着我们的程序指令(如上面的add ax, ax),在执行循环的时候,若CX的值不为零,则"Loop 标号"指令将IP的值设置为标号所标识的地址,CPU就将执行IP所指向的指令。

我们可以得到这样一个Loop指令的简单框架:

mov cx, 循环次数
label:
需要循环执行的程序段
loop label

【注意】书上的一个实例程序中提到在汇编程序中的数据表示问题,我们知道,在汇编中,数据多以16进制表示,而16进制中有 'A~F' 6个字母,但是在汇编源程序中,数据的书写不能以字母开头,如“9876H”可以直接书写为“9876H”,但是“A000H”不能书写成“A000H”,而需写为“0A000H”(以0开头)。

[BX]和Loop指令

在实际编程中可能会遇到要处理某一段地址连续的内存单元中的数据,通常可用循环来解决这类问题。在这样的循环过程中,需要一个变量来保存内存单元的偏移地址,这时候“基址寄存器——BX”就起作用了。

【注:以下内容来自王爽的《汇编语言》(第三版)】

考虑这么一个问题,我们要计算 ffff:0~ffff:b 单元中的数据的和,要求将结果存储在dx寄存器中。

我们首先分析一下:

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

    ffff:0~ffff:b 内存单元中的数据是字节型的数据,范围在0~255之间,12个这样的数据相加的结果不会大于65535,是可以存储在dx寄存器中的。
  2. 我们能否将 ffff:0~ffff:b 中的数据直接累加到dx中?

    这是比不可能的,为什么?因为数据类型不匹配,dx是16位寄存器,而 ffff:0~ffff:b 中的数据是8位的。
  3. 那么是否可以将其累加到dl中,并设置(dh)=0,从而实现累加到dx中?

    看第一条分析,12个8字节的数据相加是有可能超过255的,而我们的dl是8位寄存器,那么答案很明显了。不能!
  4. 那到底应该如何做呢?

    这里有两个问题,类型的匹配和结果的不超界,我们可以考虑用一个16位的寄存器来做中介。将内存单元中的8位数据赋值到一个16位寄存器ax中,再将ax中的数据加到dx上,从而使两个运算对象类型匹配并且结果不会超界。

考虑完以上问题,很明显,如果是在高级语言中,这是一个很容易做的问题,一个循环就可以实现,那么在汇编中,我们也可以用循环来实现这个操作。我们可以把BX用作存储内存单元偏移地址的变量,在每次循环的时候改变BX中的值,从而实现把 ffff:0~ffff:b 12个内存单元中的数据相加。

实现如下:

assume cs:code
code segment
    start:             ;程序入口
    mov ax, 0ffffh
    mov ds, ax
    mov bx, 0       ;初始化ds:bx指向ffff:0

    mov dx, 0      ;初始化累加寄存器dx,(dx)=0

    mov cx, 12
    s:
    mov al, [bx]
    mov ah, 0
    add dx, ax
    inc bx          ;使ds:bx指向下一个内存单元
    loop s

    mov ax, 4c00h
    int 21h
code ends
end start        ;程序结束

段前缀

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

mov ax, ds:[bx]
mov ax, cs:[bx]
mov ax, ss:[bx]
mov ax, es:[bx]
mov ax, ss:[0]
mov ax, cs:[0]

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

段前缀的使用

考虑一个问题,将内存单元 ffff:0~ffff:b 单元中的数据复制到 0:200~0:20b 单元中。

分析:

  1. 0:200 ~0:20b 单元等同于 0020:0~0020:b 单元,它们描述的是同一段内存空间。
  2. 复制过程用循环实现,我们可以使用一个变量[BX]同时操作两段内存单元(使用段前缀来标识不同的段)。
  3. 将 0:200~0:20b 用 0020:0~0020:b 描述,是为了使目标单元的偏移地址和源始单元的偏移地址从同一数值0开始。

实现如下:

assume cs:code
code segment
    mov ax, 0ffffh
    mov ds, ax           ;(ds)=0ffffh

    mov ax, 0020h
    mov es, ax         ;(es)=0020h

    mov bx, 0   ;此时ds:bx指向ffff:0,es:dx指向0020:0

    mov cx, 12
    s:
    mov dl, [bx]      ;段地址默认在ds中
    mov es:[bx], dl   ;段前缀指明内存段
    inc bx
    loop s

    mov ax, 4c00h
    int 21h
code ends
end

80806汇编(5)——[BX]和Loop指令的更多相关文章

  1. 王爽汇编第五章,[bx]和loop指令

    目录 王爽汇编第五章,[bx]和loop指令 [bx]和loop指令 例子: 王爽汇编第五章,[bx]和loop指令 [bx]和loop指令 [bx]之前我们介绍寄存器的时候,已经很详细的说明过了,b ...

  2. [汇编学习笔记][第五章[BX]和loop指令]

    第五章[BX]和loop指令 前言 定义描述性符号“()”来表示一个寄存器或一个内存单元的内容,比如: (ax)表示ax中的内容,(al)表示al的内容. 约定符号ideta表示常量. 5.1 [BX ...

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

    汇编语言-[BX]和loop指令 [BX]指令介绍 mov ax,[bx] 功能: bx为偏移地址,段地址默认为ds.因此,上面指令作用就是将ax中的数据送入内存ds:bx处,即:((ds)*16 + ...

  4. 汇编-5.0-[BX]和loop指令

    1.要完整的描述一个内存单元,需要两种信息:1.内存单元的地址:2.内存单元的长度(类型). 2."()"表示一个寄存器或一个内存单元中的内容.如:(ax)表示ax中的内容. &q ...

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

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

  6. 小甲鱼零基础汇编语言学习笔记第五章之[BX]和loop指令

         这一章主要介绍什么是[BX]以及loop(循环)指令怎么使用,loop和[BX]又怎么样相结合,段前缀又是什么鬼,以及如何使用段前缀.   1.[BX]的概念      [BX]和[0]类似 ...

  7. [bx]和loop指令

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  8. 汇编:汇编语言实现冒泡排序(loop指令实现)

    ;=============================== ;循环程序设计 ;loop指令实现 ;冒泡排序 ;for(int i=0;i<N;i++){ ; for(int h=0;j&l ...

  9. 汇编语言-[bx]和loop指令和多个段

    5.1 [BX]和内存单元的描述 要完成描述一个内存单元,需要两种信息: 内存单元的地址: 可以用 [0] 表示一个内存单元, 0 表示单元的偏移地址,段地址默认在 ds 中: 同样也可以用 [bx] ...

随机推荐

  1. Akka(25): Stream:对接外部系统-Integration

    在现实应用中akka-stream往往需要集成其它的外部系统形成完整的应用.这些外部系统可能是akka系列系统或者其它类型的系统.所以,akka-stream必须提供一些函数和方法来实现与各种不同类型 ...

  2. python 浅析模块

    今天买了一本关于模块的书,说实话,模块真的太多了,小编许多也不知道,要是把模块全讲完,可能得出本书了,所以小编在自己有限的能力范围内在这里浅析一下自己的见解,同时讲讲几个常用的模块. 首先说一下对模块 ...

  3. Mybatis第一篇【介绍、快速入门、工作流程】

    什么是MyBatis MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为 ...

  4. Servlet第一篇【介绍Servlet、HTTP协议、WEB目录结构、编写入门Servlet程序、Servlet生命周期】

    什么是Serlvet? Servlet其实就是一个遵循Servlet开发的java类.Serlvet是由服务器调用的,运行在服务器端. 为什么要用到Serlvet? 我们编写java程序想要在网上实现 ...

  5. [04] Object类

    1.基本概念 Object类是所有类的父类,位于java.lang包中.任何类的对象,都可以调用Object类中的方法,包括数组对象. 2.常用方法 2.1 toString toString可以将任 ...

  6. Java中增强for循环的用法

    此方法在jdk1.5之后才出现. 1:遍历数组 语法: for (Type value : array) { expression value; } 例子: void Sum() { int[] ar ...

  7. 一张图告诉你移动Web前端所有技术(工程化、预编译、自动化)

    你要的移动web前端都在这里! 大前端方向:移动Web前端.Native客户端.Node.js. 大前端框架:React.Vue.js.Koa 跨终端技术:HTML5.CSS 3.JavaScript ...

  8. 云 MongoDB 优化让 LBS 服务性能提升十倍

    欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 随着国内服务共享化的热潮普及,共享单车,共享雨伞,共享充电宝等各种服务如雨后春笋,随之而来的LBS服务定位问题成为了后端服务的一个挑战.M ...

  9. struts标签与jstl标签互换

    近期在做struts切换spring mvc时发现代码中使用了大量的struts标签,对常用的struts标签做了总结,首先需要引入 <%@ taglib prefix="c" ...

  10. Java并发之线程中断

    前面的几篇文章主要介绍了线程的一些最基本的概念,包括线程的间的冲突及其解决办法,以及线程间的协作机制.本篇主要来学习下Java中对线程中断机制的实现.在我们的程序中经常会有一些不达到目的不会退出的线程 ...