Win32汇编其他指令(4)

た 入场券 2021-12-11 05:13 528阅读 0赞

title: Win32汇编其他指令(4)
date: 2019-04-19 10:09:50
tags:

  • 汇编语言
    categories: 汇编语言
    copyright: true
    -—

汇编语言(assembly language)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言.在汇编语言中,用助记符(Mnemonics)代替机器指令的操作码,用地址符号(Symbol)或标号(Label)代替指令或操作数的地址.在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令,普遍地说,特定的汇编语言和特定的机器语言指令集是相互对应的,不同平台之间不可直接移植.

字串操作指令

移动串指令: MOVSB、MOVSW、MOVSD ;从 ESI -> EDI; 执行后, ESI 与 EDI 的地址移动相应的单位
比较串指令: CMPSB、CMPSW、CMPSD ;比较 ESI、EDI; 执行后, ESI 与 EDI 的地址移动相应的单位
扫描串指令: SCASB、SCASW、SCASD ;依据 AL/AX/EAX 中的数据扫描 EDI 指向的数据, 执行后 EDI 自动变化
储存串指令: STOSB、STOSW、STOSD ;将 AL/AX/EAX 中的数据储存到 EDI 给出的地址, 执行后 EDI 自动变化
载入串指令: LODSB、LODSW、LODSD ;将 ESI 指向的数据载入到 AL/AX/EAX, 执行后 ESI 自动变化
其中的 B、W、D 分别指 Byte、Word、DWord, 表示每次操作的数据的大小单位.

上述指令可以有重复前缀:
REP ECX > 0 时
REPE (或 REPZ) ECX > 0 且 ZF=1 时
REPNE(或 REPNZ) ECX > 0 且 ZF=0 时
;重复前缀可以自动按单位(1、2、4)递减 ECX

字符串复制(movsb):

  1. .data
  2. string1 db "hello lyshark",0 ; 原始字符串
  3. str_len equ $ - string1 -1 ; 计算出原始字符串长度
  4. string2 db str_len dup(?),0 ; 目标内存地址
  5. .code
  6. main PROC
  7. cld ; 清除方向标志
  8. mov esi,offset string1 ; 取源字符串内存地址
  9. mov edi,offset string2 ; 取目标字符串内存地址
  10. mov ecx,str_len ; 指定循环次数,为原字符串长度
  11. rep movsb ; 逐字节复制,直到ecx=0为止
  12. ret
  13. main ENDP
  14. END main

另一种字串复制(movsb): 不使用rep重复前缀的方式完成字串复制.

  1. .data
  2. string1 db "hello lyshark",0 ; 原始字符串
  3. str_len equ $ - string1 -1 ; 计算出原始字符串长度
  4. string2 db str_len dup(?),0 ; 目标内存地址
  5. .code
  6. main PROC
  7. lea esi,string1 ; string1的地址
  8. lea edi,string2 ; string2的地址
  9. mov ecx,str_len ; 取字符串长度,用于循环
  10. cld ; 方向->正向
  11. @@: movsb ; 每次复制一个字节BYTE
  12. dec ecx ; 每次ecx减一
  13. jnz @B ; 如果ecx不为0则循环
  14. ret
  15. main ENDP
  16. END main

(movsd)四字节复制字串:

  1. .data
  2. ddSource DWORD 10h,20h,30h ; 定义三个四字节数据
  3. ddDest DWORD lengthof ddSource dup(?) ; 得到目标地址
  4. .code
  5. main PROC
  6. lea esi,ddSource
  7. lea edi,ddDest
  8. mov ecx,lengthof ddSource
  9. cld
  10. rep movsd
  11. ret
  12. main ENDP
  13. END main

CMPSB:

  1. .data
  2. Text1 db "hello lyshark",0
  3. Text2 db "hello lyshar1",0
  4. .code
  5. main PROC
  6. lea esi,Text1
  7. lea edi,Text2
  8. mov ecx,lengthof Text1
  9. cld
  10. repe cmpsb
  11. je L1
  12. xor eax,eax ; 字串不同则清空eax
  13. jmp L2
  14. L1: xor ebx,ebx ; 字串相同则清空ebx
  15. L2: ret
  16. main ENDP
  17. END main

CMPSD: 比对两个双字数据是否相等.

  1. .data
  2. var1 DWORD 1234h
  3. var2 DWORD 5678h
  4. .code
  5. main PROC
  6. lea esi,var1
  7. lea edi,var2
  8. cmpsd
  9. je L1
  10. xor eax,eax ; 两数如果相等则清空eax
  11. jmp L2
  12. L1: xor ebx,ebx ; 两数不相等则清空ebx
  13. L2: ret
  14. main ENDP
  15. END main

