字符串(Strings)
我们在前面的例子中已经使用了可变长度字符串。 可变长度字符串可以包含所需的字符数。 通常,我们通过两种方式之一指定字符串的长度 -
- 显式存储字符串长度
- Using a sentinel character
我们可以使用$ 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字符的字符串来分隔字符串,而不是显式地存储字符串长度。 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前缀还具有以下变体:
记者:这是无条件的重复。 它重复操作直到CX为零。
REPE或REPZ:有条件重复。 它重复操作,而零标志指示等于/零。 当ZF指示不等于/零或CX为零时停止。
REPNE或REPNZ:这也是有条件的重复。 它在零标志指示不等于/零时重复该操作。 当ZF指示等于/零或CX递减为零时停止。