串操作
- 串操作指令
- 串方向
- 重复前缀

;=================================||
- movsb
- 功能:
- mov string
- 将si地址的内容拷贝到di地址
- DF=0(up)
- si<-si+1
- di<-di+1
- DF=1(DN)
- si<-si-1
- di<-di-1
;=================================
- movsw
- 功能:
- mov string
- 将si地址的内容拷贝到di地址
- DF=0(up)
- si<-si+2
- di<-di+2
- DF=1(DN)
- si<-si-2
- di<-di-2
;=================================||
- stosb
- 功能
- store string
- 将al或者ax内存存储到di地址
- (dl)<-al
- DF=0(up)
- di<-di+1
- DF=1(DN)
- di<-di-1
;=================================
- stosw
- 功能
- store string
- 将al或者ax内存存储到di地址
- (di)<-ax
- DF=0(up)
- di<-di+2
- DF=1(DN)
- di<-di-2
;=================================||
- lodsb
- 功能
- load string
- 将si地址内容读入al或ax
- al<-(si)
- DF=0(up)
- si<-si+1
- DF=1(DN)
- si<-si-1
;=================================
- lodsw
- 功能
- load string
- 将si地址内容读入al或ax
- ax<-(si)
- DF=0(up)
- si<-si+2
- DF=1(DN)
- si<-si-2
;=================================||
- cmpsb
- 功能
- cmp string
- si地址内容减去di地址内容,不存储结果,影响标志位
- (si)-(di)
- DF=0(up)
- si<-si+1
- di<-di+1
- DF=1(DN)
- si<-si-1
- di<-di-1
;=================================
- cmpsw
- 功能
- cmp string
- si地址内容减去di地址内容,不存储结果,影响标志位
- (si)-(di)
- DF=0(up)
- si<-si+2
- di<-di+2
- DF=1(DN)
- si<-si-2
- di<-di-2
;=================================||
- scasb
- 功能
- scan string
- al减去di地址内容,不存储结果,影响标志位
- al-(di)或者ax-(di)
- DF=0(up)
- di<-di+1
- DF=1(DN)
- di<-di-1
;=================================
- scas2
- 功能
- scan string
- ax减去di地址内容,不存储结果,影响标志位
- al-(di)或者ax-(di)
- DF=0(up)
- di<-di+2
- DF=1(DN)
- di<-di-2
;=================================||
- 串方向
- CLD ;DF置0,自动加
- STD ;DF置1,自动减

cmpsb示例:
data segmentg_szSrc db "hello world$"g_szDst db "heLL"data endsstack segment stackdw 20h dup(?)top label wordstack endscode segmentassume ds:data,cs:code,ss:stackp proc farmov ax,datamov ds,axmov ax,stackmov ss,axlea sp,top;=====================================;为es赋值mov ax,dsmov es,axlea si,g_szSrc;lea di,g_szDstCLDcmpsbcmpsbcmpsbcmpsbp endpcode endsend p
执行2次
下一次就是对比l和L了,再次执行
标志位改变,但是源数据不变
重复前缀
- 重复前缀
- 串操作指令一般都配合重复前缀使用,实现内存批量操作。
- 注意(下图的loads应该是lods)

