首先通过使用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
下面是这个程序运行的结果: