汇编开发(五):算法

作者: _凌浩雨 | 来源:发表于2019-02-19 16:18 被阅读3次

    1. Shift 和 Rotate 指令

    位移意味着在操作数内部按位左/右移动,其影响着OF和CF标志位。

    Shift and Rotate Instructions.png
    1). 逻辑移动和算术移动
    • 逻辑移动
      将新创建的字节位填充0,
    Logical shift.png
    • 算术移动
      新创建的字节位填充原位置上的数据。
    Arithmetic shift.png
    2). SHL 指令

    SHL指令表示在目标操作数上逻辑左移,低位填充0。

    SHL.png
    • 格式
    ; 第一个是目标操作数,第二个是移动的位数
    SHL destination,count
    
    SHL reg,imm8
    SHL mem,imm8
    SHL reg,CL
    SHL mem,CL
    

    x86 处理器支持imm8的范围在整型0—255之间,另外,CL寄存器也可以包含移动的位数。此格式同样应用在SHR, SAL, SAR, ROR, ROL,
    RCR 和RCL 指令。

    示例:

    mov bl,8Fh      ; BL = 10001111b
    shl bl,1        ; CF = 1, BL = 00011110b
    
    mov al,10000000b
    shl al,2        ; CF = 0, AL = 00000000b
    
    • 按位乘
      左移n位相当于操作数乘以2^n。
    mov dl,5
    shl dl,1
    
    Bitwise Multiplication.png
    3). SHR 指令

    SHR 指令表示在目标操作数上逻辑右移,高位用0替换。

    SHR.png

    示例:

    mov al,0D0h     ; AL = 11010000b
    shr al,1        ; AL = 01101000b, CF = 0
    
    mov al,00000010b
    shr al,2        ; AL = 00000000b, CF = 1
    
    • 按位除
      右移一个无符号整数n位相当于操作数除以2^n。
    mov dl,32
    shr dl,1
    
    Bitwise Division.png
    4). SAL 和 SAR 指令
    • SAL
      SAL 指令与SHL指令相同。SAL指令的每一位向高位移动,低位补0.
    SAL.png
    • SAR
      SAR 指令移动后新的位置上填充原位置上的数字。
    SAR.png

    示例:

    mov al,0F0h     ; AL = 11110000b (-16)
    sar al,1        ; AL = 11111000b (-8), CF = 0
    
    • 符号除
      有符号的操作数除以2,可以使用SAR指令。
    mov dl,-128     ; DL = 10000000b
    sar dl,3        ; DL = 11110000b
    
    • AX符号扩展到EAX
      AX包含一个有符号的整型,并将它扩展到EAX寄存器中。
    mov ax,-128     ; EAX = ????FF80h
    shl eax,16      ; EAX = FF800000h
    sar eax,16      ; EAX = FFFFFF80h
    
    5). ROL 指令

    ROL 指令指循环移动,即移出的一位补充到先增加的那个位置上。

    SHL.png

    示例:

    mov al,40h      ; AL = 01000000b
    rol al,1        ; AL = 10000000b, CF = 0
    rol al,1        ; AL = 00000001b, CF = 1
    rol al,1        ; AL = 00000010b, CF = 0
    
    • 多次旋转
      当循环位数大于1的时候,进位标志与最后一位相同
    mov al,00100000b
    rol al,3            ; CF = 1, AL = 00000001b
    
    • 交换比特组
      可以使用ROL交换高位和低位的字节。
    mov al,26h
    rol al,4        ; AL = 62h
    
    6). ROR 指令

    ROR 指令 每一位右移,并复制最低位到CF标志位和最高位。

    ROR.png

    示例:

    mov al,01h      ; AL = 00000001b
    ror al,1        ; AL = 10000000b, CF = 1
    ror al,1        ; AL = 01000000b, CF = 0
    
    • 多次旋转
      当使用旋转位数大于1时,CF标志位与最后一次移动的位数值相同。
    mov al,00000100b
    ror al,3            ; AL = 10000000b, CF = 1
    
    7). RCL 和 RCR 指令

    RCL 指令向左移动每一位,复制到CF标志位和最低位。

    RCL.png

    示例:

    clc         ; CF = 0 清空CF标志位
    mov bl,88h  ; CF,BL = 0 10001000b
    rcl bl,1    ; CF,BL = 1 00010000b
    rcl bl,1    ; CF,BL = 0 00100001b
    
    • 从进位标志中恢复
      RCL 可以恢复移动之前的CF标志位。
    .data
        testval BYTE 01101010b
    .code
        shr testval,1   ; shift LSB into Carry flag
        jc exit         ; exit if Carry flag set
        rcl testval,1   ; else restore the number
    
    • RCR 指令
      RCR 指令向右移动每一位,复制CF标志位到最高位,将最低位复制到CF标志位。
    RCR.png

    示例:

    stc         ; CF = 1 设置CF标志位为1
    mov ah,10h  ; AH, CF = 00010000 1
    rcr ah,1    ; AH, CF = 10001000 0
    
    8). 符号溢出

    移动或者旋转一个有符号的整型时,符号位溢出后,OF标志位被设置。

    mov al,+127 ; AL = 01111111b
    rol al,1    ; OF = 1, AL = 11111110b
    
    9). SHLD / SHRD 指令

    SHLD/SHRD 指令向左/右移动一个目标操作数指定的数字位数,新添加的位数由源操作数中的高/低位填充。格式如下:

    SHLD/SHRD dest, source, count
    
    SHLD/SHRD reg16,reg16,CL/imm8
    SHLD/SHRD mem16,reg16,CL/imm8
    SHLD/SHRD reg32,reg32,CL/imm8
    SHLD/SHRD mem32,reg32,CL/imm8
    
    SHLD.png SHRD.png
    • 示例1:
    .data
        wval WORD 9BA6h
    .code
        mov ax,0AC36h
        shld wval,ax,4      ; wval = BA6Ah
    
    • 示例2:
    mov ax,234Bh
    mov dx,7654h
    shrd ax,dx,4        ; ax = 4234h
    

    2. 移动和旋转应用

    1). 转换多个DWORD
    ; 数组元素移位
    
    INCLUDE Irvine32.inc
    
    .data
        ArraySize = 3
        array BYTE ArraySize DUP(99h)
    
    .code
    main PROC
        mov esi, 0
        shr array[esi + 2], 1       ; 最高字节
        rcr array[esi + 1], 1       ; 中间字节
        rcr array[esi], 1           ; 低字节
        
        call Crlf
        call WaitMsg
        exit
    main ENDP
    
    END
    
    2). 二进制乘法

    将某个数分解之后成为2的n次方,并将乘数依次与之相乘,最后求和。例如:36可以分为25+22, 则10036 = 10025+100*22。

    mov eax,100
    mov ebx,eax
    shl eax,5   ; multiply by 25
    shl ebx,2   ; multiply by 22
    add eax,ebx ; add the products
    
    3). 显示二进制位

    共同的代码程序将二进制整数转换为ASCII码字符串,并将ASCII码显示。

    ;---------------------------------------------------------
    ;
    ; Converts 32-bit binary integer to ASCII binary.
    ; Receives: EAX = binary integer, ESI points to buffer
    ; Returns: buffer filled with ASCII binary digits
    ;---------------------------------------------------------
    BinToAsc PROC USES ecx, esi
        mov ecx,32              ; number of bits in EAX
    L1: 
        shl eax,1               ; shift high bit into Carry flag
        mov BYTE PTR [esi],'0'  ; choose 0 as default digit
        jnc L2                  ; if no Carry, jump to L2
        mov BYTE PTR [esi],'1'  ; else move 1 to buffer
    L2: 
        inc esi                 ; next buffer position
        loop L1                 ; shift another bit to left
        RET
    BinToAsc ENDP
    
    4). 提取文件日期

    应用经常需要提取位串用于获取时间。在MS-DOS中日期存储在DX中,其中0—4位代表天,5—8位代表月,9—15代表年。

    Extracting File Date Fields.png

    示例:

    ; 获取天
    mov al,dl           ; make a copy of DL
    and al,00011111b    ; clear bits 5-7
    mov day,al          ; save in day
    
    ; 获取月
    mov ax,dx           ; make a copy of DX
    shr ax,5            ; shift right 5 bits
    and al,00001111b    ; clear bits 4-7
    mov month,al        ; save in month
    
    ; 获取年
    mov al,dh           ; make a copy of DH
    shr al,1            ; shift right one position
    mov ah,0            ; clear AH to zeros
    add ax,1980         ; year is relative to 1980
    mov year,ax         ; save in year
    

    3. MUL 和 DIV 指令

    在32位模式中,MUL和DIV 可以作用于32位,16位,8位操作数。
    在64为模式中,MUL和DIV指令作用于无符号整型中,IMUL和IDIV指令作用于有符号整型中。

    1). MUL 指令
    • 格式
    MUL reg/mem8
    MUL reg/mem16
    MUL reg/mem32
    
    MUL Operands.png
    ; 示例1
    mov al,5h
    mov bl,10h
    mul bl      ; AX = 0050h, CF = 0
    
    ; 示例2
    .data
    val1 WORD 2000h
    val2 WORD 0100h
    .code
    mov ax,val1     ; AX = 2000h
    mul val2        ; DX:AX = 00200000h, CF = 1
    
    ; 示例3
    mov eax,12345h
    mov ebx,1000h
    mul ebx         ; EDX:EAX = 0000000012345000h, CF = 0
    
    • 64位模式中的MUL
    .data
        multiplier QWORD 10h
    .code
        mov rax,0AABBBBCCCCDDDDh
        mul multiplier          ; RDX:RAX = 00000000000000000AABBBBCCCCDDDD0h
    
    2). IMUL 指令

    IMUL 指令表示有符号整数的乘法。

    • 单操作数格式
    IMUL reg/mem8   ; AX = AL * reg/mem8
    IMUL reg/mem16  ; DX:AX = AX * reg/mem16
    IMUL reg/mem32  ; EDX:EAX = EAX * reg/mem32
    
    • 双操作数格式
    IMUL reg16,reg/mem16
    IMUL reg16,imm8
    IMUL reg16,imm16
    IMUL reg32,reg/mem32
    IMUL reg32,imm8
    IMUL reg32,imm32
    
    • 三操作数格式
    IMUL reg16,reg/mem16,imm8
    IMUL reg16,reg/mem16,imm16
    IMUL reg32,reg/mem32,imm8
    IMUL reg32,reg/mem32,imm32
    

    如果符号位丢失,则需要设置OF和CF标志位。

    • 64位模式下的IMUL
      64位模式下,可以使用64位模式下MUL指令。在双操作数格式下,一个64位寄存器或者内存数乘以RDX,产生一个128位有符号扩展的RDX:RAX。64位模式下三操作数格式也是可用的。
    ; 双操作数
    mov rax,-4
    mov rbx,4
    imul rb     ; RDX = 0FFFFFFFFFFFFFFFFh, RAX = -16
    
    ; 三操作数
    .data
        multiplicand QWORD -16
    .code
        imul rax, multiplicand, 4   ; RAX = FFFFFFFFFFFFFFC0 (-64)
    

    示例:

    ; 单操作数
    mov al,48
    mov bl,4
    imul bl     ; AX = 00C0h, OF = 1
    
    mov al,-4
    mov bl,4
    imul bl     ; AX = FFF0h, OF = 0
    
    ; 双操作数
    .data
        word1 SWORD 4
        dword1 SDWORD 4
    .code
        mov ax,-16      ; AX = -16
        mov bx,2        ; BX = 2
        imul bx,ax      ; BX = -32
        imul bx,2       ; BX = -64
        imul bx,word1   ; BX = -256
        mov eax,-16     ; EAX = -16
        mov ebx,2       ; EBX = 2
        imul ebx,eax    ; EBX = -32
        imul ebx,2      ; EBX = -64
        imul ebx,dword1 ; EBX = -256
    
        mov ax,-32000
        imul ax,2 ; OF = 1  
        
    ; 三操作数
    .data
        word1 SWORD 4
        dword1 SDWORD 4
    .code
        imul bx,word1,-16   ; BX = word1 * -16
        imul ebx,dword1,-16 ; EBX = dword1 * -16
        imul ebx,dword1,-2000000000 ; signed overflow!
    
    3). 比较MUL/IMUL和移位的运行时间
    ; 比较MUL/IMUL和移位的运行时间
    
    INCLUDE Irvine32.inc
    
    .data
        LOOP_COUNT = 0FFFFFFFFh
        intval DWORD 5
        startTime DWORD ?
        shiftTime DWORD ?
        mulTime DWORD ?
    
    .code
    main PROC
        call GetMseconds    ; get start time
        mov startTime,eax
        mov eax,intval      ; multiply now
        call mult_by_shifting
        call GetMseconds    ; get stop time
        sub eax,startTime
        call WriteDec       ; display elapsed time
    
        call Crlf
    
        call GetMseconds    ; get start time
        mov startTime,eax
        mov eax,intval      ; multiply now
        call mult_by_MUL
        call GetMseconds    ; get stop time
        sub eax,startTime
        call WriteDec       ; display elapsed time
    
        call Crlf
        call WaitMsg
        exit
    main ENDP
    
    ;----------------------------------
    ; 使用SHL移位计算EAX*36
    ;----------------------------------
    mult_by_shifting PROC USES eax
        mov ecx, LOOP_COUNT
    L1:
        mov ebx, eax
        shl eax, 5
        shl eax, 2
        add eax, ebx
        LOOP L1
        RET
    mult_by_shifting ENDP
    
    ;----------------------------------
    ; 使用乘法计算EAX*36
    ;----------------------------------
    mult_by_MUL PROC USES eax
        mov ecx, LOOP_COUNT
    L1:
        mov ebx, 36
        mul ebx
        LOOP L1
        RET
    mult_by_MUL ENDP
    
    END
    
    效果.png
    4). DIV 指令
    • 格式
    DIV reg/mem8
    DIV reg/mem16
    DIV reg/mem32
    
    被除数、除数、商和余数关系.png
    • 示例
    ; 示例1
    mov ax,0083h    ; dividend
    mov bl,2        ; divisor
    div bl          ; AL = 41h, AH = 01h
    
    ; 示例2
    mov dx,0        ; clear dividend, high
    mov ax,8003h    ; dividend, low
    mov cx,100h     ; divisor
    div cx          ; AX = 0080h, DX = 0003h
    
    5). 带符号整数除法

    有符号整数除法与无符号除法几乎相同,但有一个重要区别:除法必须在除法发生之前进行符号扩展。

    .data
        wordVal SWORD -101  ; 009Bh
    .code
        mov eax,0           ; EAX = 00000000h
        mov ax,wordVal      ; EAX = 0000009Bh (+155)
        cwd                 ; EAX = FFFFFF9Bh (-101)
        mov bx,2            ; EBX is the divisor
        idiv bx             ; divide EAX by BX
    
    • 符号扩展指令 (CBW, CWD, CDQ)
      CBW 指令(BYTE -> WORD)扩展符号位从AL到AH。CWD(WORD -> DWORD)扩展符号位AX到DX。CDQ(DWORD -> QWORD)口占EAX到EDX。
    ; CBW 使用
    .data
        byteVal SBYTE -101  ; 9Bh
    .code
        mov al,byteVal      ; AL = 9Bh
        cbw                 ; AX = FF9Bh
    
    ; CWD 使用
    .data
        wordVal SWORD -101  ; FF9Bh
    .code
        mov ax,wordVal      ; AX = FF9Bh
        cwd
    
    ; CDQ 使用
    .data
        dwordVal SDWORD -101    ; FFFFFF9Bh
    .code
        mov eax,dwordVal
        cdq
    
    • IDIV 指令
      IDIV 指令表示有符号除法,使用和DIV相同。
    .data
        byteVal SBYTE -48   ; D0 hexadecimal
    .code
        mov al,byteVal      ; lower half of dividend
        cbw                 ; extend AL into AH
        mov bl,+5           ; divisor
        idiv bl             ; AL = -9, AH = -3
    
    • 除法溢出
    mov ax,1000h
    mov bl,10h
    div bl      ; AL cannot hold 100h
    

    建议:使用32位除数和64位被除数来降低除法溢出条件的概率。

    6). 实现除法/乘法的算术表达式
    ; 示例表达式1: var4 = (var1 + var2) * var3
        mov eax,var1
        add eax,var2
        mul var3        ; EAX = EAX * var3
        jc tooBig       ; unsigned overflow?
        mov var4,eax
        jmp next
    tooBig:         ; display error message
    
    ; 示例表达式2: var4 = (var1 * 5) / (var2 - 3)
        mov eax,var1    ; left side
        mov ebx,5
        mul ebx         ; EDX:EAX = product
        mov ebx,var2    ; right side
        sub ebx,3
        div ebx         ; final division
        mov var4,eax
    

    4. 扩展加和减

    扩展加和减是添加和减去几乎无限大小的数字的技术。

    1). ADC 指令

    ADC指令将源操作数和CF标志的内容添加到目标操作数。

    • 格式
    ADC reg,reg
    ADC mem,reg
    ADC reg,mem
    ADC mem,imm
    ADC reg,imm
    

    示例:

    mov dl,0
    mov al,0FFh
    add al,0FFh     ; AL = FEh
    adc dl,0        ; DL/AL = 01FEh
    
    效果.png
    2). 扩展加示例

    将数组中的数据一一对应相加。

    ; 扩展加法示例:数组元素对应相加
    
    INCLUDE Irvine32.inc
    
    .data
        op1 BYTE 34h,12h,98h,74h,06h,0A4h,0B2h,0A2h
        op2 BYTE 02h,45h,23h,00h,00h,87h,10h,80h
        sum BYTE 9 dup(0)
    
    .code
    main PROC
        mov esi, OFFSET op1
        mov edi, OFFSET op2
        mov ebx, OFFSET sum
        mov ecx, LENGTHOF op1
    
        call Extended_Add
    
        ; 显示和
        mov esi, OFFSET sum
        mov ecx, LENGTHOF sum
        call Display_Sum
        
        call Crlf
        call WaitMsg
        exit
    main ENDP
    
    ;-------------------------------------------------
    ; 计算两个字节数组之和
    ; Receives: ESI和EDI指向两个整型,EBX指向一个存储和的
    ;           变量,ECX循环计数
    ; Returns: 无
    ;-------------------------------------------------
    Extended_Add PROC
        pushad
        clc
    
    L1: 
        mov al, [esi]       ; 获取第一个整数
        adc al, [edi]       ; 添加第二个整数
        pushfd              ; 保存CF标记位
        mov [ebx], al       ; 存储和
        add esi, 1          ; 指针指向下一个数
        add edi, 1
        add ebx, 1
        popfd               ; 恢复CF
        LOOP L1             ; 循环
    
        mov byte ptr [ebx], 0; 清除sum的高位
        adc byte ptr [ebx], 0; 添加CF标记位
        popad
        RET
    Extended_Add ENDP
    
    Display_Sum PROC
        pushad
        ; point to the last array element
        add esi,ecx
        sub esi,TYPE BYTE
        mov ebx,TYPE BYTE
    L1: 
        mov al,[esi]        ; get an array byte
        call WriteHexB      ; display it
        sub esi,TYPE BYTE   ; point to previous byte
        call Crlf
        loop L1
        popad
        ret
    Display_Sum ENDP
    
    END
    

    结果:0122C32B0674BB5736, 数组对应元素的和,在结果中从低位到高位显示,最高位为符号位。

    3). SBB 指令

    SBB指令表示从目的操作数中减去源操作数和CF标志位。

    mov edx,7 ; upper half
    mov eax,1 ; lower half
    sub eax,2 ; subtract 2
    sbb edx,0 ; subtract upper half
    
    Subtracting from a 64-bit integer using SBB.png

    5. ASCII 和未压缩的十进制算法

    • 四个处理指令
    deal with ASCII addition, subtraction, multiplication, and division.png
    • ASCII 十进制 和 未解压十进制
    All values are in hexadecimal.png
    1). AAA 指令
    mov ah,0
    mov al,'8'      ; AX = 0038h
    add al,'2'      ; AX = 006Ah
    aaa             ; AX = 0100h (ASCII adjust result)
    or ax,3030h     ; AX = 3130h = '10' (convert to ASCII)
    
    • 使用AAA进行多字节相加
    ; ASCII 加法
    ; 字符串中ASCII算法
    INCLUDE Irvine32.inc
    
    DECIMAL_OFFSET = 5          ; 从右数字符串偏移
    .data
        decimal_one BYTE "100123456789765"  ; 1001234567.89765
        decimal_two BYTE "900402076502015"  ; 9004020765.02015
        sum BYTE (SIZEOF decimal_one + 1) DUP(0), 0
    
    .code
    main PROC
        ; 开始从最后一个数字的位置
        mov esi, SIZEOF decimal_one - 1
        mov edi, SIZEOF decimal_one
        mov ecx, SIZEOF decimal_one
        mov bh, 0                       ; 设置CF为0
    L1:
        mov ah, 0                       ; 加之前清空AH
        mov al, decimal_one[esi]        ; 获取当前位置的数字
        add al, bh                      ; 添加之前的进位
        aaa                             ; 调整总和
        mov bh, ah                      ; 存储CF标志位
        or bh, 30h                      ; 转换ASCII
        add al, decimal_two[esi]        ; 添加第二个数
        aaa                             ; 调整总和
        or bh, ah                       ; 或CF标志位
        or bh, 30h                      ; 转换为ASCII码
        or al, 30h                      ; 转换al为ASCII
        mov sum[edi], al                ; 存储和
        dec esi                         ; 移动到下一位
        dec edi
        LOOP L1
        mov sum[edi], bh                ; 存储进位
        
        ; 显示总和字符串
        mov edx, OFFSET sum
        call WriteString
    
        call Crlf
        call WaitMsg
        exit
    main ENDP
    
    END
    
    效果.png
    2). AAS 指令
    .data
        val1 BYTE '8'
        val2 BYTE '9'
    .code
        mov ah,0
        mov al,val1     ; AX = 0038h
        sub al,val2     ; AX = 00FFh
        aas             ; AX = FF09h
        pushf           ; save the Carry flag
        or al,30h       ; AX = FF39h
        popf            ; restore the Carry flag
    

    此处8 - 9 之后,AH减1变为FFh, AL变为39h, 可理解为18 - 9,即个位为9,向前借了一位。

    3). AAM 指令
    .data
        AscVal BYTE 05h,06h
    .code
        mov bl,ascVal       ; first operand
        mov al,[ascVal+1]   ; second operand
        mul bl              ; AX = 001Eh
        aam                 ; AX = 0300h , or 3030h
    
    4). AAD 指令
    .data
        quotient BYTE ?
        remainder BYTE ?
    .code
        mov ax,0307h    ; dividend
        aad             ; AX = 0025h, or 3030h
        mov bl,5        ; divisor
        div bl          ; AX = 0207h
        mov quotient,al
        mov remainder,ah
    

    6. 压缩十进制算术

    涉及到两个指令:DAA (decimal adjust after addition) 与 DAS (decimal adjust after subtraction)。压缩十进制算术中无乘法和相关指令。

    1). DAA
    ; 压缩加法
    ; 压缩十进制加法
    INCLUDE Irvine32.inc
    
    .data
        packed_1 WORD 4536h
        packed_2 WORD 7207h
        sum DWORD ?
    
    .code
    main PROC
        ; 初始化总和和序号
        mov sum, 0
        mov esi, 0
    
        ; 添加低字节
        mov al, BYTE PTR packed_1[esi]
        add al, BYTE PTR packed_2[esi]
        daa
        mov BYTE PTR sum[esi], al
    
        ; 添加高字节,包含CF标志位
        inc esi
        mov al, BYTE PTR packed_1[esi]
        adc al, BYTE PTR packed_2[esi]
        daa
        mov BYTE PTR sum[esi], al
        ; 添加CF标志位
        inc esi
        mov al, 0
        adc al, 0
        mov BYTE PTR sum[esi], al
    
        ; 十六进制格式显示
        mov eax, sum
        call WriteHex
    
        call Crlf
        call WaitMsg
        exit
    main ENDP
    
    END
    
    AddPacked.png
    2). DAS
    mov bl,48h
    mov al,85h
    sub al,bl   ; AL = 3Dh
    das         ; AL = 37h (adjusted result)
    

    相关文章

      网友评论

        本文标题:汇编开发(五):算法

        本文链接:https://www.haomeiwen.com/subject/edaaeqtx.html