- repne:重复执行器后面的指令,CX或ECX存放最多比较次数,DI或EDI存放查找表首地址,AL或AX或EAX存放想要查找的内容。当(CX或ECX)=0或ZF=1退出重复。否则,(CX或ECX)自动减一,执行其后面的串指令。CX或ECX为0结束是因为已经查表完毕,没有匹配到;ZF=1说明“比较的结果为0”,也就是查找到一样的内容,说明匹配到了想要查找的内容。
movs和rep的配对示例
data segmentg_szSrc db "hello world$"g_szDst db 255 dup(00)g_szDst0 db "heLL"data endsstack segment stackdw 20h dup(?)top label wordstack endscode segmentassume ds:data,cs:code,ss:stackp proc farmov ax,datamov ds,axmov ax,stackmov ss,axlea sp,top;=====================================;为es赋值mov ax,dsmov es,axlea si,g_szSrc;mov ax,offset g_szSrclea di,g_szDstCLDmov cx,offset g_szDst - offset g_szSrcrep movsbxor ax,axp endpcode endsend p
流程转移指令
- 无条件跳转
- 条件跳转
- LOOP
- 无条件跳转
段内跳转示例:
data segmentg_szSrc db "hello world$"g_szDst db 255 dup(00)g_szDst0 db "heLL"data endsstack segment stackdw 20h dup(?)top label wordstack endscode segmentassume ds:data,cs:code,ss:stackp proc farmov ax,datamov ds,axmov ax,stackmov ss,axlea sp,top;=====================================jmp LABEL1mov ax,axLABEL1:jmp LABEL2mov bx,bxLABEL2:mov ah,4chint 21hp endpcode endsend p
段间跳转示例:
data segmentg_szSrc db "hello world$"g_szDst db 255 dup(00)g_szDst0 db "heLL"data endsstack segment stackdw 20h dup(?)top label wordstack endscode_seg2 segmentLABELT:mov si,simov ah,4chint 21hcode_seg2 endscode segmentassume ds:data,cs:code,ss:stackp proc farmov ax,datamov ds,axmov ax,stackmov ss,axlea sp,top;=====================================jmp far ptr LABELTmov ah,4chint 21hp endpcode endsend p
- 指令偏移计算
- 指令中的偏移值是下一条指令到目的地址的偏移

- 指令偏移计算练习

- 120h-102h-2h = 1c -> EB 1C (后面的-2h,是根据120h-102h可以很明显得到该跳转指令短跳就可以了,因此该jmp指令2字节的机器码就够了,因此是键2h,后面同理)
- 320h-102h=21Eh 很明显一个字节是存不下的,因此应当时3字节机器码的近跳转。21Eh-3h = 21B 所以机器码应该是 E9 1B 02
- 0020h-0102h=ff1eh,很明显再减去2h肯定不够一个字节的存放,因此应该是三字节的近跳 ,ff13h-3h=ff1bh E9 1B FF
- E9 FB FC
- …
- 使用寄存器间接转移

示例:
data segmentg_szSrc db "hello world$"g_szDst db 255 dup(00)g_szDst0 db "heLL"data endsstack segment stackdw 20h dup(?)top label wordstack endscode segmentassume ds:data,cs:code,ss:stackp proc farmov ax,datamov ds,axmov ax,stackmov ss,axlea sp,top;=====================================lea ax,LABEL2jmp axmov ax,axLABEL2:xor ax,axmov ah,4chint 21hp endpcode endsend p
- 使用EA的间接转移

条件跳转
- 条件跳转
- 依据标志位判断,条件成立则跳转,条件不成立则不跳。
- 单条件跳转

- 有符号数判断

- 无符号数判断

