0
点赞
收藏
分享

微信扫一扫

汇编程序的多模块化



首先通过使用ENTERN伪指令创建传统的多模块程序,这里的ENTERN伪指令实际上只起了调用其他模块里的过程前对此过程的声明作用。这里的被调用过程与一个模块表达式没有书写格式上的变化,源程序如下:

(_prompt.asm模块)


1. TITLE Prompt For Integers         (_prompt.asm)  
2.   
3. INCLUDE Irvine32.inc  
4. .code  
5. ;----------------------------------------------------  
6. PromptForIntegers PROC  
7.   
8. ; 提示用户输入三个整数,调用ReadInt读取输入返回到eax中,  
9. ; 然后把值插入到数组中.  
10. ; 参数:  
11. ;   ptrPrompt:PTR BYTE
12. ;   ptrArray:PTR DWORD
13. ;   arraySize:DWORD
14. ; 返回值:无  
15. ;-----------------------------------------------------  
16. arraySize   EQU [ebp+16]  
17. ptrArray    EQU [ebp+12]  
18. ptrPrompt   EQU [ebp+8]         ; [ebp+8]指向调用此模块(call指令)之前的入栈数据  
19.   
20.     enter   0,0           
21. ; enter指令自动为被调用过程创建堆栈框架(此处相当于push ebp;mov ebp,esp;sub esp,0),  
22. ; 并为局部变量创建堆栈空间(enter 0,0  前一个0表示局部变量占用的字节数,  
23. ; 后一个0表示从调用过程复制到当前堆栈框架中的堆栈框架指针的数目)  
24.     pushad              ; 8个通用寄存器入栈  
25.   
26.     mov ecx,arraySize       ; ecx表示数组的大小,这里同时是循环计数器  
27.     cmp ecx,0           ; 循环计数器 <= 0?  
28.     jle L2              ; 是:跳过循环体  
29.     mov edx,ptrPrompt       ; 否:把提示字符串首地址传递给edx  
30.     mov esi,ptrArray        ; esi指向数组的首地址  
31.   
32. L1: call    WriteString     ; 预先定义的过程,输出edx代表的字符串  
33.     call    ReadInt         ; 等待用户输入后,从标准输入中读取一个32位有符号整数并在eax中返回  
34.     call    Crlf              
35.     mov [esi],eax           ; 把输入的值存储在数组中  
36.     add esi,4           ; esi指向数组下一个元素  
37.     loop    L1  
38.   
39. L2: popad               ; 8个通用寄存器出栈  
40.     leave  
41. ; leave指令释放一个过程的堆栈框架,执行与enter相反的动作(此处相当于mov esp,ebp;pop ebp)  
42. ; 如果enter指令创建了局部变量,leave还要释放局部变量占用的堆栈空间  
43.     ret 12                
44. ; 调用此模块前,主模块会把此模块用到的相应参数入栈,这里12表示此模块结束后释放主模块中占用的堆栈空间  
45. ; 相当于依次执行ret;add esp,12的指令  
46. PromptForIntegers ENDP  
47. END


