• 《汇编语言 基于x86处理器》第七章整数运算部分的代码


    ▶ 书中第七章的程序,使用各种位移运算,加深了对内存、寄存器中整数类型变量存储的认识

    ● 代码,双字数组右移 4 位

     1 INCLUDE Irvine32.inc
     2 
     3 COUNT = 4                           ; 右移位数
     4 
     5 .data
     6 array DWORD 148B2165h, 8C943A29h, 6DFA4B86h, 91F76C04h, 8BAF9857h
     7 
     8 .code
     9 main PROC    
    10     mov  esi, OFFSET array          ; 移之前的情况
    11     mov  ecx, LENGTHOF array    
    12     mov  ebx, TYPE array
    13     call DumpMem
    14 
    15     mov  bl, COUNT
    16     call ShiftDoublewords
    17 
    18     mov  esi, OFFSET array          ; 移之后的情况
    19     mov  ecx, LENGTHOF array
    20     mov  ebx, TYPE array
    21     call DumpMem
    22 
    23     call WaitMsg
    24     exit
    25 main ENDP
    26 
    27 ShiftDoublewords PROC
    28     mov  esi, OFFSET array
    29     mov  ecx, (LENGTHOF array) - 1  ; 循环次数等于数组长度减一,最后一个数单独处理
    30 
    31 L1: 
    32     push ecx                        ; 需要使用 cl 移动数
    33     mov  cl, COUNT
    34     mov  eax, [esi + TYPE DWORD]    ; 下一个数字 DWORD 移入 eax      
    35     shrd [esi], eax, cl             ; eax 逐渐移入当前数字
    36 
    37     push esi                        ; 移了 4 位,显示一下
    38     push ecx
    39     push ebx
    40     mov  esi, OFFSET array
    41     mov  ecx, LENGTHOF array
    42     mov  ebx, TYPE array
    43     call DumpMem
    44     pop ebx
    45     pop ecx
    46     pop esi
    47 
    48     add  esi, TYPE DWORD            ; 移完了,esi 指向下一个数字
    49     pop  ecx                        ; 恢复 ecx
    50     loop L1
    51 
    52     shr DWORD PTR [esi], COUNT      ; 最后一个数,直接右移,偷偷使用 cf 中的值
    53 
    54     ret
    55 ShiftDoublewords ENDP
    56 
    57 END main

    ● 输出结果

    Dump of offset 01156000                             // 移之前
    -------------------------------
    148B2165  8C943A29  6DFA4B86  91F76C04  8BAF9857
    
    Dump of offset 01156000                             // 移第 1 个 DWORD,"9" 来自第二个数的最低 4 位
    -------------------------------
    9148B216  8C943A29  6DFA4B86  91F76C04  8BAF9857
    
    Dump of offset 01156000                             // 移第 2 个 DWORD
    -------------------------------
    9148B216  68C943A2  6DFA4B86  91F76C04  8BAF9857
    
    Dump of offset 01156000                             // 移第 3 个 DWORD
    -------------------------------
    9148B216  68C943A2  46DFA4B8  91F76C04  8BAF9857
    
    Dump of offset 01156000                             // 移第 4 个 DWORD
    -------------------------------
    9148B216  68C943A2  46DFA4B8  791F76C0  8BAF9857
    
    Dump of offset 01156000                             // 移第 5 个 DWORD,完成移动
    -------------------------------
    9148B216  68C943A2  46DFA4B8  791F76C0  08BAF985

    ● 代码,内存右移 1 位

     1 INCLUDE Irvine32.inc
     2 
     3 .data
     4 array BYTE 45h, 67h, 89h
     5 
     6 .code
     7 main PROC
     8     call DisplayArray    
     9     
    10     mov esi, 0
    11     mov eax, OFFSET array
    12     shr array[esi+2], 1         ; 最高字节(第一个元素/字节)右移
    13     rcr array[esi+1], 1         ; 中间元素循环右移,偷偷使用 CF
    14     rcr array[esi], 1           ; 最低字节循环右移
    15 
    16     call DisplayArray            
    17     
    18     call WaitMsg
    19     exit
    20 main ENDP
    21 
    22 DisplayArray PROC
    23     pushad
    24 
    25     mov  esi, OFFSET array      ; 先用 DumpMem 显示内存情况(注意元素/字节是倒着存的)
    26     mov  ecx, LENGTHOF array
    27     mov  ebx, TYPE array
    28     call DumpMem
    29     
    30     mov esi, LENGTHOF array     ; esi 循环变量
    31     dec esi
    32 L1:
    33     mov  al, array[esi]
    34     mov  ebx, 1                 
    35     call WriteBinB              ; display binary bits
    36     mov  al, ' '
    37     call WriteChar
    38     dec  esi
    39     Loop L1
    40     
    41     call Crlf
    42     popad
    43     ret
    44 DisplayArray ENDP
    45 
    46 END main

    ● 输出结果

    Dump of offset 00F66000         // 右移前,注意元素/字节是顺着存的
    ------------------------------- // 用 DumpMem 显示反而会翻转过来
    45 67 89
    1000 1001 0110 0111 0100 0101
    
    Dump of offset 00F66000         // 右移后
    -------------------------------
    A2 B3 44
    0100 0100 1011 0011 1010 0010

    ● 代码,二进制数转 ASCII 显示(逐字节打印),结果输出 00010010001101001010101111001101

     1 INCLUDE Irvine32.inc
     2 
     3 .data
     4 binVal    DWORD 1234ABCDh        ; 需要输出的数字
     5 buffer    BYTE 32 dup(0),0
     6 
     7 .code
     8 main PROC
     9     mov    eax, binVal
    10     mov    esi, OFFSET buffer
    11     call    BinToAsc         
    12 
    13     mov    edx,OFFSET buffer
    14     call WriteString            
    15 
    16     call Crlf
    17     call WaitMsg
    18     exit
    19 main ENDP
    20 
    21 BinToAsc PROC uses ecx esi
    22     
    23     mov    ecx, 32
    24 
    25 L1:    
    26     shl    eax, 1                ; eax 中的二进制串左移一位,最高位放入 cf 用于下面的跳转
    27                                  ; binVal 在内存中存成了 cd ab 34 12(4 字节整数模式下可以看到 1234abcd)
    28                                  ; 但对寄存器进行左移的时候还是按照 1234ABCDh 来左移
    29                                  ; 例如第一次左移后得到 2469579Ah
    30     mov    BYTE PTR [esi],'0'    ; 内存先写上 '0' 再说
    31     jnc    L2                    ; 如果 cf 中是 1,把内存改写成 '1',否则跳过改写
    32     mov    BYTE PTR [esi],'1'     
    33 
    34 L2:    
    35     inc    esi                    
    36     loop    L1                    
    37 
    38     ret
    39 BinToAsc ENDP
    40 
    41 END main

    ● 代码,用 adc 指令实现长整数加法

     1 INCLUDE Irvine32.inc
     2 
     3 .data
     4 op1 BYTE 34h,12h,98h,74h,06h,0A4h,0B2h,0A2h
     5 op2 BYTE 02h,45h,23h,00h,00h, 87h,10h, 80h
     6 
     7 sum BYTE 9 dup(0)     ; = 0122C32B0674BB5736h
     8 
     9 .code
    10 main PROC
    11 
    12     mov    esi, OFFSET op1       
    13     mov    edi, OFFSET op2       
    14     mov    ebx, OFFSET sum       
    15     mov    ecx, LENGTHOF op1     
    16     
    17     call    Extended_Add
    18 
    19     mov  esi, OFFSET sum
    20     mov  ecx, LENGTHOF sum    
    21 
    22     add esi, ecx                ; 找到数组结尾,从高位逐字节输出
    23     sub esi, TYPE BYTE
    24     mov ebx, TYPE BYTE
    25     
    26 L1:
    27     mov  al,[esi]               
    28     call WriteHexB     
    29     sub  esi, TYPE BYTE          
    30     loop L1
    31 
    32 
    33     call Crlf
    34     call WaitMsg
    35     exit
    36 main ENDP
    37 
    38 
    39 Extended_Add PROC
    40     pushad
    41     clc                         ; 清除 CF
    42 
    43     mov edx,0
    44 L1:
    45     mov    al, [esi]             
    46     adc    al, [edi]             
    47     pushfd                      ; CF(进位标志)压栈
    48     mov    [ebx], al            
    49     add    esi, 1               ; 更新指针
    50     add    edi, 1
    51     add    ebx, 1
    52     popfd                       ; CF 出栈,准备进行下一次加法
    53     loop    L1                 
    54 
    55     mov    byte ptr [ebx],0     ; 最后一次加法,最高字节加上剩余的进位标志
    56     adc    byte ptr [ebx],0
    57     
    58     popad
    59     ret
    60 Extended_Add ENDP
    61 
    62 END main

    ● ASCII 长整数加法,结果输出 1000525533291780

     1 INCLUDE Irvine32.inc
     2 
     3 DECIMAL_OFFSET = 5                      ; 小数点位于位 5 的右边(没用到)
     4 .data
     5 decimal_one BYTE "100123456789765"            ; == 1001234567.89765
     6 decimal_two BYTE "900402076502015"            ; == 9004020765.02015
     7 sum BYTE (SIZEOF decimal_one + 1) DUP(0),0    ; 预留进位
     8 
     9 .code
    10 main PROC
    11     mov     esi, SIZEOF decimal_one - 1 ; 从最低位开始
    12     mov     edi, SIZEOF decimal_one
    13     mov     ecx, SIZEOF decimal_one
    14     mov     bh, 0                       ; 旧进位标志,初始化为 0
    15 
    16 L1:
    17     mov     ah, 0                       
    18     mov     al, decimal_one[esi] 
    19     add     al, bh                  ; 加旧进位
    20     aaa                             ; 调整和
    21     mov     bh, ah                  ; ah 存储了进位,将其放进 bh
    22     or      bh, 30h                 ; 转成  ASCII
    23     add     al, decimal_two[esi]    ; 加一个数字,过程同上
    24     aaa                             
    25     or      bh, ah                  ; 9 + 1 + 9 = 19 < 20,加了两次但最多进位 1
    26     or      bh, 30h                 ; 进位和结果都转成 ASCII
    27     or      al, 30h                 
    28     mov     sum[edi], al            ; 当前位结果放入内存
    29     dec     esi                     ; 指向下一对计算的数字
    30     dec     edi
    31     loop    L1
    32     mov     sum[edi], bh            ; 最后的进位放在预留的最高位上
    33 
    34     mov     edx, OFFSET sum
    35     call    WriteString
    36     call    Crlf    
    37     call WaitMsg
    38     exit
    39 main ENDP
    40 END main

    ● 压缩十进制加法,输出结果 00011743。逻辑简单,但是不能理解 daa 的实现方法

     1 INCLUDE Irvine32.inc
     2 
     3 .data
     4 packed_1 WORD 4536h
     5 packed_2 WORD 7207h
     6 sum DWORD ?
     7 
     8 .code
     9 main PROC
    10     mov    sum,0
    11     mov    esi,0
    12     mov eax,0
    13     
    14     mov    al,BYTE PTR packed_1[esi]   ; 低字节,daa 将 al 中的和转化为十进制和的低两位,放入内存
    15     add    al,BYTE PTR packed_2[esi]
    16     daa
    17     mov    BYTE PTR sum[esi],al
    18     
    19     inc    esi                         ; 中字节,包含进位
    20     mov    al,BYTE PTR packed_1[esi]
    21     adc    al,BYTE PTR packed_2[esi]
    22     daa
    23     mov    BYTE PTR sum[esi],al
    24 
    25     inc    esi                         ; 高字节,只考虑进位
    26     mov    al,0
    27     adc    al,0
    28     mov    BYTE PTR sum[esi],al
    29     
    30     mov    eax,sum
    31     call    WriteHex
    32     call    Crlf
    33     call WaitMsg
    34     exit
    35 main ENDP
    36 END main
  • 相关阅读:
    LNMP 部署
    zabbix3.2安装graphtree3.0.4
    升级java8---from centos
    mysql5.6-5.7性能调优
    samba server install
    centos7 zabbix3 install done
    实验四总结
    第五周学习小结
    个人的一些html、css笔记
    为什么wait,notify,notifyAll定义在Object中?
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9596452.html
Copyright © 2020-2023  润新知