【汇编语言】子程序结构

您所在的位置:网站首页 子程序调用的步骤 【汇编语言】子程序结构

【汇编语言】子程序结构

2024-07-16 05:02| 来源: 网络整理| 查看: 265

子程序结构

在这里插入图片描述

文章目录 子程序结构一、子程序指令(1)子程序调用指令CALL1.子程序调用指令CALL的功能2.子程序调用指令CALL的使用方法3.子程序调用指令CALL的分类 (2)子程序返回指令RET(3)过程定义伪指令 二、参数传递(1)寄存器传递参数(2)共享变量传递参数(3)堆栈传递参数

一、子程序指令 (1)子程序调用指令CALL

CALL指令用在主程序中,实现子程序的调用子程序和主程序可以在同一个代码段内,也可以在不同段内。因而,与无条件转移指令 JMP 类似,子程序调用指令 CALL 也可以分成段内调用(近调用)和段间调用(远调用),同时, CALL指令的目标地址也可以采用相对寻址、直接寻址或间接寻址。

1.子程序调用指令CALL的功能

CALL指令用在主程序中,实现子程序的调用

功能1:将下条指令的地址压入堆栈(顶部)功能2:转移到目标地址

CALL 指令实际上就是入栈指令 PUSH 和转移指令 JMP 的组合

2.子程序调用指令CALL的使用方法

调用标号指定的子程序

CALL label ;调用标号指定的子程序

调用寄存器指定地址的子程序

CALL reg32/reg16 ;调用寄存器指定地址的子程序

调用存储单元指定地址的子程序

CALL mem48/mem32/mem16 ;调用存储单元指定地址的子程序 3.子程序调用指令CALL的分类

CALL分成段内调用(近调用)和段间调用(远调用)目标地址支持相对寻址、直接寻址或间接寻址

在这里插入图片描述

(2)子程序返回指令RET

RET指令用在子程序结束,实现返回主程序

功能1:从当前堆栈顶部弹出内容作为返回地址功能2:转移到返回地址 RET

无参数返回:出栈返回地址

RET i16

有参数返回:出栈返回地址,ESP←ESP+i16

在这里插入图片描述

(3)过程定义伪指令

过程名为符合语法的标识符

过程名 proc ;过程定义 ... ;过程体 过程名 endp ;过程结束

MASM会根据存储模型等信息确定子程序的远近调用,并相应产生调用、返回指令

子程序框架

标识符 proc ;过程定义(子程序开始) push ...1 ;保护寄存器 push ...2 … ;子程序体 pop ...2 ;恢复寄存器 pop ...1 ret ;子程序返回 标识符 endp ;过程(子程序)结束 RET指令返回主程序,CALL指令调用子程序利用过程定义,获得子程序名和调用属性压入和弹出操作要成对使用,保持堆栈平衡子程序开始保护寄存器,返回前相应恢复安排在代码段的主程序之外子程序允许嵌套和递归 二、参数传递 主程序与子程序间通过参数传递建立联系 ►入口参数(输入参数):主程序→子程序 ►出口参数(输出参数):子程序→主程序参数的具体内容 ►数据本身(传递数值) ►数据的存储地址(传递地址,传递引用) (1)寄存器传递参数 最简单和常用的参数传递方法把参数存于约定的寄存器 ►少量数据直接传递数值 ►大量数据只能传递地址带有出口参数的寄存器不能保护和恢复带有入口参数的寄存器可以保护、也可以不保护,但最好能够保持一致

十六进制显示:

INCLUDE io32.inc .data;数据段 regd byte 'EAX=',8 dup(0),'H',0 .code start:;代码段,主程序 mov eax,1234abcdh ;假设一个数据 xor ebx,ebx ;相对寻址访问字符串 mov ecx,8 ;8位十六进制数 again: rol eax,4 ;高4位循环移位进入低4位 push eax;也可以用mov edx,eax call htoasc ;调用子程序htoasc mov regd+4[ebx],al ;保存转换后的ASCII码 pop eax ;也可以用moveax,edx inc ebx loop again mov eax,offset regd call dispmsg ;显示 exit 0 ;代码段,子程序 htoasc proc and al,0fh ;只取AL的低4位 or al,30h ;AL高4位变成3 cmp al,39h ;是0~9,还是A~F jbe htoend add al,7 ;是A~F,ASCII码再加上7 htoend: ret ;子程序返回 htoasc endp end start

在这里插入图片描述

(2)共享变量传递参数

共享变量对应高级语言的全局变量

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

二进制输入子程序:

;代码段,子程序:输入32位二进制数 rdbd proc ;出口参数:共享变量TEMP push eax ;寄存器保护 push ebx push ecx rdbd1: xor ebx,ebx ;EBX用于存放二进制结果 mov ecx,32 ;限制输入字符的个数 rdbd2: call readc ;输入一个字符 cmp al,'0' ;检测键入字符是否合法 jb rderr ;不合法则转到出错处理 cmp al,'1' ja rderr sub al,'0' ;对输入的字符进行转化 shl ebx,1 ;EBX的值乘以2(左移1位) or bl,al ;BL和AL相加(或) loop rdbd2 ;循环输入字符 mov temp,ebx ;把二进制结果存放TEMP返回 call dispcrlf ;分行 pop ecx pop ebx pop eax ret rderr: mov eax,offset errmsg ;显示错误信息 call dispmsg jmp rdbd1 ;重新输入 errmsg byte 0dh,0ah,'Input error, enter again: ',0 rdbd endp

在这里插入图片描述

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

采用堆栈传递参数可以程式化 • 子程序设置EBP等于当前ESP • 利用EBP相对寻址访问堆栈中的参数

计算有符号数平均值子程序:

INCLUDE io32.inc .data ;数据段 array dword 675,354,-34,198,267,0,9,2371,-67,4257 .code ;代码段,主程序 push lengthof array ;压入数据个数(4个字节) push offset array ;压入数组地址(4个字节) call mean ;调用求平均值子程序 add esp,8 ;主程序平衡堆栈(弹出8个字节) call dispsid ;显示平均值EAX(出口参数) ;代码段,子程序:计算32位有符号数平均值 mean proc ;入口参数:顺序压入个数和地址 push ebp ;出口参数:EAX=平均值 mov ebp,esp push ebx ;保护寄存器 push ecx push edx mov ebx,[ebp+8] ;EBX=取出的数组地址 mov ecx,[ebp+12] ;ECX=取出的数据个数 xor eax,eax ;EAX保存和值 xor edx,edx ;EDX=指向数组元素 mean1: add eax,[ebx+edx*4] ;求和 add edx,1 ;指向下一个数据 cmp edx,ecx ;比较个数 jb mean1 ;增量计数循环 cdq ;将累加和EAX符号扩展到EDX ;将EAX最高位填入EDX所有位 idiv ecx ;有符号数除法,EAX=平均值 pop edx ;恢复寄存器 pop ecx pop ebx pop ebp ret 8;子程序平衡堆栈 mean endp

在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3