. 8D7C24 10 lea edi, dword ptr [esp+10] ; esp+10 指向字符串
. 83C9 FF or ecx, FFFFFFFF
. 33C0 xor eax, eax
. F2:AE repne scas byte ptr es:[edi] ; 这里不明白。
. F7D1 not ecx
. 49 dec ecx
这个是最经典的求字符串长度的代码。
33C0 xor eax, eax
F2:AE repne scas byte ptr es:[edi]
扫描字符串ES:[EDI]中的AL字节值,遇到AL值停止
参考:
重复前缀指令
任何一个串操作指令,都可以在前面加一个重复前缀,以实现串操作的重复执行,重复次数隐含在CX寄存器中
REP ;REP前缀用在MOVS、STOS、LODS指令前,每次执行一次指令,CX减1;直到CX=0,重复执行结束
REPZ ;也可以表把为REPE,用在CMPS、SCAS指令前,每执行一次串指令CX减1,并判断ZF标志是否为0
;只要CX=0或ZF=0,则重复执行结束
REPNZ ;也可以表达为REPNE,用在CMPS、SCAS指令前,每执行一次串操作指令CX减1,并判断ZF标志是否为1,只要CX=0或ZF=1,则重复执行结束。
串扫描指令SCAS
SCASB ;字节串扫描:AL-ES:[DI],DI←DI+/-1
SCASW ;字串扫描:AX-ES:[DI],DI←DI+/-2
串扫描指令SCAS将附加段中的字节或字内容与AL/AX寄存器内容进行比较,根据比较的结果设置标志,每次比较后修改DI寄存器的值,使之指向下一个元素。
解释:
假设esp+10指向字符串如:"xqiang",长度为6,以0结尾
ecx=FFFFFFFF
eax=0,则al=0
执行repne scas时候:
第一次:
al-'x',di=di-1,即byte ptr es:[edi]指向'q',并置相应的标志位
然后cx-1,则ecx=FFFFFFFE,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第二次:
al-'q',di=di-1,即byte ptr es:[edi]指向'i',并置相应的标志位
然后cx-1,则ecx=FFFFFFFD,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第三次:
al-'i',di=di-1,即byte ptr es:[edi]指向'a',并置相应的标志位
然后cx-1,则ecx=FFFFFFFC,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第三次:
al-'a',di=di-1,即byte ptr es:[edi]指向'n',并置相应的标志位
然后cx-1,则ecx=FFFFFFFB,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第四次:
al-'n',di=di-1,即byte ptr es:[edi]指向'g',并置相应的标志位
然后cx-1,则ecx=FFFFFFFA,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第五次:
al-'g',di=di-1,即byte ptr es:[edi]指向'0',并置相应的标志位
然后cx-1,则ecx=FFFFFFF9,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第六次:
al-0,di=di-1,即byte ptr es:[edi]指向'未知字符',并置相应的标志位
然后cx-1,则ecx=FFFFFFF8,判断是否cx=0或ZF=1,此时ZF=1,停止串搜索
现在ecx从FFFFFFFF到FFFFFFF8记录了字符串'xqiang'和0的长度
然后not ecx得到ecx=00000007
dec ecx得到ecx=00000006 该长度就是字符串'xqiang'的实际长度
重复前缀指令
任何一个串操作指令,都可以在前面加一个重复前缀,以实现串操作的重复执行,重复次数隐含在CX寄存器中
REP ;REP前缀用在MOVS、STOS、LODS指令前,每次执行一次指令,CX减1;直到CX=0,重复执行结束
REPZ ;也可以表把为REPE,用在CMPS、SCAS指令前,每执行一次串指令CX减1,并判断ZF标志是否为0
;只要CX=0或ZF=0,则重复执行结束
REPNZ ;也可以表达为REPNE,用在CMPS、SCAS指令前,每执行一次串操作指令CX减1,并判断ZF标志是否为1,只要CX=0或ZF=1,则重复执行结束。
串扫描指令SCAS
SCASB ;字节串扫描:AL-ES:[DI],DI←DI+/-1
SCASW ;字串扫描:AX-ES:[DI],DI←DI+/-2
串扫描指令SCAS将附加段中的字节或字内容与AL/AX寄存器内容进行比较,根据比较的结果设置标志,每次比较后修改DI寄存器的值,使之指向下一个元素。
解释:
假设esp+10指向字符串如:"xqiang",长度为6,以0结尾
ecx=FFFFFFFF
eax=0,则al=0
执行repne scas时候:
第一次:
al-'x',di=di-1,即byte ptr es:[edi]指向'q',并置相应的标志位
然后cx-1,则ecx=FFFFFFFE,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第二次:
al-'q',di=di-1,即byte ptr es:[edi]指向'i',并置相应的标志位
然后cx-1,则ecx=FFFFFFFD,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第三次:
al-'i',di=di-1,即byte ptr es:[edi]指向'a',并置相应的标志位
然后cx-1,则ecx=FFFFFFFC,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第三次:
al-'a',di=di-1,即byte ptr es:[edi]指向'n',并置相应的标志位
然后cx-1,则ecx=FFFFFFFB,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第四次:
al-'n',di=di-1,即byte ptr es:[edi]指向'g',并置相应的标志位
然后cx-1,则ecx=FFFFFFFA,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第五次:
al-'g',di=di-1,即byte ptr es:[edi]指向'0',并置相应的标志位
然后cx-1,则ecx=FFFFFFF9,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第六次:
al-0,di=di-1,即byte ptr es:[edi]指向'未知字符',并置相应的标志位
然后cx-1,则ecx=FFFFFFF8,判断是否cx=0或ZF=1,此时ZF=1,停止串搜索
现在ecx从FFFFFFFF到FFFFFFF8记录了字符串'xqiang'和0的长度
然后not ecx得到ecx=00000007
dec ecx得到ecx=00000006 该长度就是字符串'xqiang'的实际长度
这里的 "串" 并不单指字符串, 包括所有连续的数据(如数组); 串指令只用于内存操作.
移动串指令: MOVSB、MOVSW、MOVSD ;从 ESI -> EDI; 执行后, ESI 与 EDI 的地址移动相应的单位 比较串指令: CMPSB、CMPSW、CMPSD ;比较 ESI、EDI; 执行后, ESI 与 EDI 的地址移动相应的单位 扫描串指令: SCASB、SCASW、SCASD ;依据 AL/AX/EAX 中的数据扫描 EDI 指向的数据, 执行后 EDI 自动变化 储存串指令: STOSB、STOSW、STOSD ;将 AL/AX/EAX 中的数据储存到 EDI 给出的地址, 执行后 EDI 自动变化 载入串指令: LODSB、LODSW、LODSD ;将 ESI 指向的数据载入到 AL/AX/EAX, 执行后 ESI 自动变化 其中的 B、W、D 分别指 Byte、Word、DWord, 表示每次操作的数据的大小单位. 上述指令可以有重复前缀: REP ECX > 0 时 REPE (或 REPZ) ECX > 0 且 ZF=1 时 REPNE(或 REPNZ) ECX > 0 且 ZF=0 时 ;重复前缀可以自动按单位(1、2、4)递减 ECX
MOVSB: 移动字符串
; Test29_1.asm .386 .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data szSource db 'Delphi 2010', 0 len equ $ - szSource - 1 szDest db len dup(?), 0 .code main proc lea esi, szSource lea edi, szDest mov ecx, len cld ;复位标志寄存器的方向标志, 以让串地址由低到高 rep movsb PrintString szDest ;Delphi 2010 ret main endp end main
上面的例子, 假如不使用重复前缀...
; Test29_2.asm .386 .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data szSource db 'Delphi 2010', 0 len equ $ - szSource - 1 szDest db len dup(?), 0 .code main proc lea esi, szSource lea edi, szDest mov ecx, len cld @@: movsb dec ecx jnz @B PrintString szDest ret main endp end main
MOVSD 例:
; Test29_3.asm .386 .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data ddSource dd 11h,22h,33h ddDest dd lengthof ddSource dup(?) .code main proc lea esi, ddSource lea edi, ddDest mov ecx, lengthof ddSource cld rep movsd DumpMem offset ddDest, sizeof ddDest ;11 00 00 00 - 22 00 00 00 - 33 00 00 00 ret main endp end main
MOVSW 例:
; Test29_4.asm .386 .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data ddSource dw 11h,22h,33h ddDest dw lengthof ddSource dup(?) .code main proc lea esi, ddSource lea edi, ddDest mov ecx, lengthof ddSource cld rep movsw DumpMem offset ddDest, sizeof ddDest ;11 00 22 00 - 33 00 00 00 ret main endp end main
CMPSD 例:
; Test29_5.asm .386p .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data ddVal1 dd 1234h ddVal2 dd 5678h .code main proc lea esi, ddVal1 lea edi, ddVal2 cmpsd je L1 PrintText '两数不等' jmp L2 L1: PrintText '两数相等' L2: ret main endp end main
CMPSW 例:
; Test29_6.asm .386p .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data dwArr1 dw 1,2,3,4,5 dwArr2 dw 1,3,5,7,9 .code main proc lea esi, dwArr1 lea edi, dwArr2 mov ecx, lengthof dwArr1 cld repe cmpsw je L1 PrintText '两数组不等' jmp L2 L1: PrintText '两数组相等' L2: ret main endp end main
对比数组时, 假如数组长度不一致...
; Test29_7.asm .386p .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data dwArr1 dw 1,2,3,4,5 dwArr2 dw 1,2,3,4,5,6 .code main proc lea esi, dwArr1 lea edi, dwArr2 mov ecx, lengthof dwArr1 cmp ecx, lengthof dwArr2 jne L1 cld repe cmpsw jne L1 PrintText '两数组相等' jmp L2 L1: PrintText '两数组不等' L2: ret main endp end main
如果对比的是 0 结束的字符串, 长度不一致也不用考虑
; Test29_8.asm .386p .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data szText1 db 'Delphi 2010', 0 szText2 db 'Delphi 2011', 0 .code main proc lea esi, szText1 lea edi, szText2 mov ecx, lengthof szText1 cld repe cmpsb je L1 PrintText '字符串不同' jmp L2 L1: PrintText '字符串相同' L2: ret main endp end main
SCASB 例:
; Test29_9.asm .386p .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data szText db 'ABCDEFGH', 0 .code main proc lea edi, szText mov al, 'F' mov ecx, lengthof szText - 1 cld repne scasb je L1 PrintText '没找到' jmp L2 L1: sub ecx, lengthof szText - 1 neg ecx PrintDec ecx ;如果找得到, 这里显示是第几个字符; 本例结果是 6 L2: ret main endp end main
STOSB 例:
; Test29_10.asm .386p .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data len = 31 szText db len dup(0), 0 .code main proc lea edi, szText mov al, 'x' mov ecx, len cld rep stosb PrintString szText ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ret main endp end main
LODSW 例: 数组求和
; Test29_11.asm .386p .model flat, stdcall include windows.inc include kernel32.inc include masm32.inc include debug.inc includelib kernel32.lib includelib masm32.lib includelib debug.lib .data dwArr dw 1,2,3,4,5,6,7,8,9,10 .code main proc lea esi, dwArr mov ecx, lengthof dwArr xor edx, edx xor eax, eax @@: lodsw add edx, eax loop @B PrintDec edx ;55 ret main endp end main