REP
指令簇主要用来重复执行指令。REP
前缀后加指令来协同完成。如:
REP MOVSB
REP LODS AL
重复N次字符串指令,N的值存储在(E)CX计数寄存器中,或者直到ZF标志位不满足为止。 REP指令前缀簇有如下指令:
指令 | 原名 | 备注 |
---|---|---|
REP | repeat | 重复指令 |
REPE | repeat while equal | 当ZF为0时表示值相等,重复指令 |
REPNE | repeat while not equal | 当ZF为1时,表示两个值不相等,重复指令 |
REPZ | repeat while zero | 当ZF为0时表示值相等,重复指令 |
REPNZ | repeat while not zero | 当ZF为1时,表示两个值不相等,重复指令 |
以上的指令前缀都可以配合字符串指令来共同作用。
例如:INS
,OUTS
,MOVS
,LODS
以及STOS
,CMPS
,SCAS
指令。
REP前缀如果使用非字符串指令时是不允许的。REP前缀同一时间只能够应用于一条字符串指令。如果需要重复多条指令,则需要使用LOOP指令或者其他的循环结构。
所有的这些repeat前缀会导致与其相关联的指令重复执行,直到计数寄存器((E)CX)减少到0,如果是32位地址则为ECX,如果是16位地址则为CX寄存器。
REPE,REPNE,REPZ和REPNZ前缀在每一次循环的时候都会检查ZF标志位,当ZF标志位归0,并且(E)CX计数寄存器为0时,停止循环。 当两个终止条件都满足时,就确定循环终止:
如下表所示,当条件都满足的时候才会终止:
前缀 | 终止条件1 | 终止条件2 |
---|---|---|
REP | ECX=0 | None |
REPE/REPZ | ECX=0 | ZF=0 |
REPNE/REPNZ | ECX=0 | ZF=1 |
当REPE/REPZ以及REPNE/REPNZ前缀使用的时候,ZF标志位不需要初始化,因为CMPS以及SCAS指令会根据结果将ZF标志位进行修改
字符串操作的重复指令会被异常或者中断而打断。当异常或者中断发生的时候,寄存器的状态可以被字符串操作所保存,并且从中断或者异常的Handler中返回并且Resume。源寄存器和目标寄存器指向要操作的下一个字符串元素,EIP寄存器指向字符串指令,ECX寄存器具有在指令的最后一次成功迭代之后保持的值。该机制允许长串操作在不影响系统的中断响应时间的情况下进行。
当错误发生在以REPE或者REPNE的CMPS以及SCAS指令时,EFLAGS寄存器的值将在指令执行前恢复状态。一旦SCAS以及CMPS指令不再使用EFLAGS寄存器作为输入时,处理器会在页错误Handler处理之后继续指令的执行。
使用REP INS以及REP OUTS指令的时候,不是所有的IO端口都能跟上这些指令的处理速度。
REP STOS指令是最建立一个比较大的内存块的最快的方法。
指令:REP INS mem8/16/32, DX 描述:从DX保存的端口中连续读取(E)CX个字节/字/双字数据放入ES:(E)DI寄存器中
指令:REP MOVS mem8/16/32, m8/16/32 描述:从DS:[(E)SI]中复制(E)CX个字节/字/双字到ES:[(E)DI]
DS:[(E)SI]由于(E)SI寄存器中保存的是源操作数的地址,所以DS:[(E)SI]指的就是该地址保存的值
指令:REP OUTS DX, reg/m(8/16/32) 描述:将DS:[(E)SI]作为基址,输出(E)CX个字节/字/双字到DX保存的端口中
指令:REP LODS AL/AX/EAX 描述:从DS:[(E)SI]处加载(E)CX个字节到AL/AX/EAX寄存器中
指令:REP STOS m8/16/32 描述:将AL/AX/EAX中的值填充(E)CX个字节到ES:[(E)DI]地址处
指令:REPE CMPS m8/16/32, m8/16/32 描述:比较ES:[(E)DI]和DS:[(E)SI]的(E)CX个字符
指令:REPE SCAS m8/16/32 描述:扫描从ES:[(E)DI]位置开始的非AL/AX/EAX的字符串
指令:REPNE CMPS m8/16/32, m8/16/32 描述:比较ES:[(E)DI]和DS:[(E)SI]的字节/字/双字
指令:REPNE SCAS m8 描述:从ES:[(E)DI]开始查找AL/AX/EAX的字符串