串操作

  1. 串操作指令
  2. 串方向
  3. 重复前缀

image.png
;=================================||

  • 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,自动减

image.png

cmpsb示例:

  1. data segment
  2. g_szSrc db "hello world$"
  3. g_szDst db "heLL"
  4. data ends
  5. stack segment stack
  6. dw 20h dup(?)
  7. top label word
  8. stack ends
  9. code segment
  10. assume ds:data,cs:code,ss:stack
  11. p proc far
  12. mov ax,data
  13. mov ds,ax
  14. mov ax,stack
  15. mov ss,ax
  16. lea sp,top
  17. ;=====================================
  18. ;为es赋值
  19. mov ax,ds
  20. mov es,ax
  21. lea si,g_szSrc;
  22. lea di,g_szDst
  23. CLD
  24. cmpsb
  25. cmpsb
  26. cmpsb
  27. cmpsb
  28. p endp
  29. code ends
  30. end p

执行2次
image.png
下一次就是对比l和L了,再次执行
image.png
标志位改变,但是源数据不变

重复前缀

  • 重复前缀
    • 串操作指令一般都配合重复前缀使用,实现内存批量操作。
  • 注意(下图的loads应该是lods)
  • image.png
  • repne:重复执行器后面的指令,CX或ECX存放最多比较次数,DI或EDI存放查找表首地址,AL或AX或EAX存放想要查找的内容。当(CX或ECX)=0或ZF=1退出重复。否则,(CX或ECX)自动减一,执行其后面的串指令。CX或ECX为0结束是因为已经查表完毕,没有匹配到;ZF=1说明“比较的结果为0”,也就是查找到一样的内容,说明匹配到了想要查找的内容。

movs和rep的配对示例

  1. data segment
  2. g_szSrc db "hello world$"
  3. g_szDst db 255 dup(00)
  4. g_szDst0 db "heLL"
  5. data ends
  6. stack segment stack
  7. dw 20h dup(?)
  8. top label word
  9. stack ends
  10. code segment
  11. assume ds:data,cs:code,ss:stack
  12. p proc far
  13. mov ax,data
  14. mov ds,ax
  15. mov ax,stack
  16. mov ss,ax
  17. lea sp,top
  18. ;=====================================
  19. ;为es赋值
  20. mov ax,ds
  21. mov es,ax
  22. lea si,g_szSrc;mov ax,offset g_szSrc
  23. lea di,g_szDst
  24. CLD
  25. mov cx,offset g_szDst - offset g_szSrc
  26. rep movsb
  27. xor ax,ax
  28. p endp
  29. code ends
  30. end p

流程转移指令

  1. 无条件跳转
  2. 条件跳转
  3. LOOP
  1. 无条件跳转

image.png段内跳转示例:

  1. data segment
  2. g_szSrc db "hello world$"
  3. g_szDst db 255 dup(00)
  4. g_szDst0 db "heLL"
  5. data ends
  6. stack segment stack
  7. dw 20h dup(?)
  8. top label word
  9. stack ends
  10. code segment
  11. assume ds:data,cs:code,ss:stack
  12. p proc far
  13. mov ax,data
  14. mov ds,ax
  15. mov ax,stack
  16. mov ss,ax
  17. lea sp,top
  18. ;=====================================
  19. jmp LABEL1
  20. mov ax,ax
  21. LABEL1:
  22. jmp LABEL2
  23. mov bx,bx
  24. LABEL2:
  25. mov ah,4ch
  26. int 21h
  27. p endp
  28. code ends
  29. end p

