天天看点

汇编语言学习第五章-[BX]和loop指令

本博文系列参考自<<汇编语言>>第三版,作者:王爽

1.[bx]和内存单元的描述

[bx]与我们前面见过的[0]类似,mov ax,[0] 的意思是将内存地址为DS:0的两字节内容存入ax中。其中[0]中的0代表的是偏移地址。

类似的,我们有 mov al,[0]的意思是将内存地址为DS:0的单字节内容存入al中。那么我们可以大胆的推断mov ax,[bx]代表的是将偏移地址为bx寄存器中的值的内存地址的两字节内容存入到ax中,其段地址在DS中存储。

2.关于定义的描述性符号: "()"

后面的内容我们都将用符号"()"来表示一个内存单元或一个寄存器中的值。(ax)表示寄存器ax中的值,(al)表示寄存器al中的值。

(20000H)表示内存地址为20000的内容

((ds)*16+(bx)) ds的内容为R1,bx中的地址为R2。那么该公式代表R1*16+R2内存地址处的内容。

"( )"中可以有三种类型元素:(1).寄存器  (2)段寄存器 (3)内存地址 其表示的数据有两种类型:字和字节。如何区分数据类型是根据寄存器类型和运算类型进行区分的。

"()"的应用举例:

汇编语言学习第五章-[BX]和loop指令

1.[bx]

看几个指令:

mov ax,[bx]  设偏移地址为SA,段地址默认存储在DS寄存器中,那么该指令的作用是将地址为DS:SA处的值传入ax寄存器中。

用"()"符号解释为 (ax)=((DS)*16+(bx))

mov [bx],ax  设偏移地址为SA,段地址默认存储在DS寄存器中,那么该指令的作用是将寄存器ax值传入[bx]所代表的偏移地址的位置,用"()"符号解释为 ((DS)*16+(bx))=(ax)

2. LOOP指令

LOOP指令为循环指令,其格式为 LOOP 标号,当cx不为0的时候跳转到标号处循环同时cx=cx-1,如果标号为0则向下执行。(CX默认为循环计数器)

下面实现一个小程序,用LOOP实现2^12,代码如下:

汇编语言学习第五章-[BX]和loop指令

1.标号

标号s处有一条指令,add ax,ax用于累加,标号s代表该条指令的地址。

2.loop s

当cx寄存器中的值不为0的时候将跳转到标号处循环执行add ax,ax。当cx=0的时候,loop s不再跳转,将执行Loops后面的指令。

用cx和loop实现循环框架如下:

         mov cx,循环次数

标号: 代码段

        loop  标号

现在有这样一个程序功能需要实现:计算ffff:0006单元中的数乘以3,结果存放在dx中。

此程序有三个注意点

1、ffff:0006单元中的数是一个字节型数据。范围为0-255,乘以3完全可以放到dx中,不用担心超过dx的范围

2、将ffff:0006单元中的数赋值给ax,然后令(dx)=0,用dx存储累加三次的结果

3、因为ffff:0006为一个字节单元,ax为一个字单元。如何将ffff:0006单元的值赋值给ax呢。这里只需要将ax中高位字节扩展为      00h即可,比如ffff:0006中为2CH,那么赋值给ax后为002CH,虽然数据长度不等,但是值是相等的。

汇编语言学习第五章-[BX]和loop指令

注意几点,0ffffh为何前面会有个"0",当16进制数据最高位为字母的时候需要在最高位前面加上0.

下面我们通过masm和link两条指令对该程序进行编译链接生成exe文件。

汇编语言学习第五章-[BX]和loop指令

用debug工具加载vpoet.exe:

汇编语言学习第五章-[BX]和loop指令

DS为14E9   CS:IP为 14F9:0000 指向第一条指令 mov AX,FFFF

现在我们用U指令查看程序内容。

汇编语言学习第五章-[BX]和loop指令

可以看到LOOP S处的地址为14F9:E2FC 此时LOOP S中的S标号变成地址0012,当执行了LOOP循环后,那么CX=CX-1,如果CX不为0,那么将IP设置为S标号的地址0012 CPU将执行地址14F9:0012处的指令ADD DX,AX实现叠加。

汇编语言学习第五章-[BX]和loop指令

前三条指令执行完之后,DS被设置为FFFFH,BX设置为0006H 此时DS:bx指向 FFFF:6,接下来将执行MOV AL,[BX]取出FFFF:6地址处的值,在右边显示了该值为32H

继续执行下面两条指令:

汇编语言学习第五章-[BX]和loop指令

执行完后完成了对AX的复制,AX值为0032H

继续执行 MOV DX,0和MOV CX,3完成累加器和计数器的初始化

汇编语言学习第五章-[BX]和loop指令

下面开始循环过程,可以看出每次循环一次CX减小1,同时DX增加一倍。

汇编语言学习第五章-[BX]和loop指令

当CX=0000时候循环结束,执行接下来的返回语句 MOV AX,4c00h和int 21h。至此整个程序结束将CPU控制器交给command.

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

1.在汇编语言中,如果一个指令要访问内存单元,则在指令中必须用[...]来表示内存单元,如果在[...]中直接用常量给出内存地址的偏移地址,那么需要在"[ ]"前面加上段寄存器。比如

mov al,ds:[0]如果没有显示的给出段寄存器ds:,那么mov al,[0]在汇编语言中被理解为mov al,0

2.在汇编语言中,也可以将偏移地址存入一个普通寄存器bx,比如

mov bx,0

mov al,[bx]这样也是允许的,其中段寄存器默认在ds中

5.5  段前缀

汇编指令mov ax,[bx]将偏移地址在寄存器bx中指出,而段地址默认在ds中,我们也可以在指令中显示的给出段地址:

比如

 mov ax,ds:[bx]

 mov ax,ds:[bx]

 mov ax,cs:[bx]

 mov ax,ds:[0]

 mov ax,ds:[0]

 mov ax,cs:[0]

其中 ds:    cs:  ss:称为段前缀

5.6 一段安全的空间

在汇编中,当我们更改某个内存地址的内容的时候需要十分谨慎,因为该地址可能存储着重要的代码或者数据,一旦覆盖或者更改会导致整个系统的崩溃。在DOS方式下,DOS和其他合法的程序一般都不会使用0:200~0:2ff这256个字节的空间。所以,使用这段空间是安全的,我们可以在debug下查看这段地址是否为0,如果为0证明该内存段未被DOS和其他程序使用。

5.8段前缀的使用

问题,我们需要将内存ffff:0~ffff:b单元的数据复制到0:200~0:20b

分析如下:

1.0:200~0:20b等同于 0020:0~0020:b,这样描述为了使得目标地址和源地址偏移量都从0开始

2.复制过程用loop循环实现

初始化:

   X=0

循环12次:

将ffff:X单元的数据送入0020:X(需要一个寄存器中转)

X=X+1

3.循环中ffff:X和0200:X的偏移量X存入bx

代码及注释如下:

汇编语言学习第五章-[BX]和loop指令

OK,only stop here~~

汇编语言学习第五章-[BX]和loop指令

继续阅读