![Assembly Programming Tutorial](/assembly_programming/images/assembly-mini-logo.jpg)
汇编 - 字符串
我们已经在之前的示例中使用了变长字符串。变长字符串可以包含任意数量的字符。通常,我们通过以下两种方式之一指定字符串的长度:
- 显式存储字符串长度
- 使用哨兵字符
我们可以使用表示当前位置计数器值的 $ 位置计数器符号显式存储字符串长度。在下面的示例中:
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 寄存器。
下表提供了字符串指令的各种版本以及操作数的假设空间。
基本指令 | 操作数位于 | 字节操作 | 字操作 | 双字操作 |
---|---|---|---|---|
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 减至零时停止。