段间跳转示例:

  1. data segment
  2. g_szSrc db "hello world$"
  3. g_szDst db 255 dup(00)
  4. g_szDst0 db "heLL"
  5. data ends
  6. stack segment stack
  7. dw 20h dup(?)
  8. top label word
  9. stack ends
  10. code_seg2 segment
  11. LABELT:
  12. mov si,si
  13. mov ah,4ch
  14. int 21h
  15. code_seg2 ends
  16. code segment
  17. assume ds:data,cs:code,ss:stack
  18. p proc far
  19. mov ax,data
  20. mov ds,ax
  21. mov ax,stack
  22. mov ss,ax
  23. lea sp,top
  24. ;=====================================
  25. jmp far ptr LABELT
  26. mov ah,4ch
  27. int 21h
  28. p endp
  29. code ends
  30. end p
  • 指令偏移计算
    • 指令中的偏移值是下一条指令到目的地址的偏移

image.png

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

image.png
示例:

  1. data segment
  2. g_szSrc db "hello world$"
  3. g_szDst db 255 dup(00)
  4. g_szDst0 db "heLL"
  5. data ends
  6. stack segment stack
  7. dw 20h dup(?)
  8. top label word
  9. stack ends
  10. code segment
  11. assume ds:data,cs:code,ss:stack
  12. p proc far
  13. mov ax,data
  14. mov ds,ax
  15. mov ax,stack
  16. mov ss,ax
  17. lea sp,top
  18. ;=====================================
  19. lea ax,LABEL2
  20. jmp ax
  21. mov ax,ax
  22. LABEL2:
  23. xor ax,ax
  24. mov ah,4ch
  25. int 21h
  26. p endp
  27. code ends
  28. end p
  • 使用EA的间接转移

image.png

条件跳转

  • 条件跳转
    • 依据标志位判断,条件成立则跳转,条件不成立则不跳。
  • 单条件跳转
  • image.png
  • 有符号数判断
  • image.png
  • 无符号数判断
  • image.png

作业

1、SCASB指令的作用是什么?叙述指令REPE SCASB指令所完成的功能。
scasb:al减去di地址内容,不存储结果,影响标志位.al-(di)或者ax-(di).

  • repen是重复执行指令。
  • scas是用来搜索字符
  • 一些标志位参数:
    • DF:方向
    • CX:索要搜索的串的长度
    • AX:索要搜索的数据
    • DI:要搜索的那条串
  • 用法1:

    • 计算字符串的长度
      1. ;需要将di指向所搜索的那条字符串
      2. mov cx,FFFF;设置循环次数,这里用于计算字符串的长度所以设置为最大
      3. xor ax,ax ;将ax0 字符串以\0结尾时
      4. cld ;将DF0
      5. repne scasb;开始搜索
      6. neg cx ;得到cx所减的次数
      7. dec cx ;长度不包括\0
  • 检测代码中的一些特殊指令(如断点,花指令,以及一些反调试代码)

