汇编语言 字符串
在前面的实例中,我们已经使用了可变长度字符串。可变长度字符串可以包含所需的任意多个字符。
通常,我们通过以下两种方法之一指定字符串的长度:
- 显式存储字符串长度
- 使用哨兵字符
我们可以使用表示位置计数器当前值的 $location
计数器符号来显式存储字符串长度。
在以下实例中:
msg db 'Hello, world!',0xa ;我们常见的字符
len equ $ - msg ;长度
$指向字符串变量 msg
的最后一个字符之后的字节。因此,$ - msg
给出字符串的长度。我们也可以这样写:
msg db 'Hello, world!',0xa ;字符串
len equ 13 ;字符串的长度
另外,您可以存储带有尾部定点字符的字符串来定界字符串,而不是显式存储字符串长度。前哨字符应为不出现在字符串中的特殊字符。
例如,
message DB 'I am loving it!', 0
字符串指令
每个字符串指令可能需要一个源操作数,一个目标操作数或两者。对于 32 位段,字符串指令使用 ESI
和 EDI
寄存器分别指向源和目标操作数。但是,对于 16 位段,SI
和 DI
寄存器分别用于指向源和目标。
有 5 种用于处理字符串的基本说明。他们是:
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 是否为 0。重复指令处理,直到 CX 为 0 为止。
方向标志(DF)确定操作的方向。
- 使用 CLD(清除方向标志,DF = 0)使操作从左到右。
- 使用 STD(设置方向标志,DF = 1)使操作从右到左。
REP
前缀也有以下变化:
- REP: 这是无条件的重复。重复该操作,直到 CX 为零为止。
- REPE 或 REPZ: 这是有条件的重复。当零标志指示等于/零时,它将重复操作。当 ZF 表示不等于 0 或 CX 为 0 时,它将停止。
- REPNE 或 REPNZ: 这也是有条件的重复。当零标志指示不等于/ 0 时,它将重复操作。当 ZF 指示等于/ 0 或 CX 减为 0 时,它将停止。