目录编程
已经很久没写点东西了,国庆节就一直想弄个我的网站,这段时间一直在弄那个,虽然有现成的框架(Hexo),可是总想弄出本身的效果来,可是最后仍是有些差强人意,只好打翻了有重来(强迫症表示难受),也懒得弄那么多了。好在最近差很少事情也理顺了,今天强迫本身静下来写了点东西。框架
今天看了下汇编中的[BX]和Loop指令,Loop指令容易知道,一看就是用来作循环的指令,那么[BX]又是什么呢?oop
首先咱们知道,要完整的描述一个内存单元,须要两种信息:网站
对于第一个——【内存单元的地址】,咱们知道,用[addr]能够表示一个内存单元,其中addr表示这个内存单元的偏移地址,段地址默认在DS寄存器中。而单元的长度(类型)则能够由指令中的其余操做对象指出(如寄存器),就像下面这样:code
mov ax, [0]
那么,在这里[BX]也表示一个内存单元,其偏移地址存于BX寄存器中,段地址默认在DS寄存器中。也把BX寄存器叫作基址寄存器。对象
为了方便后面的叙述,这里做两个约定,固然也是跟着书上的来啦,哈哈,不过我发现不少书上也都默认有这个叙述方法。内存
用描述性符号“( )”表示一个寄存器或一个内存单元中的内容,如:it
(ax) 表示寄存器AX中的内容,(al) 表示寄存器AL中的内容。 (addr) 表示物理地址为addr的内存单元中的内容。
所以"( )"中的元素类型有3种:asm
其所表示的数据类型有:class
具体是那种类型则由寄存器名或具体的运算符决定。
用idata表示一个常量。
如用mov ax, [idata]
表明mov ax, [1]
、mov ax, [2]
等。
如用mov bx, idata
表明mov bx, 1
、mov bx, 2
等。
咱们对[BX]的使用有以下用法:
mov ax, [bx] ; bx中存放的数据做为偏移地址,段地址默认在ds中,(ax) = ((ds) * 16 + (bx)) mov [bx], ax ; bx中存放的数据做为偏移地址,段地址默认在ds中,((ds) * 16 + (bx)) = (ax)
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”就起做用了。
【注:如下内容来自王爽的《汇编语言》(第三版)】
考虑这么一个问题,咱们要计算 ffff:0~ffff:b 单元中的数据的和,要求将结果存储在dx寄存器中。
咱们首先分析一下:
ffff:0~ffff:b 内存单元中的数据是字节型的数据,范围在0~255之间,12个这样的数据相加的结果不会大于65535,是能够存储在dx寄存器中的。
这是比不可能的,为何?由于数据类型不匹配,dx是16位寄存器,而 ffff:0~ffff:b 中的数据是8位的。
看第一条分析,12个8字节的数据相加是有可能超过255的,而咱们的dl是8位寄存器,那么答案很明显了。不能!
这里有两个问题,类型的匹配和结果的不超界,咱们能够考虑用一个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 单元中。
分析:
实现以下:
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