汇编语言---字符串操作指令
字符串操作指令的实质是对一片连续的存储单元进行处理,这片连续的存储单元由隐含指针DS:SI或ES:DI来指定;字符串操作指令可对内存单元按照字节、字、双字进行处理,并能根据操作对象的字节数使变址寄存器SI/DI增加或减少1、2、4字节;
规定如下:
A.当DF=0时,变址寄存器SI/DI增加1、2、4字节;即:变址寄存器SI/DI递增的步长可以是1、2、4字节;
B.当DF=1时,变址寄存器SI/DI减少1、2、4字节;即:变址寄存器SI/DI递减的步长可以是1、2、4字节;
一、取字符串数据指令(Load String Instruction)
从指针DI:SI所指定的内存单元开始,取一个字节/字/双字,然后存入到AL/AX/EAX中,并根据标志位DF的值对寄存器SI做相应的增减;把存放字符串数据的连续存储区当做是数据源,使用寄存器SI;
该指令的执行不会影响任何标志位;
指令格式: LODS 地址表达式
LODSB/LODSW 地址表达式
LODS 地址表达式 ;80386+
在指令LODS中,它会根据"地址表达式"的属性来决定读取一个字节、字或双字;即:当该地址表达式的属性为字节、字或双字时,将从指针DI:SI处读取一个字节到AL中,或读取一个字到AX中,或读取一个双字到EAX中,与此同时,SI还将分别增减1、2、4字节;
取字符串数据指令的功能示意图如下图所示:
![汇编语言---字符串操作指令 - 哥哥 - 哥哥](http://www.feiesoft.com/asm/05-15.gif)
二、置字符串数据指令(Store String Instruction)
该指令把寄存器AL/AX/EAX中的值存入指针ES:DI所指向内存单元开始的一片存储单元中,并根据标志位DF的值对寄存器DI做相应的增减;把存放字符串的连续存储区当做是数据的目的地,使用寄存器DI;
该指令的执行并不会影响任何标志位;
指令格式: STOS 地址表达式
STOSB/STOSW 地址表达式
STOSD 地址表达式 ;80386+
置字符串数据指令的功能示意图如下图所示:
![汇编语言---字符串操作指令 - 哥哥 - 哥哥](http://www.feiesoft.com/asm/05-16.gif)
三、字符串传送指令(Move String Instruction)
该指令把指针DS:SI所指向的字节、字或双字传送给指针ES:DI所指向的内存单元,并根据标志位DF的值对寄存器DI和SI分别作相应的增减;
该指令的执行并不会影响任何标志位;
指令格式: MOVS 地址表达式1,地址表达式2
MOVSB/MOVSW 地址表达式1,地址表达式2
MOVSD 地址表达式1,地址表达式2 ;80386+
字符串传送指令的功能示意图如下图所示:
![汇编语言---字符串操作指令 - 哥哥 - 哥哥](http://www.feiesoft.com/asm/05-17.gif)
该指令是从某一指定端口接受一个字符串,并存入到一片连续的存储单元中;输入端口由寄存器DX指定,存储单元的首地址由指针ES:DI来确定,读入的数据个数由寄存器CX来确定;在指令的执行过程中,还要根据标志位DF的值来对寄存器DI做相应的增减;把存放字符串的连续存储区当做是数据的目的地;
该指令不会影响任何标志位;
与指令有关的操作数ES、DI、DX和CX等都是隐含操作数;
指令格式: INS 地址表达式
INSB/INSW 地址表达式
INSD 地址表达式 ;80386+
五、字符串输出指令(Output String Instruction)
该指令是把一个给定的字符串输出到一个指定的端口中;输出端口由通用寄存器DX指定,输出数据的首地址由指针DS:SI确定,输出数据的个数由计数寄存器CX来确定;在指令执行的过程中,还要根据方向标志DF的值来对变址寄存器SI做相应的增减;
该指令的执行并不会影响任何标志位;
与指令有关的操作数DS、SI、DX和CX等都是隐含操作数;
指令格式: OUTS 地址表达式
OUTSB/OUTSW 地址表达式
OUTSD 地址表达式 ;80386+
六、字符串比较指令(Compare String Instruction)
该指令是把指针DS:SI所指向的字节、字、双字的值与指针ES:DI所指向的字节、字、双字的值相减,并用所得到的差来设置相关标志位;与此同时,变址寄存器SI和DI也将根据方向标志位DF的值做相应的增减;
指令格式: CMPS 地址表达式1,地址表达式2
CMPSB/CMPSW 地址表达式1,地址表达式2
CMPSD 地址表达式1,地址表达式2 ;80386+
受影响的标志位: AF,CF,OF,PF,SF,ZF
字符串比较指令的功能示意图如下图所示:
![汇编语言---字符串操作指令 - 哥哥 - 哥哥](http://www.feiesoft.com/asm/05-18.gif)
七、字符串扫描指令(Scan String Instruction)
该指令是用指针ES:DI所指向字节/字/双字的值与相应的AL/AX/EAX的值相减,并依据所得到的差值来设置相关标志位;与此同时,变址寄存器DI还将根据方向标志DF的值来做相应的增减;
指令格式: SCAS 地址表达式
SCASB/SCASW 地址表达式
SCASD 地址表达式 ;80386+
受影响的标志位: AF,CF,OF,PF,SF,ZF
字符串扫描指令的功能示意图如下图所示:
![汇编语言---字符串操作指令 - 哥哥 - 哥哥](http://www.feiesoft.com/asm/05-19.gif)
八、重复字符串操作指令(Repeat String Instruction)
前面的字符串操作指令:取字符串数据、置字符串数据、字符串传送、输入字符串、输出字符串、字符串比较、字符串扫描,等指令,都是执行一次所具有的功能;但是,每个字符串通常都是由多个字符组成的,所以,需要重复执行这些字符串操作指令;为了满足这种需要,指令系统提供了一组重复前缀指令;
虽然在这些字符串指令的前面都可以添加一个重复前缀指令,但是由于指令执行结果的差异,对某个具体的字符串指令又不用重复前缀指令而改用其它循环来实现重复的需要;
重复字符串操作指令对标志位的影响是由被重复的字符串操作指令来决定;
1.重复前缀指令REP(Repeat String Instruction)
重复前缀指令是重复其后指定的字符串操作指令,重复的次数由计数寄存器CX来决定;
指令格式:
REP LODS/LODSB/LODSW/LODSD
REP STOS/STOSB/STOSW/STOSD
REP MOVS/MOVSB/MOVSW/MOVSD
REP INS/INSB/INSW/INSD
REP OUTS/OUTSB/OUTSW/OUTSD
重复前缀指令的执行步骤如下:
STEP1:判断: CX=0
STEP2:如果CX=0,则结束重复操作,执行程序中的下一条指令;
STEP3:否则,CX=CX-1(不影响相关标志位),并执行重复前缀指令后面指定的字符串操作指令,在该指令执行完后,再转到步骤STEP1;
从上面的重复前缀指令格式来看,虽然我们可以使用重复前缀指令来重复取字符串数据指令(第一组指令),但是可能会因为指令的执行结果而在程序中几乎不会使用;
例如:编写一段程序,计算字符串"12345abcdefg"中各个字符的ASCII之和;
解:
......
MESS DB '12345abcdefg' ;在数据段进行变量说明
......
MOV AX,SEG MESS
MOV DS,AX
LEA SI,MESS ;用DS:SI来指向字符串的首地址;
MOV CX,13D ;重复次数
XOR BX,BX ;置求和的初值为0
REP LODSB ;循环去处字符;
......
从程序片段中看,虽然"REP LODSB"能从字符串中逐一取出每个字符,但这个操作是在同一条指令中完成的,程序的其它指令根本无法处理每次取出的字符数据,指令的执行结果是:AL中只保存了最后一次取出的字符'h'的ASCII码;
所以,为了实现本例的要求,不能使用重复前缀指令,而要把指令"REP LODSB"改写成如下四条指令:
XOR AH,AH ;为后面的累加做准备
AGAIN:LODSB
ADD BX,AX ;AL是被取出的字符,AH已被清0
LOOP AGAIN
2.条件重复前缀指令(Repeat String Conditionally)
条件重复前缀指令与重复前缀指令的功能相似,所不同的是:条件重复前缀指令中的重复次数不仅由CX来决定,而且还会由标志位ZF的值来决定;根据ZF所起的作用又可分为两种:相等重复前缀指令和不等重复前缀指令;
A.相等重复前缀指令:
指令格式:
REPE/REPZ SCAS/SCASB/SCASW/SCASD
REPE/REPZ CMPS/CMPSB/CMPSW/CMPSD
该重复前缀指令的执行步骤如下:
STEP1:判断条件: CX!=0 且 ZF=1
STEP2:如果条件不成立,则结束重复操作,执行程序中的下一条指令;
STEP3:否则,CX=CX-1(不影响任何标志位),并执行重复前缀指令后面指定的字符串操作指令,在该指令执行后,再转到步骤STEP1;
B.不等重复前缀指令:
指令格式:
REPNE/REPNZ SCAS/SCASB/SCASW/SCASD
REPNE/REPNZ CMPS/CMPSB/CMPSW/CMPSD
该重复前缀指令的执行步骤如下:
STEP1:判断条件:CX!=0 且 ZF=0
STEP2:如果条件不成立,则结束重复操作,执行程序中的下一条指令;
STEP3:否则,CX=CX-1(不影响任何标志位),并执行重复前缀指令后面指定的字符串操作指令,在该指令执行完后,再转到步骤STEP1;