CMPSW:

  1. .data
  2. Array1 WORD 1,2,3,4,5 ; 必须全部相等才会清空ebx
  3. Array2 WORD 1,3,5,7,9
  4. .code
  5. main PROC
  6. lea esi,Array1
  7. lea edi,Array2
  8. mov ecx,lengthof Array1
  9. cld
  10. repe cmpsw
  11. je L1
  12. xor eax,eax ; 两数不相等则清空eax
  13. jmp L2
  14. L1: xor ebx,ebx ; 两数相等则清空ebx
  15. L2: ret
  16. main ENDP
  17. END main

SCASB 扫描字串: 依据 AL/AX/EAX 中的数据扫描 EDI 指向的数据, 执行后 EDI 自动变化

  1. .data
  2. szText BYTE "ABCDEFGHIJK",0
  3. .code
  4. main PROC
  5. lea edi,szText
  6. mov al,"F"
  7. mov ecx,lengthof szText -1
  8. cld
  9. repne scasb ; 如果不相等则重复
  10. je L1
  11. xor eax,eax ; 如果没找到F则清空eax
  12. jmp L2
  13. L1: sub ecx,lengthof szText -1
  14. neg ecx ; 如果找得到, 这里显示是第几个字符; 本例结果是 6
  15. L2: ret
  16. main ENDP
  17. END main

STOSB 存储字串: 将 AL/AX/EAX 中的数据储存到 EDI 给出的地址, 执行后 EDI 自动变化

  1. .data
  2. len = 10
  3. szText db len dup(0),0
  4. .code
  5. main PROC
  6. lea edi,szText ; EDI指向字符串
  7. mov al,"W" ; 定义查找字母为W
  8. mov ecx,len ; 设置查找计数器
  9. cld ; 方向=正向
  10. rep stosb ; ecx>0则执行
  11. ret
  12. main ENDP
  13. END main

LODSW 载入指令: 将 ESI 指向的数据载入到 AL/AX/EAX, 执行后 ESI 自动变化,如下是累加求和

  1. .data
  2. Array WORD 1,2,3,4,5,6,7,8,9,10
  3. .code
  4. main PROC
  5. lea esi,Array
  6. mov ecx,lengthof Array
  7. xor edx,edx
  8. xor eax,eax
  9. @@: lodsw
  10. add edx,eax
  11. loop @B
  12. mov eax,edx ; 最后将相加结果放入eax
  13. main ENDP
  14. END main

初始化内存: 把String字符串中的,每一个字节均填充初始化为0FFh

  1. .data
  2. Count = 100 ; 申请空间为100
  3. String BYTE Count DUP(?) ; 初始化为BYTE
  4. .code
  5. main PROC
  6. mov al,0FFh ; 指定要填充的数据为0FFh
  7. mov edi,offset String ; EDI寄存器指向目标内存
  8. mov ecx,Count ; 循环计数
  9. cld ; 初始化:方向=前方
  10. rep stosb ; AL中的值进行填充
  11. ret
  12. main ENDP
  13. END main

数组的乘法: 把双字数组中的每一个元素分别乘以一个常量,程序中使用了(LODSD加载),(STOSD保存).

  1. .data
  2. Array DWORD 1,2,3,4,5
  3. Multi DWORD 10
  4. .code
  5. main PROC
  6. mov esi,offset Array ; 源指针
  7. mov edi,esi ; 目的指针
  8. cld ; 方向=向前
  9. mov ecx,lengthof Array ; 循环计数器
  10. L1: lodsd ; 加载[esi]至EAX
  11. mul Multi ; EAX乘以10
  12. stosd ; 将结果从EAX存储至[EDI]
  13. loop L1
  14. ret
  15. main ENDP
  16. END main

计算字符串长度: 以下代码用于计算字符串的长度,并将结果保存在EAX寄存器中.

  1. .data
  2. String BYTE "hello world",0 ; 带计算字符串
  3. .code
  4. main PROC
  5. mov edi,offset String ; 取出字符串的基地址
  6. xor eax,eax ; 清空eax用作计数器
  7. L1: cmp byte ptr [edi],0 ; 分别那[edi]的值和0作比较
  8. je L2 ; 上一步为零则跳转得到ret
  9. inc edi ; 否则继续执行
  10. inc eax
  11. jmp L1
  12. L2: ret
  13. main ENDP
  14. END main

小写字串转大写: 将MyString变量中的小写字符串,依次转换为大写字符串.

  1. .data
  2. MyString db "hello lyshark",0 ; 定义MyString字符串
  3. .code
  4. main PROC
  5. mov esi,offset MyString ; 取出字符串的偏移地址
  6. L1: cmp byte ptr [esi],0 ; 分别拿出每一个字节,与0比较
  7. je L2 ; 如果相等则跳转到L2
  8. and byte ptr [esi],11011111b ; 执行按位与操作
  9. inc esi ; 每次esi指针递增1
  10. jmp L1 ; 重复循环
  11. L2: ret
  12. main ENDP
  13. END main

