• 《汇编语言 基于x86处理器》第八章高级过程部分的代码


    ▶ 书中第八章的程序,主要讲了子过程调用过程中寄存器、堆栈的使用

    ● 代码,简单的加法,使用两种调用规范

     1 INCLUDE Irvine32.inc
     2 
     3 .data
     4 word1 WORD 1234h
     5 word2 WORD 4111h
     6 
     7 .code
     8 main PROC
     9     call    Example1        ; 先用两种规范的子过程计算了 5 + 6,然后在主过程中计算 1234h + 4111h
    10     call    Example2
    11     
    12     movzx   eax, word1
    13     push    eax
    14     movzx   eax, word2
    15     push    eax
    16     call    AddTwo
    17     call    DumpRegs        ; 没有清空堆栈
    18     call    WaitMsg
    19     exit
    20 
    21 main ENDP
    22 
    23 Example1 PROC               ; C 规范
    24     push 5                  
    25     push 6
    26     call AddTwo_C
    27     add  esp, 8             ; 主调函数中清理栈
    28     call DumpRegs
    29     ret
    30 Example1 ENDP
    31 
    32 AddTwo_C PROC
    33     push ebp
    34     mov  ebp, esp
    35     mov  eax, [ebp + 12]
    36     add  eax, [ebp + 8] 
    37     pop  ebp
    38     ret     
    39 AddTwo_C ENDP
    40 
    41 Example2 PROC               ; STDCALL 规范
    42     push 5
    43     push 6
    44     call AddTwo
    45     call DumpRegs
    46     ret
    47 Example2 ENDP
    48 
    49 AddTwo PROC
    50     push ebp
    51     mov  ebp, esp
    52     mov  eax, [ebp + 12]
    53     add  eax, [ebp + 8]    
    54     pop  ebp
    55     ret  8                  ; 被调函数中清理栈
    56 AddTwo ENDP
    57 
    58 END main

    ● 输出结果

    EAX=0000000B  EBX=010D1000  ECX=013C105A  EDX=013C105A
    ESI=013C105A  EDI=013C105A  EBP=012FFA50  ESP=012FFA3C
    EIP=013C36D1  EFL=00000206  CF=0  SF=0  ZF=0  OF=0  AF=0  PF=1
    
    
    EAX=0000000B  EBX=010D1000  ECX=013C105A  EDX=013C105A
    ESI=013C105A  EDI=013C105A  EBP=012FFA50  ESP=012FFA3C
    EIP=013C36EB  EFL=00000202  CF=0  SF=0  ZF=0  OF=0  AF=0  PF=0
    
    
    EAX=00005345  EBX=010D1000  ECX=013C105A  EDX=013C105A
    ESI=013C105A  EDI=013C105A  EBP=012FFA50  ESP=012FFA40
    EIP=013C36B4  EFL=00000202  CF=0  SF=0  ZF=0  OF=0  AF=0  PF=0

    ● 代码,数组填充。堆栈传参的典型过程。

     1 INCLUDE Irvine32.inc
     2 
     3 .data
     4 count = 100
     5 array WORD count DUP(?)
     6 
     7 .code
     8 main PROC
     9     push OFFSET array
    10     push COUNT
    11     call ArrayFill
    12     call WaitMsg
    13     exit
    14 main ENDP
    15 
    16 ArrayFill PROC
    17     push    ebp             ; 先调整寄存器,压栈,再处理参数
    18     mov     ebp, esp
    19     pushad                  ; 栈中依次(地址递减)为:OFFSET array,COUNT,WaitMsg 地址,ebp
    20     mov     esi, [ebp+12]
    21     mov     ecx, [ebp+8]
    22     cmp     ecx, 0          ; 数组长度为 0 ,已经完成
    23     je      L2
    24 
    25 L1:
    26     mov     eax, 10000h
    27     call    RandomRange
    28     mov     [esi], ax       ; 生成的随机数塞进数组
    29     add     esi, TYPE WORD  ; esi 指向数组中下一个元素
    30     loop    L1
    31 
    32 L2:
    33     popad                   ; 恢复寄存器
    34     pop    ebp              ; ebp 恢复全体压栈以前的状态
    35     ret    8                ; 清空栈clean up the stack
    36 ArrayFill ENDP
    37 
    38 END main

    ● 代码,使用局部数组,即强行在堆栈顶开辟一块空间使用。

     1 INCLUDE Irvine32.inc
     2 
     3 .code
     4 main PROC
     5     call    makeArray
     6     mov     eax, 0
     7     call    WaitMsg
     8     exit
     9 main ENDP
    10 
    11 makeArray PROC
    12     push    ebp
    13     mov     ebp, esp
    14     sub     esp, 32             ; 为了对齐双字边界,30 向上取整到 4 的倍数
    15     lea     esi, [ebp-32]       ; 可以使用 [ebp-30]
    16     mov     ecx, 32
    17 L1:
    18     mov     BYTE PTR [esi], '*' ; 填充
    19     inc     esi
    20     loop    L1
    21 
    22     add     esp, 32             ; 恢复栈顶指针和寄存器
    23     pop     ebp
    24     ret
    25 makeArray ENDP
    26 
    27 END main

    ● 代码,递归计算 1 + 2 + ... + N,使用同一个寄存器存储每一次递归的计算结果。

     1 INCLUDE Irvine32.inc
     2 .data
     3 N = 10
     4 
     5 .code
     6 main PROC
     7     mov  ecx, N         ; 计算参数
     8     mov  eax, 0         ; 计算结果
     9     call CalcSum        ; 调用函数
    10 L1:   
    11     call WriteDec       ; 输出结果
    12     call Crlf
    13     call WaitMsg
    14     exit
    15 main ENDP
    16 
    17 CalcSum PROC
    18     cmp  ecx, 0         ; 递归脱出条件,类似手工循环
    19     jz   L2             
    20     add  eax, ecx       ; 其余情况,计算并进行下一次递归
    21     dec  ecx       
    22     call CalcSum
    23 L2: 
    24     ret
    25 CalcSum ENDP
    26 
    27 END Main

    ● 代码,递归计算阶乘,注意递归过程仅用于建栈,脱出过程才进行计算。

     1 INCLUDE Irvine32.inc
     2 
     3 .code
     4 main PROC
     5     push 5              ; 向函数传输的参数
     6     call Factorial      ; 调用函数
     7     call WriteDec    
     8     call Crlf
     9     call WaitMsg
    10     exit
    11 main ENDP
    12 
    13 Factorial PROC
    14     push ebp
    15     mov  ebp, esp
    16     mov  eax, [ebp+8]   ; 获取参数
    17     cmp  eax, 0         ; 参数大于零,跳转 L1 计算,否则置 eax = 1,返回
    18     ja   L1     
    19     mov  eax, 1
    20     jmp  L2
    21 
    22 L1: 
    23     dec  eax    
    24     push eax    
    25     call Factorial
    26 
    27 ReturnFact:             ; 栈全部压好了,在返回路径上逐步计算
    28     mov  ebx, [ebp+8]   
    29     mul  ebx         
    30 
    31 L2:    
    32     pop  ebp
    33     ret  4
    34 Factorial ENDP
    35 
    36 END main

    ● 代码,交换数组元素,重点在说明 PROC 的传参过程,类似 C

     1 INCLUDE Irvine32.inc
     2 
     3 Swap PROTO,                 ; 声明过程
     4     pValX:PTR DWORD,
     5     pValY:PTR DWORD
     6 
     7 .data
     8 array  DWORD  10000h,20000h
     9 
    10 .code
    11 main PROC      
    12     mov  esi,OFFSET array   ; 交换前显示数组元素
    13     mov  ecx, 2
    14     mov  ebx,TYPE array
    15     call DumpMem
    16 
    17     INVOKE Swap, ADDR array, ADDR [array+4] ; 实参列表
    18 
    19     call DumpMem
    20     call WaitMsg
    21     exit
    22 main ENDP
    23 
    24 Swap PROC USES eax esi edi, pValX:PTR DWORD, pValY:PTR DWORD    ; 形参列表为两个指针
    25     mov esi, pValX          ; 指针元素放入寄存器
    26     mov edi, pValY
    27     mov eax,[esi]           ; 数组元素放入寄存器
    28     xchg eax,[edi]          ; 交换寄存器中元素和内存中的元素
    29     mov [esi],eax           ; 寄存器元素放回内存
    30     ret
    31 Swap ENDP
    32 
    33 END main
  • 相关阅读:
    Pro Andorid3第二章:设置开发环境
    Seminar 记录
    安装CGAL
    Literature review
    第七章:清楚简洁的英文 《英语科技写作(文法与修辞原则)》by 方克涛
    幻灯片制作去除模板背景
    vs2008下设置.h, .lib和 .dll 的路径配置全图及其意义
    配置环境变量
    PPT制作技巧
    #include文件时用双引号和尖括号的区别
  • 原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9613507.html
Copyright © 2020-2023  润新知