作业
1、SCASB指令的作用是什么?叙述指令REPE SCASB指令所完成的功能。
scasb:al减去di地址内容,不存储结果,影响标志位.al-(di)或者ax-(di).
- repen是重复执行指令。
- scas是用来搜索字符
- 一些标志位参数:
- DF:方向
- CX:索要搜索的串的长度
- AX:索要搜索的数据
- DI:要搜索的那条串
用法1:
- 计算字符串的长度
;需要将di指向所搜索的那条字符串mov cx,FFFF;设置循环次数,这里用于计算字符串的长度所以设置为最大xor ax,ax ;将ax置0 字符串以\0结尾时cld ;将DF置0repne scasb;开始搜索neg cx ;得到cx所减的次数dec cx ;长度不包括\0
- 计算字符串的长度
检测代码中的一些特殊指令(如断点,花指令,以及一些反调试代码)
2、指令REPNE SCASB结束执行的条件是什么?
CX=0或ZF=1;
3、REP前缀的作用是什么?能用指令REP LODSB读取DS:SI所指内存中的每个字符来进行处理吗?若不能,请说明原因。
重复执行后面的指令,不能,因为其只是重复执行将数据传送到al或ax而已,该指令并不能对字符的数据进行处理。
7、从键盘输入文件名,查找指定文件(不超过255)中是否含有字母B。
;======================================;======================================data segmentdata segmentFileNameFuf db 100,?,100 dup(0)TheFile db 100 dup(0)file db 'test.txt',0buf db 100 dup(?)fh dw ?error_msg db 0dh,0ah,'error!','$'success_msg db 0dh,0ah,'done!','$'FindSuccess_msg db 0dh,0ah,'FinhisAlpabet!','$'FindFaile_msg db 0dh,0ah,'NotFinhisAlpabet!','$'data ends;======================================;======================================stack segmentstack segment stackdw 20h dup(?)top label wordstack ends;======================================;======================================code segmentcode segmentassume ds:data,cs:code,ss:stackstart:;=========================================INITmov ax,datamov ds,axmov ax,stackmov ss,axlea sp,top;=========================================code todo;输入文件名lea dx,FileNameFufmov ah,0ah ;键盘输入字符串到缓冲区int 21hxor cx,cxxor al,alcopy:lea bx,FileNameFufadd bx,2add bx,cxmov al,[bx]cmp al,0dhje endcopymov si,cxlea bx,TheFilemov ds:[bx+si],alcmp cx,100je endcopyinc cxjmp copyendcopy:;lea dx,file;open filelea dx,TheFilemov al,0mov ah,3dhint 21hjc errormov fh,ax;read filelea dx,bufmov cx,100mov bx,fhmov ah,3fhint 21hjc error;计算字符串的有效长度lea ax,buf ;ax为传入参数,strlen_dollarcall strlen_dollar;查找字符'B',传到ax返回数组下标,没有找到返回-1mov al,'B'lea dx,bufcall My_FindAlphabet_al;开始判断是否找到字符cmp ax,-1je FaileFindAlphabetjmp FindAlphabetIsSuccessjmp exit;====================================================error:lea dx,error_msgmov ah,09hint 21h;=========================================FindAlphabetIsSuccess:lea dx,FindSuccess_msgmov ah,09hint 21hjmp exit;=========================================FaileFindAlphabet:lea dx,FindFaile_msgmov ah,09hint 21hjmp exit;=========================================exit:mov ah,4chint 21h;====================================================My_strlen_dollar;ax存放字符串长度带出子程序 以$结尾的字符串 di所指的那条字符串,;注意!串操作di默认es 需要提前将ds指向需要操作的段,内部自动同步es为ds所指向的偏移地址strlen_dollar:push cx;需要将es:di指向所搜索的那条字符串mov di,axmov ax,dsmov es,axmov cx,0FFFFh;设置循环次数,这里用于计算字符串的长度所以设置为最大xor ax,ax ;将ax置0mov al,'$'-1add al,1h ;为了将ZF标志位置0cld ;将DF置0repne scasb;开始搜索not cx ;得到cx所减的次数dec cx ;长度不包括$mov ax,cxpop cxret;====================================================;My_Find_al al输入所要查找的字符,dx指向查找字符串的偏移地址,ax将结果带出My_FindAlphabet_al:push cx;需要将es:di指向所搜索的那条字符串mov di,dxmov dx,dsmov es,dxmov cx,0FFFeh;设置循环次数,这里用于计算字符串的长度所以设置为最大add cx,1h ;为了将ZF标志位置0cld ;将DF置0repne scasb;开始搜索not cx ;得到cx所减的次数dec cx ;长度不包括$mov ax,cxpop cxret;====================================================code endsend start
9、程序中定义一个数组(不超过255),从键盘输入一个字符和长度,将数组中输入长度的部分设置成输入的字符。
10、使用条件转移,模拟c语言的if-else for do-while while
assume ds:datadata segmentg_a word 00g_i word 00data ends//if-else; int a = 8;; if (a > 9) {; a++;; }; else {; a--;; }mov word ptr [g_a],8cmp word ptr [g_a],9jle labifmov ax,word ptr [g_a]add ax,1mov word ptr [g_a],axjmp LabIfElseEndlabNoif:mov ax,word ptr [g_a]sub ax,1mov word ptr [g_a],ax;==================================================================; //while; while (a>0); {; a--;; }LabIfElseEnd:LabWhileStart:cmp word ptr [g_a],0jle LabWhileEndmov ax,word ptr [g_a]sub ax,1mov word ptr [g_a],axjmp LabWhileStart;==================================================================; //do-while; do; {; a ++;; } while (a<9);LabWhileEnd:LabDoWhileStart:mov ax,word ptr [g_a]add ax,1mov word ptr [g_a],axcmp word ptr [g_a],9jl LabDoWhileStart;==================================================================; //for; for (int i = 0; i < 5; i++) {; a++;; }mov word ptr [g_i],0jmp LabForInitEndmov ax,word ptr [g_i]add ax,1mov word ptr [g_i],axcmp word ptr [g_i],5jge LabForEndmov ax,word ptr [g_a]add ax,1mov word ptr [g_a],eaxLabForEnd:
11、从键盘输入字符串,比较两个字符串是否相等
;======================================;======================================data segmentdata segmentCmpBuf1 db 100,?,100 dup('$')CmpBuf2 db 100,?,100 dup('$')fh dw ?error_msg db 0dh,0ah,'error!','$'success_msg db 0dh,0ah,'done!','$'StrEqual_mes db 0dh,0ah,'str1 and str2 is equal!','$'StrNotEqual_msg db 0dh,0ah,'str1 and str2 is not equal!','$'data ends;======================================;======================================stack segmentstack segment stackdw 20h dup(?)top label wordstack ends;======================================;======================================code segmentcode segmentassume ds:data,cs:code,ss:stackstart:;=========================================INITmov ax,datamov ds,axmov ax,stackmov ss,axlea sp,top;=========================================code todo;输入字符串lea dx,CmpBuf1mov ah,0ah ;键盘输入字符串到缓冲区int 21hlea dx,CmpBuf2mov ah,0ah ;键盘输入字符串到缓冲区int 21h;计算字符串的有效长度lea ax,CmpBuf1 ;ax为传入参数,strlen_dollaradd ax,2call strlen_dollarpush axlea ax,CmpBuf2add ax,2call strlen_dollarpop dxcmp ax,dxjne strNotEqual ;两字符串有效长度相等才有比较意义;============xor ax,axmov ax,seg CmpBuf1push ax ;076chmov ax,offset CmpBuf1add ax,2push ax ;2hmov ax,seg CmpBuf2push ax ;076chmov ax,offset CmpBuf2add ax,2 ;0068hpush ax;ds sp+ah ,si sp+8 ,es sp+6 ,di sp+4;使用将对比字符串 ds:si es:di 进行入栈操作call My_CmpStrFunctioncmp ax,1je strEqualjmp strNotEqual;====================================================error:lea dx,error_msgmov ah,09hint 21h;=========================================strEqual:lea dx,StrEqual_mesmov ah,09hjmp exitstrNotEqual:lea dx,StrNotEqual_msgmov ah,09hjmp exit;=========================================exit:mov ah,4chint 21h;====================================================My_strlen_dollar;ax存放字符串长度带出子程序 以$结尾的字符串 di所指的那条字符串,;注意!串操作di默认es 需要提前将ds指向需要操作的段,内部自动同步es为ds所指向的偏移地址strlen_dollar:push cx;需要将es:di指向所搜索的那条字符串mov di,axmov ax,dsmov es,axmov cx,0FFFFh;设置循环次数,这里用于计算字符串的长度所以设置为最大xor ax,ax ;将ax置0mov al,'$'-1add al,1h ;为了将ZF标志位置0cld ;将DF置0repne scasb;开始搜索not cx ;得到cx所减的次数dec cx ;长度不包括$mov ax,cxpop cxret;====================================================;My_Find_al al输入所要查找的字符,dx指向查找字符串的偏移地址,ax将结果带出My_FindAlphabet_al:push cx;需要将es:di指向所搜索的那条字符串mov di,dxmov dx,dsmov es,dxmov cx,0FFFeh;设置循环次数,这里用于计算字符串的长度所以设置为最大add cx,1h ;为了将ZF标志位置0cld ;将DF置0repne scasb;开始搜索not cx ;得到cx所减的次数dec cx ;长度不包括$mov ax,cxpop cxret;====================================================;ds sp+ah ,si sp+8 ,es sp+6 ,di sp+4;使用将对比字符串 ds:si es:di 进行入栈操作My_CmpStrFunction:mov bx,spmov ax,ss:[bx+2]mov di,axmov ax,ss:[bx+4]mov es,axmov ax,ss:[bx+6]mov si,axmov ax,ss:[bx+8]mov ds,axCLDrepz cmpsb ;当前字符相同则继续循环je Equalmov ax,0 ;ax=0,不相等retEqual:mov ax,1 ;ax=1,相等ret;====================================================code endsend start
12、从键盘输入一个字符串,用来填充程序内部一个255的缓冲区
13、从键盘输入字符串,对字符串中所有字符转小写,然后输出
14、从键盘输入字符串,将所有的字符正反颠倒,然后输出。
