《汇编语言 基于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
原文地址:https://www.cnblogs.com/cuancuancuanhao/p/9613507.html