汇编 - 字符串

我们之前的示例中已经使用了可变长度字符串.可变长度字符串可以包含所需的字符数.通常,我们通过两种方式之一指定字符串的长度 :

  • 显式存储字符串长度

  • 使用标记字符

我们可以使用表示位置当前值的$ 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寄存器.

下表提供了各种版本的字符串指令和操作数的假定空间.

基本指令操作数字节操作字操作双字操作
MOVSES:DI ,DS:SIMOVSBMOVSWMOVSD
LODSAX,DS:SILODSBLODSWLODSD
STOSES:DI,AXSTOSBSTOSWSTOSD
CMPSDS:SI,ES:DICMPSBCMPSWCMPSD
SCASES:DI,AXSCASBSCASWSCASD

重复前缀

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递减为零时停止.