2、指令REPNE SCASB结束执行的条件是什么?
CX=0或ZF=1;
3、REP前缀的作用是什么?能用指令REP LODSB读取DS:SI所指内存中的每个字符来进行处理吗?若不能,请说明原因。
重复执行后面的指令,不能,因为其只是重复执行将数据传送到al或ax而已,该指令并不能对字符的数据进行处理。
7、从键盘输入文件名,查找指定文件(不超过255)中是否含有字母B。

  1. ;======================================;======================================data segment
  2. data segment
  3. FileNameFuf db 100,?,100 dup(0)
  4. TheFile db 100 dup(0)
  5. file db 'test.txt',0
  6. buf db 100 dup(?)
  7. fh dw ?
  8. error_msg db 0dh,0ah,'error!','$'
  9. success_msg db 0dh,0ah,'done!','$'
  10. FindSuccess_msg db 0dh,0ah,'FinhisAlpabet!','$'
  11. FindFaile_msg db 0dh,0ah,'NotFinhisAlpabet!','$'
  12. data ends
  13. ;======================================;======================================stack segment
  14. stack segment stack
  15. dw 20h dup(?)
  16. top label word
  17. stack ends
  18. ;======================================;======================================code segment
  19. code segment
  20. assume ds:data,cs:code,ss:stack
  21. start:
  22. ;=========================================INIT
  23. mov ax,data
  24. mov ds,ax
  25. mov ax,stack
  26. mov ss,ax
  27. lea sp,top
  28. ;=========================================code todo
  29. ;输入文件名
  30. lea dx,FileNameFuf
  31. mov ah,0ah ;键盘输入字符串到缓冲区
  32. int 21h
  33. xor cx,cx
  34. xor al,al
  35. copy:
  36. lea bx,FileNameFuf
  37. add bx,2
  38. add bx,cx
  39. mov al,[bx]
  40. cmp al,0dh
  41. je endcopy
  42. mov si,cx
  43. lea bx,TheFile
  44. mov ds:[bx+si],al
  45. cmp cx,100
  46. je endcopy
  47. inc cx
  48. jmp copy
  49. endcopy:
  50. ;
  51. lea dx,file
  52. ;open file
  53. lea dx,TheFile
  54. mov al,0
  55. mov ah,3dh
  56. int 21h
  57. jc error
  58. mov fh,ax
  59. ;read file
  60. lea dx,buf
  61. mov cx,100
  62. mov bx,fh
  63. mov ah,3fh
  64. int 21h
  65. jc error
  66. ;计算字符串的有效长度
  67. lea ax,buf ;ax为传入参数,strlen_dollar
  68. call strlen_dollar
  69. ;查找字符'B',传到ax返回数组下标,没有找到返回-1
  70. mov al,'B'
  71. lea dx,buf
  72. call My_FindAlphabet_al
  73. ;开始判断是否找到字符
  74. cmp ax,-1
  75. je FaileFindAlphabet
  76. jmp FindAlphabetIsSuccess
  77. jmp exit
  78. ;====================================================
  79. error:
  80. lea dx,error_msg
  81. mov ah,09h
  82. int 21h
  83. ;=========================================
  84. FindAlphabetIsSuccess:
  85. lea dx,FindSuccess_msg
  86. mov ah,09h
  87. int 21h
  88. jmp exit
  89. ;=========================================
  90. FaileFindAlphabet:
  91. lea dx,FindFaile_msg
  92. mov ah,09h
  93. int 21h
  94. jmp exit
  95. ;=========================================
  96. exit:
  97. mov ah,4ch
  98. int 21h
  99. ;====================================================My_strlen_dollar
  100. ;ax存放字符串长度带出子程序 $结尾的字符串 di所指的那条字符串,
  101. ;注意!串操作di默认es 需要提前将ds指向需要操作的段,内部自动同步esds所指向的偏移地址
  102. strlen_dollar:
  103. push cx
  104. ;需要将es:di指向所搜索的那条字符串
  105. mov di,ax
  106. mov ax,ds
  107. mov es,ax
  108. mov cx,0FFFFh;设置循环次数,这里用于计算字符串的长度所以设置为最大
  109. xor ax,ax ;将ax0
  110. mov al,'$'-1
  111. add al,1h ;为了将ZF标志位置0
  112. cld ;将DF0
  113. repne scasb;开始搜索
  114. not cx ;得到cx所减的次数
  115. dec cx ;长度不包括$
  116. mov ax,cx
  117. pop cx
  118. ret
  119. ;====================================================
  120. ;My_Find_al al输入所要查找的字符,dx指向查找字符串的偏移地址,ax将结果带出
  121. My_FindAlphabet_al:
  122. push cx
  123. ;需要将es:di指向所搜索的那条字符串
  124. mov di,dx
  125. mov dx,ds
  126. mov es,dx
  127. mov cx,0FFFeh;设置循环次数,这里用于计算字符串的长度所以设置为最大
  128. add cx,1h ;为了将ZF标志位置0
  129. cld ;将DF0
  130. repne scasb;开始搜索
  131. not cx ;得到cx所减的次数
  132. dec cx ;长度不包括$
  133. mov ax,cx
  134. pop cx
  135. ret
  136. ;====================================================
  137. code ends
  138. end start