定义二维数组: 定义一个二维数组Table,并取出第一行中的第2偏移地址的元素.

  1. .data
  2. Table WORD 10h,20h,30h,40h,50h ; 定义一个数组
  3. Row = ($ - Table) ; 取出数组每行的字节数
  4. WORD 60h,70h,80h,90h,0Ah ; 继续定义数组
  5. .code
  6. main PROC
  7. row_index = 1 ; 表的偏移地址
  8. column_index = 2 ; 行的偏移地址
  9. mov ebx,offset Table ; 取偏移地址给ebx
  10. add ebx,Row*row_index ; 每行元素*偏移
  11. mov esi,column_index ; 将行偏移赋值给esi
  12. mov ax,[ebx+esi*TYPE Table] ; Table比例因子只能是2,4,8
  13. main ENDP
  14. END main

位操作指令

符号扩展(CBW/CWDE):

  1. .code
  2. main PROC
  3. mov al,7fh
  4. cbw ; AL 扩展为 AX
  5. PrintHex ax ;007F
  6. mov al,80h
  7. cbw
  8. PrintHex ax ;FF80
  9. mov ax,7fffh
  10. cwde ; AX 扩展为 EAX
  11. PrintHex eax
  12. main ENDP
  13. END main

符号扩展(CDQ/CWD):

  1. .code
  2. main PROC
  3. mov eax,7FFFFFFFh
  4. cdq ; EAX 扩展为 64 位数 EDX:EAX
  5. PrintHex edx ;00000000
  6. PrintHex eax ;7FFFFFFF
  7. mov ax, 7FFFh
  8. cwd ; AX 扩展为 DX:AX
  9. PrintHex dx ;0000
  10. PrintHex ax ;7FFF
  11. main ENDP
  12. END main

BT、BTS、BTR、BTC: 位测试指令

;BT(Bit Test): 位测试
;BTS(Bit Test and Set): 位测试并置位
;BTR(Bit Test and Reset): 位测试并复位
;BTC(Bit Test and Complement): 位测试并取反

;它们的结果影响 CF
;它们的指令格式相同:
BT r16/r32/m16/m32, r16/r32/m16/m32
BT r16/r32/m16/m32, i8

  1. .code
  2. main proc
  3. ;BT 10000001b 的第七位复制到 CF, 得知是 1
  4. mov dx, 10000001b
  5. bt dx, 7
  6. lahf
  7. PrintHex ah ;47 - 01000111b (CF=1)
  8. ;BT 10000001b 的第六位复制到 CF, 得知是 0
  9. bt dx, 6
  10. lahf
  11. PrintHex ah ;86 - 10000110b (CF=0)
  12. ;BTS 在执行 BT 命令的同时, 把操作数的指定位置为 1
  13. mov dx, 10000001b
  14. bts dx, 6
  15. PrintHex dl ;C1 - 11000001b
  16. ;BTR 在执行 BT 命令的同时, 把操作数的指定位置为 0
  17. mov dx, 10000001b
  18. btr dx, 7
  19. PrintHex dl ;01 - 00000001b
  20. ;BTC 在执行 BT 命令的同时, 把操作数的指定位取反
  21. mov dx, 10000001b
  22. btc dx, 0
  23. PrintHex dl ;80 - 10000000b
  24. btc dx, 0
  25. PrintHex dl ;81 - 10000001b
  26. ret
  27. main endp
  28. end main

BSF、BSR: 位扫描指令

;BSF(Bit Scan Forward): 位扫描, 低 -> 高
;BSR(Bit Scan Reverse): 位扫描, 高 -> 低

;它们的结果影响 ZF

;扫描的是参数二, 找到是 1 的位后, 把位置数给参数一并置 ZF=0
;找不到(也就是参数二是 0)时, 置 ZF=1

;它们的指令格式相同:
BSF r16/r32, r16/r32/m16/m32

  1. .code
  2. main proc
  3. ;扫描到时
  4. mov dx, 0000111100001100b
  5. bsf cx, dx
  6. PrintDec cx ;2 - 也就是左数第 3
  7. bsr cx, dx
  8. PrintDec cx ;11 - 也就是左数第 12
  9. ;扫描不到时
  10. mov cx, 0FFFFh
  11. mov dx, 0
  12. bsf cx, dx
  13. lahf
  14. PrintHex ah ;C6 - 11000110 (ZF=1)
  15. PrintHex cx ;FFFF - 找不到时不会影响到目的值
  16. ret
  17. main endp
  18. end main

其他测试指令

转载于:https://www.cnblogs.com/LyShark/p/11136331.html

发表评论

表情:
评论列表 (有 0 条评论,528人围观)

还没有评论,来说两句吧...

相关阅读