(_arrysum.asm模块):


    1. TITLE ArraySum Procedure             (_arrysum.asm)  
    2.   
    3. INCLUDE Irvine32.inc  
    4. .code  
    5. ArraySum PROC  
    6. ;  
    7. ; 计算有符号32位整数数组的各元素总和  
    8. ; 参数:  
    9. ;   ptrArray        ; 指向数组首地址  
    10. ;   arraySize       ; 数组的长度(DWORD)  
    11. ; 返回值:  EAX = sum  
    12. ;-----------------------------------------------------  
    13. ptrArray EQU [ebp+8]  
    14. arraySize EQU [ebp+12]  
    15.   
    16.     enter   0,0     ; enter指令创建堆栈框架,此处无局部变量  
    17.     push    ecx         ; 提示:eax作为返回值,不能入栈  
    18.     push    esi  
    19.   
    20.     mov eax,0       ; 初始化数组总和为0  
    21.     mov esi,ptrArray    ; 数组首地址  
    22.     mov ecx,arraySize   ; 数组大小,同时是循环计数器  
    23.     cmp ecx,0       ; 循环计数器 <= 0?  
    24.     jle L2          ; 是: 跳过循环体  
    25.   
    26. L1: add eax,[esi]       ; 否:把数组一个元素加到eax中  
    27.     add esi,4       ; 指向下一个数组元素  
    28.     loop    L1  
    29.   
    30. L2: pop esi  
    31.     pop ecx         ; 总和通过eax返回到调用过程(主模块)  
    32.     leave           ; 释放enter创建的堆栈框架  
    33.     ret 8           ; 释放调用过程中(主模块)的参数通过堆栈传递时占用的堆栈空间  
    34. ArraySum ENDP  
    35. END



    (_display.asm模块):


    1. TITLE DisplaySum Procedure      (_display.asm)  
    2.   
    3. INCLUDE Irvine32.inc  
    4. .code  
    5. ;-----------------------------------------------------  
    6. DisplaySum PROC  
    7.   
    8. ; 在控制台窗口中显示总和的值  
    9. ; 参数:  
    10. ;   ptrPrompt       ; 提示字符串首地址  
    11. ;   theSum      ; 数组各元素总和(DWORD)  
    12. ; 返回值: 无  
    13. ;-----------------------------------------------------  
    14.   
    15. theSum  EQU [ebp+12]  
    16. ptrPrompt   EQU [ebp+8]  
    17.   
    18.     enter   0,0     ; enter指令创建堆栈框架,此处无局部变量  
    19.     push    eax  
    20.     push    edx  
    21.   
    22.     mov edx,ptrPrompt   ; 预先定义的过程参数  
    23.     call    WriteString ; 输出提示字符串到屏幕  
    24.     mov eax,theSum  ; 预先定义的过程参数  
    25.     call    WriteInt        ; 输出数组总和到屏幕  
    26.     call    Crlf  
    27.   
    28.     pop edx  
    29.     pop eax  
    30.     leave  
    31.     ret 8           ; 返回到主模块并释放主模块调用此过程时占用的堆栈空间  
    32. DisplaySum ENDP  
    33. END



    (Sum_main.asm主模块):




      1. TITLE Integer Summation Program      (Sum_main.asm)  
      2.   
      3. ; 多模块程序例子:   (主模块/启动模块)  
      4. ; 这个程序提示用户输入3个32位有符号整数,  
      5. ; 然后把输入的整数存储到数组中并计算这个数组的总和,  
      6. ; 显示数组的总和到屏幕  
      7.   
      8. INCLUDE Irvine32.inc    ;INCLUDE 伪指令包含用户定义的.inc文件,其中可集中放置变量或过程的声明等信息  
      9.   
      10. EXTERN PromptForIntegers@0:PROC         ; EXTERN 伪指令在调用外部模块中的过程前声明,@0表示PromptForIntegers过程没有PROC伪指令参数  
      11. EXTERN ArraySum@0:PROC, DisplaySum@0:PROC   ; EXTERN 伪指令在调用外部模块中的过程前声明,其余同上  
      12.   
      13. ; 为被调用过程赋予其他的标号,方便主模块调用  
      14. ArraySum            EQU ArraySum@0  
      15. PromptForIntegers   EQU PromptForIntegers@0  
      16. DisplaySum      EQU DisplaySum@0  
      17.   
      18. Count = 3                                   ; 标号代表定义数组的大小  
      19.   
      20. .data  
      21. prompt1 BYTE  "Enter a signed integer: ",0  
      22. prompt2 BYTE  "The sum of the integers is: ",0  
      23. array   DWORD
      24. sum     DWORD
      25.   
      26. .code  
      27. main PROC  
      28.     call    Clrscr                          ; 清理屏幕  
      29.   
      30. ; 调用PromptForIntegers( addr prompt1, addr array, Count ),括号中为向被调用过程包含的参数  
      31.     push    Count  
      32.     push    OFFSET array  
      33.     push    OFFSET prompt1  
      34.     call    PromptForIntegers  
      35.   
      36. ; 调用eax = ArraySum( addr array, Count ),其中eax是被调用过程的返回值  
      37.     push    Count  
      38.     push    OFFSET array  
      39.     call    ArraySum  
      40.     mov sum,eax  
      41.   
      42. ; 调用DisplaySum( addr prompt2, sum )  
      43.     push    sum  
      44.     push    OFFSET prompt2  
      45.     call    DisplaySum  
      46.   
      47.     call    Crlf  
      48.     exit  
      49. main ENDP  
      50.   
      51. END main



      下面是这个程序运行的结果:

      汇编程序的多模块化_数组

      举报

      相关推荐

      0 条评论