2025年4月3日 星期四 乙巳(蛇)年 正月初四 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > 汇编

汇编语言用INVOKE和PROTO新建模块

时间:03-05来源:作者:点击数:81

32 位模式中,可以用 Microsoft 的 INVOKE、PROTO 和扩展 PROC 伪指令新建多模块程序。与更加传统的 CALL 和 EXTERN 相比,它们的主要优势在于:能够将 INVOKE 传递的参数列表与 PROC 声明的相应列表进行匹配。

现在用 INVOKE、PROTO 和高级 PROC 伪指令重新编写 ArraySum。为每个外部过程创建含有 PROTO 伪指令的头文件是很好的开始。每个模块都会包含这个文件 ( 用 INCLUDE 伪指令) 且不会增加任何代码量或运行时开销。

如果一个模块不调用特定过程,汇编器就会忽略相应的 PROTO 伪指令。

sum.inc 头文件本程序的 sum.inc 头文件如下所示:

  • ; (sum.inc)
  • INCLUDE Irvine32.inc
  • PromptForIntegers PROTO,
  • ptrPrompt:PTR BYTE, ; 提示字符串
  • ptrArray:PTR DWORD, ; 数组指针
  • arraySize:DWORD ; 数组大小
  • ArraySum PROTO,
  • ptrArray:PTR DWORD, ; 数组指针
  • arraySize:DWORD ; 数组大小
  • DisplaySum PROTO,
  • ptrPrompt:PTR BYTE, ; 提示字符串
  • theSum:DWORD ; 数组之和

_prompt 模块

_prompt.asm 文件用 PROC 伪指令为 PromptForIntegers 过程声明参数,用 INCLUDE 将 sum.inc 复制到本文件:

  • ; 提示整数输入请求 (_prompt.asm)
  • INCLUDE sum.inc ; 获得过程原型
  • .code
  • ;-----------------------------------------------------
  • PromptForIntegers PROC,
  • ptrPrompt:PTR BYTE, ; 提示字符串
  • ptrArray:PTR DWORD, ; 数组指针
  • arraySize:DWORD ; 数组大小
  • ;
  • ; 提示用户输入数组元素值,并用用户输入
  • ; 填充数组
  • ; 返回:无
  • ;-----------------------------------------------------
  • pushad ; 保存所有寄存器
  • mov ecx,arraySize
  • cmp ecx,0 ; 数组大小 <= 0?
  • jle L2 ; 是: 退出
  • mov edx,ptrPrompt ; 提示信息的地址
  • mov esi,ptrArray
  • L1: call WriteString ; 显示字符串
  • call ReadInt ; 把整数读入EAX
  • call Crlf ; 换行
  • mov [esi],eax ; 保存入数组
  • add esi,4 ; 下一个整数
  • loop L1
  • L2: popad ; 恢复所有寄存器
  • ret
  • PromptForIntegers ENDP
  • END

与前面的 PromptForIntegers 版本比较,语句 enter 0,0 和 leave 不见了,这是因为当 MASM 遇到 PROC 伪指令及其声明的参数时,会自动生成这两条语句。同样,RET 指令也不需要自带常数参数了,PROC 会处理好。

_arraysum 模块

接下来,_arraysum.asm 文件包含了 ArraySum 过程:

  • ; ArraySum 过程 (_arrysum.asm)
  • INCLUDE sum.inc
  • .code
  • ;-----------------------------------------------------
  • ArraySum PROC,
  • ptrArray:PTR DWORD, ; 数组指针
  • arraySize:DWORD ; 数组大小
  • ;
  • ; 计算 32 位整数数组之和
  • ; 返回: EAX = 和数
  • ;-----------------------------------------------------
  • push ecx ; EAX 不入栈
  • push esi
  • mov eax,0 ; 和数清零
  • mov esi,ptrArray
  • mov ecx,arraySize
  • cmp ecx,0 ; 数组大小 <= 0?
  • jle L2 ; 是: 退出
  • L1: add eax,[esi] ; 将每个整数加到和数中
  • add esi,4 ; 指向下一个整数
  • loop L1 ; 按数组大小重复
  • L2: pop esi
  • pop ecx ; 用 EAX 返回和数
  • ret
  • ArraySum ENDP
  • END

_display 模块

_display.asm 文件包含了 DisplaySum 过程:

  • ; DisplaySum 过程 (_display.asm)
  • INCLUDE Sum.inc
  • .code
  • ;-----------------------------------------------------
  • DisplaySum PROC,
  • ptrPrompt:PTR BYTE, ; 提示字符串
  • theSum:DWORD ; 数组之和
  • ;
  • ; 控制台显示和数
  • ; 返回:无
  • ;-----------------------------------------------------
  • push eax
  • push edx
  • mov edx,ptrPrompt ; 提示信息的指针
  • call WriteString
  • mov eax,theSum
  • call WriteInt ; 显示 EAX
  • call Crlf
  • pop edx
  • pop eax
  • ret
  • DisplaySum ENDP
  • END

Sum_main 模块

Sum_main.asm ( 启动模块 ) 包含主程序并调用所有其他的过程。它使用 INCLUDE 从 sum.inc 复制过程原型:

  • ; 整数求和程序 (Sum_main.asm)
  • INCLUDE sum.inc
  • Count = 3
  • .data
  • prompt1 BYTE "Enter a signed integer: ",0
  • prompt2 BYTE "The sum of the integers is: ",0
  • array DWORD Count DUP(?)
  • sum DWORD ?
  • .code
  • main PROC
  • call Clrscr
  • INVOKE PromptForIntegers, ADDR prompt1, ADDR array, Count
  • INVOKE ArraySum, ADDR array, Count
  • mov sum,eax
  • INVOKE DisplaySum, ADDR prompt2, sum
  • call Crlf
  • exit
  • main ENDP
  • END main

小结 本节与上一节《用Extern伪指令新建模块》展示了在 32 位模式中新建多模块程序的两种方法:

  • 第一种使用 的是更传统的EXTERN伪指令;
  • 第二种使用的是INVOKE. PROTO和PROC的高级功能。

后一种中的伪指令简化了很多细节,并为 Windows API 函数调用进行了优化。此外,它们还隐藏了一些细节,因此,编程者可能更愿意使用显式的堆栈参数和 CALL 及 EXTERN 伪指令。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门