组装 - 琴弦
我们在前面的示例中已经使用了可变长度字符串。可变长度字符串可以包含所需数量的字符。通常,我们通过两种方式之一指定字符串的长度 -
- 显式存储字符串长度
- 使用哨兵角色
我们可以使用 $ 位置计数器符号来显式存储字符串长度,该符号表示位置计数器的当前值。在下面的例子中 -
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
或者,您可以存储带有尾随哨兵字符的字符串来分隔字符串,而不是显式存储字符串长度。哨兵字符应该是不会出现在字符串中的特殊字符。
例如 -
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寄存器。
下表提供了各种版本的字符串指令和假定的操作数空间。
基本说明 | 操作数位于 | 字节操作 | 字操作 | 双字运算 |
---|---|---|---|---|
金属氧化物半导体 | ES:DI,DS:SI | 金属氧化物半导体场效应晶体管 | 金属氧化物半导体开关 | MOVSD |
细节层次 | AX、DS:SI | LODSB | 低密度开关 | LODSD |
斯托斯 | 电子:DI、AX | STOSB | STOSW | STOSD |
CMPS | DS:SI,ES:DI | CMPSB | CMPSW | CMPSD |
斯卡斯特 | 电子:DI、AX | 科学与技术学院 | 南加州妇女协会 | 计算机辅助设计系统 |
重复前缀
当在字符串指令之前设置 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 递减至零时,它停止。