循环指令
为了实现循环可以使用前面介绍过一些指令。例如,你可以将任意通用寄存器指定为计数器(通常ECX作为计数器使用),你可以将其初始化为需要循环的次数,然后执行循环体,接着计数器递减1,判断计数器是否为0,如果计数器不为0继续重复前面的过程,如果计数器为0,就不继续循环了,而直接执行下面的代码。代码如下:
XOR ECX,ECX
MOV ECX,15h 将计数器初始化为循环次数15h。接下来就是循环体了:
Label: DEC ECX 该计数器每次递减1。其实就是循环体了,循环体里面可以是任意指令。最后,你需要添加一个判断计数器是否为0的指令以及条件跳转指令。
CMP ECX,0
JNE Label 第一次判断,计数器的值为14h,因为14h不为0,所以将继续执行循环,以此类推,直到计数器为0为止。
我们完整的来写一遍上面的循环:
XOR ECX,ECX
ADD ECX,15h
Label:
DEC ECX
;循环体
TEST ECX,ECX
JNE Label
我们使用熟悉的指令模拟了一个最简单的循环例子。其实有专门用于循环的指令。我们来看一看。
1, LOOP
LOOP指令可以帮我们完成前面例子中的事情- 将计数器ECX的值减1,判断ECX的值是否为0,如果为0就跳转到指定的地址-将像前面的例子一样。(可惜的是,大多数现代的处理器中该指令的效率不如前面模拟的例子。)
![](https://img.haomeiwen.com/i15794461/210f734ac8f593c1.png)
这里还有一些与LOOP指令相关的指令:
2, LOOPZ, LOOPE 重复循环,直到零标志位Z置1
3, LOOPNZ, LOOPNE 重复循环,直到零标志位Z清0
这几条指令同样是循环指令,即重复循环体,直到计数器为0,每次循环将计数器的值递减1。此外,LOOPZ,LOOPNZ指令还将检查零标志位Z是否为0。只有计数器的值和零标志Z同时满足条件时才循环。
串操作
1, MOVS
该指令是从一个地址向另一个地址复制数据。源地址保存在ESI寄存器中,目的地址保存在EDI寄存器中。我们不需要显示地指定参数。现在我们在OD中写入 MOVS DWORD PTR ES:[EDI], DWORD PTR DS:[ESI] 指令,这里我们用ESI来保存源地址,EDI来保存目的地址。
这里MOVS拷贝4个字节的内容,即DWORD,另外一种书写形式为:MOVSD。与之对应的还有拷贝两个字节的MOVSW指令和拷贝一个字节的MOVSB指令。
请注意ESI,EDI拷贝的方向,拷贝的方向取决于方向标志位D。
2, REP
该指令可做为前面介绍的一些指令的前缀,尤其是MOVS指令。该前缀表示当前指令需要执行的次数ECX。每次循环计数器ECX的值递减1,和前面介绍的循环一样。
因此,REP MOVS不一定拷贝是4个字节,它拷贝的大小为每次拷贝的大小 * ECX, 源指针ESI和目的指针EDI每次递增4或者递减4(递增或递减取决于方向标志位D)。该指令看起来很实用,是不是?
该指令可以配合前面介绍的指令实现从一个地址单元拷贝任意数目的字节内容到另一个地址单元,但是很多现代处理器中实现的该指令效率并不是很高。
![](https://img.haomeiwen.com/i15794461/2099830e56a2b9b9.png)
源地址现在是40365C(仅供说明),目的地址和之前的一样,是40369C
3, LODS
该指令从源地址(像之前一样,ESI)拷贝数据到EAX中
LODS DWORD PTR DS:[ESI],
REP前缀也可以与LODS指令配合使用,他们会重复执行直到计数器ECX的值为0。
当循环执行REP
LODS指令时,解释窗口中会提示ECX的值,以及ESI指向的内存单元中下一次将被拷贝到EAX寄存器中的内容。也有一次拷贝两个字节和一个字节的LODSW和LODSB指令。
4, STOS
该指令是将EAX的值拷贝到EDI指向的内存单元中。
STOS DWORD PTR ES:[EDI]
5, CMPS
该指令比较ESI和EDI指向内存单元的内容
CMPS DWORD PTR [ESI],DWORD PTR [EDI] ,
该指令执行的是算数减法运算,这里,差值为0,所以零标志位Z将置1,为该指令影响的零标志位Z,所以你可以配合REPE/REPZ前缀指令使用,直到计数器ECX的值为0或者零标志位清0。
网友评论