• Win32汇编之其他指令


    汇编语言(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):

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

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

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

    (movsd)四字节复制字串:

    .data
    	ddSource DWORD 10h,20h,30h               ; 定义三个四字节数据
    	ddDest   DWORD lengthof ddSource dup(?)  ; 得到目标地址
    
    .code
    	main PROC
    		lea esi,ddSource
    		lea edi,ddDest
    		mov ecx,lengthof ddSource
    		cld
    		rep movsd
    		ret
    	main ENDP
    END main
    

    CMPSB:

    .data
    	Text1 db "hello lyshark",0
    	Text2 db "hello lyshar1",0
    .code
    	main PROC
    		lea esi,Text1
    		lea edi,Text2
    		mov ecx,lengthof Text1
    		cld
    		repe cmpsb
    		je L1
    		xor eax,eax            ; 字串不同则清空eax
    		jmp L2
    	L1:	xor ebx,ebx            ; 字串相同则清空ebx
    	L2:	ret
    	main ENDP
    END main
    

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

    .data
    	var1 DWORD 1234h
    	var2 DWORD 5678h
    .code
    	main PROC
    		lea esi,var1
    		lea edi,var2
    		cmpsd
    		je L1
    		xor eax,eax      ; 两数如果相等则清空eax
    		jmp L2
    	L1:	xor ebx,ebx      ; 两数不相等则清空ebx
    	L2:	ret
    	main ENDP
    END main
    

    CMPSW:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ## 位操作指令

    符号扩展(CBW/CWDE):

    .code
    	main PROC
    		mov al,7fh
    		cbw                 ; 将 AL 扩展为 AX
    		PrintHex ax ;007F
    		mov al,80h
    		cbw
    		PrintHex ax ;FF80
    		
    		mov ax,7fffh
    		cwde                 ; 将 AX 扩展为 EAX
    		PrintHex eax
    	main ENDP
    END main
    

    符号扩展(CDQ/CWD):

    .code
    	main PROC
    		mov eax,7FFFFFFFh
    		cdq                      ; 将 EAX 扩展为 64 位数 EDX:EAX
    		PrintHex edx ;00000000
    		PrintHex eax ;7FFFFFFF
    		
    		mov ax, 7FFFh
    		cwd                       ; 将 AX 扩展为 DX:AX
    		PrintHex dx ;0000
    		PrintHex ax ;7FFF
    		
    	main ENDP
    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

    .code
    main proc
        ;BT 把 10000001b 的第七位复制到 CF, 得知是 1
        mov dx, 10000001b
        bt  dx, 7
        lahf
        PrintHex ah ;47 - 01000111b (CF=1)
        ;BT 把 10000001b 的第六位复制到 CF, 得知是 0
        bt  dx, 6
        lahf
        PrintHex ah ;86 - 10000110b (CF=0)
        
        ;BTS 在执行 BT 命令的同时, 把操作数的指定位置为 1
        mov dx, 10000001b
        bts dx, 6
        PrintHex dl ;C1 - 11000001b
        
        ;BTR 在执行 BT 命令的同时, 把操作数的指定位置为 0
        mov dx, 10000001b
        btr dx, 7
        PrintHex dl ;01 - 00000001b
        
        ;BTC 在执行 BT 命令的同时, 把操作数的指定位取反
        mov dx, 10000001b
        btc dx, 0
        PrintHex dl ;80 - 10000000b
        btc dx, 0
        PrintHex dl ;81 - 10000001b
        ret
    main endp
    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

    .code
    main proc
        ;扫描到时
        mov dx, 0000111100001100b
        bsf cx, dx
        PrintDec cx ;2  - 也就是左数第 3 位
        
        bsr cx, dx
        PrintDec cx ;11 - 也就是左数第 12 位
        
        ;扫描不到时
        mov cx, 0FFFFh
        mov dx, 0
        bsf cx, dx
        lahf
        PrintHex ah ;C6 - 11000110 (ZF=1)
        PrintHex cx ;FFFF - 找不到时不会影响到目的值
        ret
    main endp
    end main
    

    其他测试指令

    参考文献:《Intel 汇编语言程序设计》,《琢石成器-Win32汇编语言程序设计》,《汇编语言-王爽》

  • 相关阅读:
    Leetcode 421.数组中两数的最大异或值
    Leetcode 419.甲板上的战舰
    Leetcode 417.太平洋大西洋水流问题
    Leetcode 416.分割等和子集
    Leetcode 413.等差数列划分
    Leetcode 410.分割数组的最大值
    由股票价格形成因素看如何选股(发布于06-02 13:09)
    巴菲特的资产配置艺术(发布于06-01 13:28)
    ROE能否包打天下?(发布于05-31 11:27)
    价值迟迟不回归怎么办?(发布于05-30 10:02)
  • 原文地址:https://www.cnblogs.com/LyShark/p/11136331.html
Copyright © 2020-2023  润新知