第九章 字符串和数组

9.2 基本字符串操作指令

32 位模式中,下表中的每条指令都隐含使用 ESI、EDI,或是同时使用这两个寄存器来寻址内存。

 

 

指令说明
MOVSB、MOVSW、MOVSD 传送字符串数据:将 ESI 寻址的内存数据复制到 EDI 寻址的内存位置
CMPSB、CMPSW、CMPSD 比较字符串:比较分别由 ESI 和 EDI 寻址的内存数据
SCASB、SCASW、SCASD 扫描字符串:比较累加器 (AL、AX 或 EAX) 与 EDI 寻址的内存数据
STOSB、STOSW、STOSD 保存字符串数据:将累加器内容保存到 EDI 寻址的内存位置
LODSB、LODSW、LODSD 从字符串加载到累加器:将 ESI 寻址的内存数据加载到累加器

使用重复前缀

就其自身而言,字符串基本指令只能处理一个或一对内存数值。如果加上重复前缀,指令就可以用 ECX 作计数器重复执行。重复前缀使得单条指令能够处理整个数组。下面为可用的重复前缀:

 

REP ECX > 0 时重复
REPZ、REPE 零标志位置 1 且 ECX > 0 时重复
REPNZ、REPNE 零标志位清零且 ECX > 0 时重复

TITLE testprogram

INCLUDE Irvine32.inc

.data
Array1 BYTE "Hello World!",0
Array2 BYTE 13 DUP(?)

.code
main PROC
    mov esi,OFFSET Array1
    mov edi,OFFSET Array2
    mov ecx,SIZEOF Array1
    REP MOVSB
    mov edx,OFFSET Array2
    call WriteString
    call Crlf
    call WaitMsg
    exit
main ENDP
END main

方向标志位

根据方向标志位的状态,字符串基本青令增加或减少 ESI 和 EDI 如下表所示。可以用 CLD 和 STD 指令显式修改方向标志位:

CLD ;方向标志位清零(正向)
STD ;方向标志位置 1(反向)

 

 

方向标志位的值对ESI和EDI的影响地址顺序
0 增加 低到高
1 减少 高到低

 

9.2.1 MOVSB,MOVSW和MOVSD指令

MOVSB、MOVSW 和 MOVSD 指令将数据从 ESI 指向的内存位置复制到 EDI 指向的内存位置。(根据方向标志位的值)这两个寄存器自动地增加或减少:

MOVSB 传送(复制)字节
MOVSW  传送(复制)字
MOVSD 传送(复制)双字


MOVSB、MOVSW 和 MOVSD 可以使用重复前缀。方向标志位决定 ESI 和 EDI 是否增加或减少。增加 / 减少的量如下表所示:

 

指令 ESI 和 EDI 增加或减少的数值
MOVSB 1
MOVSW 2
MOVSD 4

 

 

.data
source DWORD 20 DUP(OFFFFFFFFh)
target DWORD 20 DUP(?)
.code
cld                     ;方向为正向
mov ecx,LENGTHOF source ;设置 REP 计数器
mov esi,OFFSET source   ;ES工指向 source
mov edi,OFFSET target   ;ED工指向 target
rep novsd               ;复制双字

 

9.2.2 CMPSB,CMPSW和CMPSD指令

.data
source DWORD 1234h
target DWORD 5678h
.code
mov esi,OFFSET source
mov edi,OFFSET target
cmpsd                 ;比较双字
ja L1                 ;若 source > target 则跳转

 

mov esi,OFFSET source
mov edi,OFFSET target
cld                       ;方向为正向
mov ecx,LENGTHOF source   ;设置重复计数器
repe cmpsd                ;相等则重复

 

应该强调一下,只有在两个字符串相等的条件下,使用CMPSB指令比较两个字符串才是可行的。(不足,自行填充空格)

 

9.2.3 SCASB,SCASW和SCASD指令

.data
alpha BYTE "ABCDEFGH",0
.code
mov edi,OFFSET alpha        ;ED工指向字符串
mov al, 'F'                 ;检索字符F
mov ecx,LENGTHOF alpha      ;设置检索计数器
cld                         ;方向为正向
repne seasb                 ;不相等则重复
jnz quit                    ;若未发现字符则退出
dec edi                     ;发现字符:EDI 减 1

 

9.2.4 STOSB,STOSW和STOSD指令

与 REP 前缀组合使用时,这些指令实现用同一个值填充字符串或数组的全部元素。例如,下面的代码就把 string1 中的每一个字节都初始化为 OFFh:

.data
Count = 100
string1 BYTE Count DUP(?)
.code
mov al, OFFh              ;要保存的数值
mov edi,OFFSET string1       ;ED:[指向目标字符串
mov ecx,Count              ;字符计数器
cld                          ;方向为正向
rep stosb                  ;用 AL 的内容实现填充

 

9.2.5 LODSB ,LODSW和LODSD指令

【示例】数组乘法,下面的程序把一个双字数组中的每个元素都乘以同一个常数。程序同时 使用了 LODSD 和 STOSD:

;数组乘法    (Mult.asm)
;本程序将一个32位整数数组中的每个元素都乘以一个常数。
INCLUDE Irvine32.inc
.data
array DWORD 1,2,3,4,5,6,7,8,9,10    ;测试数据
mug" 0W0RD -10
.code

main PROC
    cld                             ;方向为正向
    mov esi,OFFSET array            ;源数组索引
    itqv edi,esi                    ;目标数组索引
    mov ecx,LENGTHOF array          ;循环计数器
L1: lodsd                           ;将 [ESI] 加载到 EAX
mul multiplier                      ;与常数相乘
stosd                               ;将 EAX 保存到[EDI]
loop L1
exit
main ENDP
END main

 

posted @ 2019-11-11 16:02  Hk_Mayfly  阅读(200)  评论(0编辑  收藏  举报