字符串操作指令包括:
movs 字符串传送
cmps 字符串比较
scas 字符串扫描
stos 存入字符串
lods 从字符串取
指令前缀
rep 重复
repe 相等则重复
repz 结果为0则重复,与repe等价
repne 不相等则重复
repnz 结果不为0则重复,与repne完全等价
单独的字符串指令表示执行一次字符串操作,加了指令前缀的字符串指令表示重复执行字符串操作
字符串传送指令 movsb movsw movs
[rep] movsb;以字节为单位传送字符串
;movsb
;byte ptr es:[di]=byte ptr ds:[si]
;if df==0 si++ di++;正方向
;else si-- di--;反方向
;rep movsb
again:
if cx==0
goto done
else
byte ptr es:[di]=byte ptr ds:[si]
if df==0 si++ di++
else si-- di--
cx--
goto again
;注意,是先赋值,然后++,
[rep] movsw;以字为单位传送字符串,类似
不过里面的si,di+2
[rep ] movs byte ptr es:[di],byte ptr seg:[si]
;类似上面的movsb,但这里区别就是源段地址寄存器不只是ds可以任意指定,当然也可以都是es
[rep ]movs word ptr es:[di],word ptr seg:[si]
字符串比较指令:cmpsb,cmpsw,cmps
[repe|repne]cmpsb;以字节为单位比较字符串
;cmpsb
;null=byte ptr ds:[si]-byte ptr es:[di]比较ds:[si]与es:[di]
;temp=fl
;if df==0 si++ di++
;else si-- id--
;endif,fl=temp
;repe cmpsb
again:
if cx==0
goto done
else
{
null=byte ptr ds:[si]-byte ptr es:[di]
temp=fl
;if df==0 si++ di++
;else si-- id--
cx=cx-1
fl=temp
if zf==1;若两者不相等,那么就不循环了,就可以直接得出两个字符串不一样
goto agaim
}
;继续下次比较的条件是cx!=0,zf=1
;repne cmpsb
;与repe唯一区别就是 if zf==0 goto again
;若两者相等,就不继续比较,只有不相等才继续循环
;继续下次比较的条件是zf=0,cx!=0
repe cmpsb 等价于repz cmpsb
repne cmpsb等价于repnz cmpsb
;注意,cmp与mov指令都会在结束后指向下一个字符,他们总是现为下次做好准备,然后才判断本次比较是否相等
[repe|repne ]cmpsw;以字为单位比较
[repe|repne ]cmps byte ptr seg:[si],byte ptr es:[di]
[repe|repne ]cmps word ptr seg:[si],word ptr es:[di]
字符串扫描指令 scasb,scasw
[repe|repne] scasb;在字符串中查找一个字符
scasb
;null=al-byte ptr es:[di];比较al与byte ptr es:[di]
;temp=fl
;if(df==0) di++ else di--
;fl=temp
repe scasb
;again:
;if(cx==0)
;goto done'
else{
null=al-byte ptr es:[di]
temp=fl
if (df==0)di++ else di--
cx--
fl=temp
if(zf==1)
goto again
done:
}
repne scasb
;与上面的位移区别就是判断zf==0
repe scasb要求本次扫描相等才进行下次扫描,而repne scasb要求本次扫描不相等才进行下次扫描
;格式
scasb
repe scasb ;等价于 repz scasb
repne scasb ;等价于repnz scasb
例子:求一个字符串长度,(该字符串以00h结束),长度不包括结束字符串
mov ax,1000h
mov es,ax
mov di 10a0h;es:di指向目标首字符
movv cx,0ffffh;最多查找65535次
mov al,00h;带查找字符
cld;df==0,正向
repne scasb;因为之前循环的条件都是不相等,所以用repne
;指令结束时,由于repne内部实现的机理,di指向的是00h后面的一个字节
dec di;这个时候才指向的是00h
sub di,10a0h
mov cx,di;字符串的长度
;;注意,字符串扫描指令同字符串比较,总是先为下次扫描作准备,然后才判断本次扫描是否相等
[repe|repne] scasw;在字符串中查找一个字
scasw
null=ax-word ptr es:[di];比较ax和es:[di]
temp=fl
if df==0 di+2 else di-2
fl=temp
;类似于scasb,只不过al换成ax,byte ptr换成word ptr,di++换成di+2
存入字符串指令stosb,stosw
[rep]stosb;存入字节到字符串
;stosb操作
byte ptr es:[di]=al
if(df==0)di++ else di--
;rep stosb操作
again:
if(cx==0) done
else{
byte ptr es:[di]=al
if (df==0) di++ else di--
cx--
goto again
}
其实比较像我们在定义数据段200 dup(0)
ex:用存入字符串指令按照正方向填100个0
mov ax,1000h
mov es,ax
mov di,10a0h
mov cx,100h
mov al,0
cld
rep stosb
[rep] stosw
类似,只不过word ptr es:[di]=ax,di+2或di-2
从字符串读取字节或字指令 lodsb,lodsw,lods
lodsb;从字符串读取字节
;操作
al=byte ptr ds:[si]
if(df==0) si++ else si--
例子:设存放了old red cracker字符串,长度为15字节额,把除空格意外复制到2000:20f0中
mov ax,1000h
mov ds,ax
mov ax,2000h
mov es,ax
mov si 10A0h
mov di,20f0h
mov cx,15
cld
again:
lodsb;al=ds:[si]并且si++
cmp al,' '
je next
stosb;es:[di]=al,并且di++指向下一个储存的位置
next:
dec cx
jnz again
lodsw
;操作类似,不过是ax=word ptr ds:[si],si+2或si-2
lods byte ptr seg:[si]
;区别就是seg可以是cs,es,ds,ss任意一个
lods word ptr seg:[asi]
;同上