9、程序中定义一个数组(不超过255),从键盘输入一个字符和长度,将数组中输入长度的部分设置成输入的字符。
10、使用条件转移,模拟c语言的if-else for do-while while

  1. assume ds:data
  2. data segment
  3. g_a word 00
  4. g_i word 00
  5. data ends
  6. //if-else
  7. ; int a = 8;
  8. ; if (a > 9) {
  9. ; a++;
  10. ; }
  11. ; else {
  12. ; a--;
  13. ; }
  14. mov word ptr [g_a],8
  15. cmp word ptr [g_a],9
  16. jle labif
  17. mov ax,word ptr [g_a]
  18. add ax,1
  19. mov word ptr [g_a],ax
  20. jmp LabIfElseEnd
  21. labNoif:
  22. mov ax,word ptr [g_a]
  23. sub ax,1
  24. mov word ptr [g_a],ax
  25. ;==================================================================
  26. ; //while
  27. ; while (a>0)
  28. ; {
  29. ; a--;
  30. ; }
  31. LabIfElseEnd:
  32. LabWhileStart:
  33. cmp word ptr [g_a],0
  34. jle LabWhileEnd
  35. mov ax,word ptr [g_a]
  36. sub ax,1
  37. mov word ptr [g_a],ax
  38. jmp LabWhileStart
  39. ;==================================================================
  40. ; //do-while
  41. ; do
  42. ; {
  43. ; a ++;
  44. ; } while (a<9);
  45. LabWhileEnd:
  46. LabDoWhileStart:
  47. mov ax,word ptr [g_a]
  48. add ax,1
  49. mov word ptr [g_a],ax
  50. cmp word ptr [g_a],9
  51. jl LabDoWhileStart
  52. ;==================================================================
  53. ; //for
  54. ; for (int i = 0; i < 5; i++) {
  55. ; a++;
  56. ; }
  57. mov word ptr [g_i],0
  58. jmp LabForInitEnd
  59. mov ax,word ptr [g_i]
  60. add ax,1
  61. mov word ptr [g_i],ax
  62. cmp word ptr [g_i],5
  63. jge LabForEnd
  64. mov ax,word ptr [g_a]
  65. add ax,1
  66. mov word ptr [g_a],eax
  67. LabForEnd:

