我们之前的示例中已经使用了可变长度字符串.可变长度字符串可以包含所需的字符数.通常,我们通过两种方式之一指定字符串的长度 :
显式存储字符串长度
使用标记字符
我们可以使用表示位置当前值的$ location计数器符号显式存储字符串长度计数器.在下面的例子中 :
msg db 'Hello, world!',0xa ;our dear string len equ $ - msg ;length of our dear string
$指向字符串变量 msg 的最后一个字符后的字节.因此, $ - msg 给出字符串的长度.我们也可以写
msg db 'Hello, world!',0xa ;our dear string len equ 13 ;length of our dear string
或者,您可以存储带有尾随哨兵字符的字符串来分隔字符串,而不是显式地存储字符串长度. sentinel字符应该是一个不会出现在字符串中的特殊字符.
例如 :
message DB 'I am loving it!', 0
每个字符串指令可能需要一个源操作数,目标操作数或两者.对于32位段,字符串指令使用ESI和EDI寄存器分别指向源和目标操作数.
但对于16位段,SI和DI寄存器是用于分别指向源和目标.
处理字符串有五个基本指令.它们是 :
MOVS : 该指令将1字节,字或双字数据从内存位置移动到另一个.
LODS : 该指令从内存加载.如果操作数是一个字节,则将其加载到AL寄存器中,如果操作数是一个字,则将其加载到AX寄存器中,并将双字加载到EAX寄存器中.
STOS : 该指令将寄存器(AL,AX或EAX)中的数据存储到存储器中.
CMPS : 该指令比较内存中的两个数据项.数据可以是字节大小,字或双字.
SCAS : 该指令将寄存器(AL,AX或EAX)的内容与内存中项目的内容进行比较.
每个上面的指令有一个字节,字和双字版本,字符串指令可以使用重复前缀重复.
这些指令使用ES:DI和DS:SI寄存器对,其中DI和SI寄存器包含有效的偏移地址,它指的是存储在存储器中的字节. SI通常与DS(数据段)相关联,DI始终与ES(额外段)相关联.
DS:SI(或ESI)和ES:DI(或EDI)寄存器分别指向源操作数和目标操作数.假设源操作数位于DS:SI(或ESI),ES中的目标操作数:内存中的DI(或EDI).
对于16位地址,SI和使用DI寄存器,对于32位地址,使用ESI和EDI寄存器.
下表提供了各种版本的字符串指令和操作数的假定空间.
基本指令 | 操作数 | 字节操作 | 字操作 | 双字操作 |
---|---|---|---|---|
MOVS | ES:DI ,DS:SI | MOVSB | MOVSW | MOVSD |
LODS | AX,DS:SI | LODSB | LODSW | LODSD |
STOS | ES:DI,AX | STOSB | STOSW | STOSD |
CMPS | DS:SI,ES:DI | CMPSB | CMPSW | CMPSD |
SCAS | ES:DI,AX | SCASB | SCASW | SCASD |
REP前缀,当在字符串指令之前设置时,例如 - REP MOVSB,导致基于放置在CX寄存器的计数器重复指令. REP执行指令,将CX减1,并检查CX是否为零.它重复指令处理直到CX为零.
方向标志(DF)确定操作的方向.
使用CLD(清除方向标志,DF = 0)使操作从左向右.
使用STD(设置方向标志,DF = 1)进行操作从右到左的操作.
REP前缀也有以下变化:
REP:这是无条件重复.它重复操作直到CX为零.
REPE或REPZ:这是条件重复.它重复操作,而零标志指示等于/零.当ZF表示不等于/零或CX为零时停止.
REPNE或REPNZ:它也是条件重复.它在零标志指示不等于/零时重复该操作.当ZF指示等于/零或者CX递减为零时停止.