05汇编模块化程序设计

一、子程序结构

1.子程序设计

  • 子程序框架
//子程序框架
子程序名 proc;子程序开始
		push ...1;保护寄存器
		push ...2
		...;子程序体
		pop  ...2;恢复寄存器
		pop  ...1
		ret;子程序返回
子程序名 endp;子程序结束

RET指令返回主程序,CALL指令调用子程序
利用过程定义,获得子程序名和调用属性
压入和弹出操作要成对使用,保持堆栈平衡
子程序开始保护寄存器,返回前相应恢复
安排在代码段的主程序之外
子程序允许嵌套和递归

子程序返回指令RET

;ret指令的功能:
1.弹出返回地址;从当前堆栈顶部弹出内容作为返回地址
2.转移到返回地址

ret ;无参数返回:出栈返回地址
ret i16;有参数返回:出栈返回地址,ESP<-ESP+i16

ret;栈顶数据出栈到指令寄存器EIP
   ;EIP=SS:[ESP],ESP=ESP+4
   ;数据进入EIP,就作为下条要执行指令的地址
  • 子程序调用
//子程序调用
call name

;call 指令的功能:
1.入栈返回地址;用在主程序中,实现子程序的调用,将下条指令的地址压入堆栈(顶部)
2.转移到目标地址

call label;调用标号制定的子程序
call reg32/reg16;调用寄存器指定地址的子程序
call mem48/mem32/mem16;调用存储单元指定地址的子程序
call label
next:...
;相当于
push next;入栈返回地址,ESP=ESP-4,SS:[ESP]=EIP(EIP->next)
jmp label;转移目标地址:EIP=EIP+偏移量

2.参数传递

入口参数:
主程序 —> 子程序
出口参数:
子程序 —>主程序

参数的具体内容:
数据本身(传递数值)
数据的存储地址(传递地址,传递引用)

参数传递的方式

  1. 通用寄存器
  2. 共享变量
  3. 堆栈
寄存器传递参数

最简单和常用的参数传递方法;
把参数存于约定的寄存器;
►少量数据直接传递数值
►大量数据只能传递地址
带有出口参数的寄存器不能保护和恢复;
带有入口参数的寄存器可以保护、也可以不保护,但最好能够保持一致

共享变量传递参数

子程序和主程序使用同一个变量名存取数据;
如果变量定义和使用不在同一个程序模块中,需要利用PUBLIC、EXTREN声明;
共享变量传递参数,子程序的通用性较差;
特别适合在多个程序段间、尤其在不同的程序模块间传递数据;
共享变量对应高级语言的全局变量

堆栈传递参数

主程序将入口参数压入堆栈
►子程序从堆栈中取出参数
采用堆栈传递参数常是程式化的
►子程序设置EBP等于当前ESP
►利用EBP相对寻址访问堆栈中的参数
出口参数通常不使用堆栈传递
高级语言函数调用的参数实质是堆栈传递参数

二、多模块程序结构

1.程序模块

MASM支持的多模块方法:1.源文件包含;2.模块连接;
3.子程序库;4.库文件包含

  • 源文件包含
    大型源程序可以合理地分放在若干个文本文件中

1.各种常量定义、声明语句等组织在包含文件(*.INC)
2.常用的或有价值的宏定义存放在宏定义文件(*.MAC)
3.常用的子程序形成汇编语言源文件(.ASM)
4.任何文本文件

使用源文件包含微指令inlcude
include 文件名
;将指定文件内容插入主体源程序

示例:

;文件名:eg0508.inc,程序的数据段内容
.data
...
;文件名:eg0508s.asm,子程序
rdhd proc;十六进制输入子程序
...
dphd proc;十六进制输出子程序
...
write proc;显示有符号十进制数字
...
;文件名: eg0508.asm,主程序
include io32.inc;包含软件I/O库声明
inclue eg0508.inc;包含数据段
.code;代码段,主程序
...
exit 0;主程序结束
include eg0508s.asm;包含子程序代码
end start

源文件包含的使用
被包含文件:
1.文件名要符合操作系统规范
2.只能是文本文件
3.内容被插入源文件包含include语句所在的位置
实质仍然是一个源程序:
1.只是分开在若干文件中
2.只需针对主体源程序文件进行汇编、连接

  • 模块连接

子程序单独编写一个源程序文件:
使用共同伪指令PUBLIC和外部伪指令EXTERN声明
子程序在代码段,与主程序文件采用相同的存储模型
没有开始执行和结束执行点,但有汇编结束语句
处理好子程序与主程序之间的参数传递问题

;定义标识符的模块使用 
public 标识符 [,标识符 …] 
;调用标识符的模块使用
 extern 标识符:类型 [,标识符:类型 …]

示例

;文件名:eg0508s.asm,子程序
	public rdhd,dphd,write;子程序共用
	extern temp:dword;外部变量
rdhd proc;十六进制输入子程序
...
end;汇编结束

模块连接的操作过程:
子程序单独编写一个源程序文件
子程序源文件汇编形成目标模块OBJ文件
连接时输入子程序目标模块文件名

  • 子程序库
    子程序库是子程序模块的集合,便于统一管理子程序

编写存入库文件的子程序:
1.遵循更加严格的子程序模块要求
2.应该遵循一致的规则(以免使用时造成混乱)

子程序库的使用

子程序单独编写一个源程序文件
子程序源文件汇编形成目标模块OBJ文件
利用库管理工具程序把子程序模块加入到子程序库
在连接主程序时提供子程序库文件名

  • 库文件包含
    要使用已存入库文件中的子程序
    在主程序源文件中用库文件包含伪指令includelib的声明
使用库文件包含伪指令includelib
includelib 文件名
;使用库文件中的子程序

库文件包含的使用

将子程序源文件汇编、模块文件加入子程序库
源文件中用库文件包含伪指令includelib声明
正常对主程序汇编、连接,无需在连接时输入库文件名:
编写主程序、子程序更加独立
子程序使用更方便

2.宏汇编

;宏定义
宏名 macro [形参表]
...;宏定义体
endm
;宏定义 
WriteString macro msg 
			push eax
			lea eax,msg 
			call dispmsg 
			pop eax 
			endm
;宏调用(宏指令)
 WriteString msg
;宏展开
push eax 
lea eax,msg 
call dispmsg
pop eax

宏汇编的特点

1.宏需要先定义后使用,且不必在任何段中:常常书写于源程序开始位置;常用的宏定义可以单独写成一个宏定义文件
2.宏定义中更改了寄存器内容,最好进行保护和恢复
3.宏定义的参数灵活,允许嵌套和递归调用
4.宏调用不需要控制的转移与返回:宏调用将相应的语句序列复制到宏指令的位置;宏展开将嵌入源程序,成为一体

宏与子程序的对比

子程序
简化程序宏仅是源程序级的简化:宏调用在汇编时进行程序语句的展开,不需要返回;不减小目标程序,执行速度没有改变子程序不仅简化源程序,还是目标程序级的简化:子程序调用在执行时由call指令转向、ret指令返回;形成的目标代码较短,执行速度减慢
传递参数宏通过形参、实参结合实现参数传递:使用软件方法,简洁直观、灵活多变;传递出错多体现为语法错误,易于发现子程序利用寄存器、存储单元或堆栈等实现:运用硬件本身,规则严格、方法固定;传递出错常反映为逻辑或运行错误,较难排除
选用原则当程序段较短或要求较快执行时,选用宏,宏常依附于源程序,适合进行全局性预处理当程序段较长或为减小目标代码时,选用子程序,子程序更具有独立性,可以分别编写
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全糖去冰不加料

打赏一块钱💰也是钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值