11、从键盘输入字符串,比较两个字符串是否相等

  1. ;======================================;======================================data segment
  2. data segment
  3. CmpBuf1 db 100,?,100 dup('$')
  4. CmpBuf2 db 100,?,100 dup('$')
  5. fh dw ?
  6. error_msg db 0dh,0ah,'error!','$'
  7. success_msg db 0dh,0ah,'done!','$'
  8. StrEqual_mes db 0dh,0ah,'str1 and str2 is equal!','$'
  9. StrNotEqual_msg db 0dh,0ah,'str1 and str2 is not equal!','$'
  10. data ends
  11. ;======================================;======================================stack segment
  12. stack segment stack
  13. dw 20h dup(?)
  14. top label word
  15. stack ends
  16. ;======================================;======================================code segment
  17. code segment
  18. assume ds:data,cs:code,ss:stack
  19. start:
  20. ;=========================================INIT
  21. mov ax,data
  22. mov ds,ax
  23. mov ax,stack
  24. mov ss,ax
  25. lea sp,top
  26. ;=========================================code todo
  27. ;输入字符串
  28. lea dx,CmpBuf1
  29. mov ah,0ah ;键盘输入字符串到缓冲区
  30. int 21h
  31. lea dx,CmpBuf2
  32. mov ah,0ah ;键盘输入字符串到缓冲区
  33. int 21h
  34. ;计算字符串的有效长度
  35. lea ax,CmpBuf1 ;ax为传入参数,strlen_dollar
  36. add ax,2
  37. call strlen_dollar
  38. push ax
  39. lea ax,CmpBuf2
  40. add ax,2
  41. call strlen_dollar
  42. pop dx
  43. cmp ax,dx
  44. jne strNotEqual ;两字符串有效长度相等才有比较意义
  45. ;============
  46. xor ax,ax
  47. mov ax,seg CmpBuf1
  48. push ax ;076ch
  49. mov ax,offset CmpBuf1
  50. add ax,2
  51. push ax ;2h
  52. mov ax,seg CmpBuf2
  53. push ax ;076ch
  54. mov ax,offset CmpBuf2
  55. add ax,2 ;0068h
  56. push ax
  57. ;ds sp+ah ,si sp+8 ,es sp+6 ,di sp+4
  58. ;使用将对比字符串 ds:si es:di 进行入栈操作
  59. call My_CmpStrFunction
  60. cmp ax,1
  61. je strEqual
  62. jmp strNotEqual
  63. ;====================================================
  64. error:
  65. lea dx,error_msg
  66. mov ah,09h
  67. int 21h
  68. ;=========================================
  69. strEqual:
  70. lea dx,StrEqual_mes
  71. mov ah,09h
  72. jmp exit
  73. strNotEqual:
  74. lea dx,StrNotEqual_msg
  75. mov ah,09h
  76. jmp exit
  77. ;=========================================
  78. exit:
  79. mov ah,4ch
  80. int 21h
  81. ;====================================================My_strlen_dollar
  82. ;ax存放字符串长度带出子程序 $结尾的字符串 di所指的那条字符串,
  83. ;注意!串操作di默认es 需要提前将ds指向需要操作的段,内部自动同步esds所指向的偏移地址
  84. strlen_dollar:
  85. push cx
  86. ;需要将es:di指向所搜索的那条字符串
  87. mov di,ax
  88. mov ax,ds
  89. mov es,ax
  90. mov cx,0FFFFh;设置循环次数,这里用于计算字符串的长度所以设置为最大
  91. xor ax,ax ;将ax0
  92. mov al,'$'-1
  93. add al,1h ;为了将ZF标志位置0
  94. cld ;将DF0
  95. repne scasb;开始搜索
  96. not cx ;得到cx所减的次数
  97. dec cx ;长度不包括$
  98. mov ax,cx
  99. pop cx
  100. ret
  101. ;====================================================
  102. ;My_Find_al al输入所要查找的字符,dx指向查找字符串的偏移地址,ax将结果带出
  103. My_FindAlphabet_al:
  104. push cx
  105. ;需要将es:di指向所搜索的那条字符串
  106. mov di,dx
  107. mov dx,ds
  108. mov es,dx
  109. mov cx,0FFFeh;设置循环次数,这里用于计算字符串的长度所以设置为最大
  110. add cx,1h ;为了将ZF标志位置0
  111. cld ;将DF0
  112. repne scasb;开始搜索
  113. not cx ;得到cx所减的次数
  114. dec cx ;长度不包括$
  115. mov ax,cx
  116. pop cx
  117. ret
  118. ;====================================================
  119. ;ds sp+ah ,si sp+8 ,es sp+6 ,di sp+4
  120. ;使用将对比字符串 ds:si es:di 进行入栈操作
  121. My_CmpStrFunction:
  122. mov bx,sp
  123. mov ax,ss:[bx+2]
  124. mov di,ax
  125. mov ax,ss:[bx+4]
  126. mov es,ax
  127. mov ax,ss:[bx+6]
  128. mov si,ax
  129. mov ax,ss:[bx+8]
  130. mov ds,ax
  131. CLD
  132. repz cmpsb ;当前字符相同则继续循环
  133. je Equal
  134. mov ax,0 ;ax=0,不相等
  135. ret
  136. Equal:
  137. mov ax,1 ;ax=1,相等
  138. ret
  139. ;====================================================
  140. code ends
  141. end start

12、从键盘输入一个字符串,用来填充程序内部一个255的缓冲区
13、从键盘输入字符串,对字符串中所有字符转小写,然后输出
14、从键盘输入字符串,将所有的字符正反颠倒,然后输出。