CALL
指令用在主程序中,实现子程序的调用子程序和主程序可以在同一个代码段内,也可以在不同段内。因而,与无条件转移指令 JMP 类似,子程序调用指令 CALL 也可以分成段内调用(近调用)和段间调用(远调用),同时, CALL指令的目标地址也可以采用相对寻址、直接寻址或间接寻址。
CALL指令用在主程序中,实现子程序的调用
CALL 指令实际上就是入栈指令 PUSH 和转移指令 JMP 的组合
调用标号指定的子程序
CALL label ;调用标号指定的子程序
调用寄存器指定地址的子程序
CALL reg32/reg16 ;调用寄存器指定地址的子程序
调用存储单元指定地址的子程序
CALL mem48/mem32/mem16 ;调用存储单元指定地址的子程序
CALL分成段内调用(近调用)和段间调用(远调用)目标地址支持相对寻址、直接寻址或间接寻址
RET指令用在子程序结束,实现返回主程序
RET
无参数返回:出栈返回地址
RET i16
有参数返回:出栈返回地址,ESP←ESP+i16
过程名为符合语法的标识符
过程名 proc ;过程定义
... ;过程体
过程名 endp ;过程结束
MASM会根据存储模型等信息确定子程序的远近调用,并相应产生调用、返回指令
子程序框架
标识符 proc ;过程定义(子程序开始)
push ...1 ;保护寄存器
push ...2
… ;子程序体
pop ...2 ;恢复寄存器
pop ...1
ret ;子程序返回
标识符 endp ;过程(子程序)结束
- 主程序与子程序间通过参数传递建立联系
►入口参数(输入参数):主程序→子程序
►出口参数(输出参数):子程序→主程序- 参数的具体内容
►数据本身(传递数值)
►数据的存储地址(传递地址,传递引用)
十六进制显示:
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
共享变量对应高级语言的全局变量
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
采用堆栈传递参数可以程式化
• 子程序设置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