一、关于REP/REPE/REPZ/REPNE/REPNZ
按计数寄存器 ((E)CX) 中指定的次数重复执行字符串指令,或是重复到 ZF 标志不再满足指定的条件。REP(重复)、REPE(相等时重复)、REPNE(不相等时重复)、REPZ(为零时重复)及 REPNZ(不为零时重复)助记符都是可以添加到一些字符串指令中的前缀。REP 前缀可以添加到 INS、OUTS、MOVS、LODS 及 STOS 指令,REPE、REPNE、REPZ 及 REPNZ 前缀可以添加到 CMPS 与 SCAS 指令。(REPZ 与 REPNZ 前缀分别是 REPE 与 REPNE 前缀的同义形式)。同非字符串指令一起使用时,REP 前缀的行为未定义。
REP 前缀一次只能应用于一条字符串指令。要重复指令块,请使用 LOOP 指令或其它循环结构。
所有这些重复前缀都会使关联的指令重复执行,直到寄存器 (E)CX 中的计数递减到 0(请参阅下表)。(如果当前地址大小属性为 32,则将寄存器 ECX 用作计数器;如果大小属性为 16,则将 CX 寄存器用作计数器)。在每次迭代之后,REPE、REPNE、REPZ 及 REPNZ 前缀还会检查 ZF 标志的状态,如果 ZF 标志未处于指定的状态,则终止重复循环。同时测试两个终止条件时,终止重复的原因可以通过使用 JECXZ 指令来测试 (E)CX 寄存器进行确定,也可以通过使用 JZ、JNZ 及 JNE 指令来测试 ZF 标志进行确定。
重复前缀 | 终止条件1 | 终止条件2 |
REP | ECX=0 | 无 |
REPE/REPZ | ECX=0 | ZF=0 |
REPNE/REPNZ | ECX=0 | ZF=1 |
使用 REPE/REPZ 与 REPNE/REPNZ 前缀时,由于 CMPS 与 SCAS 指令都会根据它们的比较结果设置 ZF 标志,因此 ZF 标志不需要初始化。
正在重复的字符串操作可以因异常或中断而暂停。发生这种情况时,将保存寄存器的状态,以便从异常或中断处理程序返回时,字符串操作能够恢复。源寄存器与目标寄存器指向下一个要操作的字符串元素,EIP 寄存器指向字符串指令,ECX 寄存器保存的是上一次成功迭代指令之后的值。通过此种机制,就可以执行很长的字符串操作,而不会影响系统的中断响应时间。
在执行以 REPE 或 REPNE 为前缀的 CMPS 或 SCAS 指令期间,如果发生错误,EFLAGS 值还原为指令执行之前的状态。由于 SCAS 与 CMPS 指令不会将 EFLAGS 用作输入,因此,处理器可以在页错误处理程序完成之后恢复执行指令。
谨慎使用 REP INS 与 REP OUTS 指令。并非所有的 I/O 端口都可以处理这些指令的执行速率。
初始化大块内存最快的方法是使用 REP STOS 指令。
示例一:在字符串中查找字符
cld //从低地址到高地址方向
lea edi, lpszName //edi指向目标字符串首地址 (00402068)="*.exe"
mov al,'x' //要查找值放入al中
mov ecx,5 //重复查找次数
repne scasb //在edi所指字符串中查找al值,若不等将继续查找,直到(ecx)=0
REPNE执行的操作:
1)如(ecx)=0时退出,否则往下执行
2)(ecx)=(ecx)-1
3)执行其后的串指令
4)重复1)~3)
上述程序段执行结果:(edi)=0040206c (ecx)=1
示例二:两个字符串比较
cld //从低地址到高地址方向
lea edi, lpszSrc //edi指向目标字符串首地址 (00402060)="c:\windows"
lea esi, lpszDes //edi指向目标字符串首地址 (00402090)="c:\windows"
mov ecx,11 //重复查找次数
repz cmpsb //如果相等则继续比较,直到源目字符不等或(ecx)=0才结束
.if ZERO? //如果条件满足,表示两个字符串完全相等
...
.endif//重复查找次数
上述程序段执行结果:(edi)=0040206B (edi)=0040209B (ecx)=0 ZF=1
二、关于mul div imul idiv
MUL: 无符号乘
;影响 OF、CF 标志位 ;指令格式: ;MUL r/m ;参数是乘数 ;如果参数是 r8/m8, 将把 AL 做乘数, 结果放在 AX ;如果参数是 r16/m16, 将把 AX 做乘数, 结果放在 EAX ;如果参数是 r32/m32, 将把 EAX 做乘数, 结果放在 EDX:EAX
示例一: 8 位
mov al, 0FFh mov cl, 8 mul cl 执行结果:(ax)=07F8h 示例二: 16 位 mov ax, 0FFFFh
mov cx, 8 mul cx
执行结果:(dx)=0007h (ax)=0FFF8h 示例三: 32 位 mov eax, 0FFFFFFFFh
mov ecx, 8 mul ecx 执行结果: (edx)=00000007h (eax)=0FFFFFFF8h
IMUL: 有符号乘
;影响 OF、CF 标志位 ;第一种指令格式: ;IMUL r/m ;单操作数 ;如果参数是 r8/m8, 将把 AL 做乘数, 结果放在 AX ;如果参数是 r16/m16, 将把 AX 做乘数, 结果放在 EAX ;如果参数是 r32/m32, 将把 EAX 做乘数, 结果放在 EDX:EAX ;以上这些都是和 MUL 一样的, 只是运算结果有时一样、有时不一样. ;IMUL 还有另外两种指令格式: ;IMUL r16/r32, r16/r32/m16/m32/i ;双操作数, (1)*(2) -> (1) ;IMUL r16/r32, r16/r32/m16/m32, i ;三操作数, (2)*(3) -> (1) ;其中常数 i 的位数可以 <= 但不能 > 其他操作数
示例一:8 位
mov al, 0FFh
mov cl, 8 imul cl
执行结果:(ax)=0FFF8h 示例二:16 位 mov ax, 0FFFFh
mov cx, 8 imul cx
执行结果:(dx)=0FFFFh (ax)=0FFF8h 示例三:32 位 mov eax, 0FFFFFFFFh
mov ecx, 8 imul ecx 执行结果:(edx)=0FFFFFFFFh (eax)=0FFFFFFF8h 示例四:;IMUL 两个操作数 mov eax, 7
mov ecx, 8 imul eax, 8 执行结果:(eax)=56 示例五:IMUL 三个操作数 mov ecx, 8
imul eax, val, 9 执行结果:(eax)=72
MUL 与 IMUL 结果的一致和不一致:
示例六:如果操作数都没有符号位, 结果一致 mov al, 7Fh
mov cl, 7fh mul cl 执行结果: (ax)=3F01h mov al, 7Fh
mov cl, 7fh imul cl 执行结果: (ax)=3F01h 示例七:如果操作数的其中之一有符号位, 结果不一致 mov al, 80h
mov cl, 7fh mul cl 执行结果: (ax)=3F80 mov al, 80h
mov cl, 7fh imul cl 执行结果: (ax)=0C080h 示例八:如果操作数都有符号位, 结果也一致 mov cl, 80h mov al, 80h mul cl 执行结果: (ax)=4000h mov al, 80h
mov cl, 80h imul cl 执行结果: (ax)=4000h
DIV、IDIV: 无符号除、有符号除
;它们没有定义对 EFLAGS 的影响 ;它们的指令格式: ;DIV r/m ;参数是除数 ;如果参数是 r8/m8, 将把 AX 做被除数; 商 -> AL, 余数 -> AH ;如果参数是 r16/m16, 将把 DX:AX 做被除数; 商 -> AX, 余数 -> DX ;如果参数是 r32/m32, 将把 EDX:EAX 做被除数; 商 -> EAX, 余数 -> EDX
示例一:除数是 8 位 mov ax, 17 ;被除数 mov cl, 3 ;除数 div cl 执行结果: (al)=5 --商 (ah)=2 --余数 示例二:除数是 16 位 mov dx, 0 ; mov ax, 17 ;dx:ax 是被除数 mov cx, 3 ;cx 是除数 div cx 执行结果: (ax)=5 --商 (dx)=2 --余数 示例三:除数是 32 位 mov edx, 0 ; mov eax, 17 ;edx:eax 是被除数 mov ecx, 3 ;ecx 是除数 div ecx 执行结果: (eax)=5 --商 (edx0=2 --余数
;IDIV 测试 示例一:除数是 8 位 mov al, -17 cbw ;ax 是被除数 mov cl, 3 ;除数 idiv cl 执行结果: (al)=-5 --商 (ah)=-2 --余数 示例二:除数是 16 位 mov ax, -17 cwd ;dx:ax 是被除数 mov cx, 3 ;cx 是除数 idiv cx 执行结果: (ax)=-5 --商 (dx)=-2 --余数 示例三:除数是 32 位 mov eax, -17 cdq ;edx:eax 是被除数 mov ecx, 3 ;ecx 是除数 idiv ecx 执行结果: (eax)=-5 --商 (edx)=-2 --余数