汇编语言程序设计实验(六)——子程序设计

1.实验目的及内容

理解子程序结构的特点,熟悉子程序参数传递的方法,掌握子程序的编写。

2、实验内容

2.1 二进制输入输出子程序

(1) 二进制输入子程序

编写二进制输入子程序、以及验证子程序的主程序,并运行正确。
代码思路:(1)利用字符输入子程序readc输入一个字符,判断是否是0或1,若合法则直接减去30h转化为数值。
(2) 重复转换字符的同时,需要将前面一次得到的总数值左移一位,并与刚得到的新数值进行相加。
(3) 如果输入了非’‘0’‘或非’‘1’'数值或者数据位数超出边界,则转至报错提示。

			include io32.inc
.data
count	= 5				;预留五个空间
array	dword count dup(0)	;声明数组
temp 	dword	?			;工具变量
.code
start:
		mov	ecx, count
		mov ebx, offset array	;初始化数组指针
again:	call rdbd				;调用子程序,从键盘读一个数据
		mov eax,temp			;获得出口参数
		mov [ebx],eax			;存放到输入缓冲区
		call dispbd
		add ebx,4				;数组指针移动
		loop again	
		exit 0


		
rdbd	proc					;二进制输入子程序、
		push eax				;出口参数,共享工具变量temp
		push ebx	
		push ecx
rdbd1:	xor ebx,ebx				;ebx用于存放二进制结果
		mov ecx,32				;限制输入字符的个数到32个
rdbd2:	call readc				;输入一个字符
		cmp al,'0'				;0小,转至报错
		jb rderr				
		cmp al,'1'				;1大,转至报错
		ja rderr
		sub al,'0'				;获得真正的数据
		shl ebx,1				;前边输入后转化为二进制的数据左移一位再相加
		or bl,al				;bl和al相加
		loop rdbd2				;循环键入字符
		mov temp,ebx			;把ebx的二进制结果存放于temp返回
		call dispcrlf
		pop ecx
		pop ebx
		pop eax
		ret
rderr:	mov eax,offset errmsg	;显示错误信息
		call dispmsg
		jmp rdbd1
errmsg 	byte 0dh,0ah,'Inpput error,enter again:',0
rdbd 	endp					;子程序结束
		end start

运行结果:
在这里插入图片描述

(2) 二进制显示子程序

编写二进制显示子程序、以及验证子程序的主程序(教材习题5.8),并运行正确。
代码思路:将得到的二进制数每次右移一位,通过判断CF是否为1来分别处理,处理时加30H转化为ACSII码,后将每次得到的ACSII码入栈,此时在原数据中每个位在栈中就是低位到高位了,输出的时候依次从栈中弹出就是正确的顺序。

						include io32.inc
			.data
array 		dword	10110101b,1010000101b,0001000100001000101b,1001010101010b
writebuf	byte	12 dup (0)		;显示缓冲区

			.code			
start:
			mov ecx, lengthof array	;数组长度计数器
			mov ebx, 0					;初始化数组指针
again:		mov eax, array[ebx*4]		;逐个取出字符数组中元素
			call write
			call dispcrlf
			inc ebx						;数组指针移动
			loop again
			exit 0

			;子程序部分
write		proc
			push ebx					;数组指针先入栈
			push ecx					;计数器再入栈
			push edx					;存放每个留在缓冲区的二进制数的edx入栈
			mov ebx, offset writebuf	;字符内部数组首指针,指向显示缓冲区	
write1:		mov ecx,32					;每个二进制数最多表示到32位
			push ecx					;结束标志入栈
			mov edx,0
write2:		cmp eax,0					;移位结束标志
			jz	write3					;所有有效数字位已经右移完毕 
			shr eax,1					;每次将最低位移出来到CF
			jnc write_0					;若最低位为0
			jmp write_1 
write_0:	mov edx,0
			add edx,30h					;30h转换为ACSII码
			push edx					;该字符入栈
			jmp write2
write_1:	mov edx,1
			add edx,30h					;30h转换为ACSII码
			push edx					;该字符入栈
			jmp write2
write3:		pop edx						;对该数从高位到低位依次出栈
			cmp edx,ecx					;出栈结束判断
			jz	write4
			mov [ebx],dl				;将栈中弹出的值放入数组
			inc ebx						;数组指针移动			
			jmp write3
write4:		mov byte ptr[ebx],0			;给显示内容加上结尾标志
			mov eax,offset writebuf		;打印缓冲区内容
			call dispmsg				
			pop edx
			pop ecx
			pop ebx
			ret
write  		endp
			end start

运行结果:
在这里插入图片描述

2.2 主存区域数据显示子程序

编写逐个字节显示主存区域数据的子程序和主程序(教材习题5.13),并运行正确。
代码思路:利用十六进制字节显示程序,将主存区域的数据(如字符数组)按字节从低位(字符数组首元素)到高位进行输出即可,每按字节输出一个两位十六进制数数组指针移动一位。

代码:

				include io32.inc
				.data
array		byte 	'This is a test.'
writebuf	byte	12	dup (0)		;显示缓冲区
	
				.code
start:		
			mov eax,offset array 			    ;将数组主存偏移地址给eax
			mov ecx,lengthof array				;ecx存放字节数
			call dispmem						;调用子程序按字节从低地址到高地址输出
			exit 0
			
			;子程序部分
dispmem		proc
			push eax						;保护eax
			push ecx						;保护ecx			
			mov ebx,eax						;先把整体32位传给ebx,ebx做数组指针
again:		
			mov eax,[ebx]					;把数组中元素传给eax
			call disphb						;利用十六进制字节显示子程序
			mov eax, 32						;输出空格
			call dispc			
			inc ebx							;指针移动
			loop again
			dispmem endp					;子程序结束
			end start			
			
			

运行结果:在这里插入图片描述

2.3 十进制数的输入和显示子程序

(1) 有符号十进制数输入子程序

编写有符号十进制数的输入子程序、以及验证子程序的主程序,并运行正确。
思路:(1)首先判断数据是否是0、负数或正数,是0则直接显示’0’退出。
(2) 若输入有符号数为负数,显示符号’-’,求数据的绝对值。
(3) 数据除以10,如十进制正数123,
编写无符号十进制数的输入输出子程序、以及验证子程序的主程序,并运行正确。

.data
count 	= 5
array 	dword 	count	dup(0)
temp 	dword 	?
readbuf byte 	30 	dup(0)

.code
begin:
mov 	ecx,count	
mov 	ebx,offset array	;ebx为数组指针
again:	call read			;调用子程序,输入一个数据
		mov eax,temp 		;获得出口参数
		mov [ebx],eax		;存放到数据缓冲区
		add ebx,4			;指针移动
		dec ecx				;计数器递减
		jnz again			;循环判定条件
		exit 0				;退出主程序
		

read	proc				;输入有符号十进制数的子程序
		push eax			;出口参数:变量temp= 补码表示的二进制数值
		push ebx			;说明:负数用"-"引导
		push ecx 			
		push edx
read0:	mov eax,offset readbuf
		call readmsg		;输入一个字符串
		test eax,eax		;没有输入数据,转向错误处理
		cmp eax,12			;
		ja readerr			;输入超过12个字符,转向错误处理
		mov edx, offset readbuf	;edx指向输入缓冲区
		xor ebx,ebx			;ebx保存结果
		xor ecx,ecx 		;ecx为正负标志,0为正,-1为负
		mov al,[edx]		;取一个字符
		cmp al,'+'			;"+",继续
		jz read1			
		cmp al,'-'			;'-',设置-1标志
		jnz read2			;转至无符号处理区read2
		mov ecx,-1			;ecx保存符号位
read1:	inc edx				;取下一个字符
		mov al,[edx]
		test al,al			;是结尾0,转向求补码
		jz read3
read2:	cmp al,'0'			;不是0~9之间的数码,输入错误
		jb readerr			
		cmp al,'9'			
		ja readerr
		sub al,30h			;0~9之间的数码,转换为二进制数
		imul ebx,10			;原数值乘10:ebx = ebx *10
		jc readerr			;乘积溢出处理
		movzx eax,al		;零位扩展,便与相加
		add ebx,eax			;原数值乘10后与新数值相加
		cmp ebx,80000000h	;数据超过2^31,出错
readerr: mov eax,offset errmsg	;显示出错信息
		call dispmsg		
		jmp read0
;
read3:	test ecx,ecx		;判断是正数还是负数
		jz read4
		neg ebx				;是负数,进行求补
		jmp read5			
read4:	cmp ebx,7fffffffh	;正数超过2^31-1,出错
		ja readerr			
read5:	mov temp,ebx		;设置出口参数
		pop edx
		pop ecx
		pop ebx
		pop eax
		ret		
errmsg	byte 'error!!',13,10,0
read	endp
		end begin  
		
(2) 有符号十进制数显示子程序

编写有符号十进制数的显示子程序、以及验证子程序的主程序,并运行正确。

代码思路:(1) 首先判断给的数据是否是0,若为0则直接输出’0’。
(2) 是负数就在数组首端放置’-’,并求数据绝对值。
(3) 数据除以10,余数为10进制数码,加30h转化为ACSII码之后放在字符数组edx中保存。
(3) 重复(3),直到商为0时结束。

程序代码:

			include io32.inc
			.data
array		dword	1234567890,-1234,0,1,-987654321,32767,-32768,5678,-5678,9000
writebuf	byte	12 dup (0)		;显示缓冲区
			.code
start:			
			mov ecx, lengthof array	;数组长度计数器 
			mov ebx, 0
again:	mov eax, array[ebx*4]			;逐个取出字符数组中元素
		call write 						;调用子程序,显示一个数据
		call dispcrlf 		
		inc ebx							;数组指针移动
		loop again							
		exit 0
		
		;子程序部分
write 	proc
		push ebx
		push ecx
		push edx
		mov ebx, offset writebuf		;字符内部数组首指针,指向显示缓冲区
		test eax,eax					;判断正/负数(结果不为0),0(结果为0),
		jnz write1						;结果不为0,要么正,要么负,转至write1进一步
		mov byte ptr[ebx],'0'
		inc ebx							;按字节来,数组指针每次增一
		jmp write5
write1: jns write2						;是正数,转至write2处理
		mov byte ptr[ebx],'-'			;若为负数,则首先给字符数组传入一个负号
		inc ebx							;字符数组指针往后移动
		neg eax							;对eax进行求补
write2: mov ecx,10						;除数 ecx=10 
		push ecx										
write3: cmp eax,0						;若该位数为0,则转至write4
		jz write4						
		xor edx,edx						;edx,被除数高位清零
		div ecx							;除以10,取余
		add edx, 30h					;余数转化为ACSII码
		push edx						;将最低位数字压栈
		jmp write3
write4: pop edx							;从高位到低位依次弹出栈中存放的数字
		cmp edx,ecx						;和除数10进行比较,是结束标志10,转至打印处理
		je write5						
		mov [ebx],dl					;将余数edx的低八位dl放进字符数组
		inc ebx							;数组指针移动,循环输出存放的数
		jmp write4
write5: mov byte ptr[ebx],0				;字符数组结束标志
		mov eax, offset writebuf		;打印缓冲区内容
		call dispmsg					
		pop edx
		pop ecx
		pop ebx
		ret
write 	endp
		end start

运行结果:
在这里插入图片描述

(3) 无符号十进制数显示子程序

代码思路:(1) 首先判断给的数据是否是0,若为0则直接输出’0’。
(2 数据除以10,余数为10进制数码,加30h转化为ACSII码之后放在字符数组edx中保存。
(3) 重复(3),直到商为0时结束div。
(4) 持续pop出栈顶元素给edx,此时出栈顺序刚好是从高位到低位。

程序代码:

				include io32.inc
				.data
array		dword	1234567890,1234,0,1,987654321,32767,32768,5678,9000
writebuf	byte	12	dup (0)		;显示缓冲区
			
				.code
start:		mov ecx, lengthof array			;ecx为数组长度计数器		
			mov ebx, 0
again:
			mov eax, array[ebx*4] 			;使用共享变量传递参数
			call write						;调用子程序,显示一个数a,需要保存ebx、ecx的值
			call dispcrlf
			inc ebx							;数组指针移动
			loop again
			exit 0
			
			;子程序
			
write		proc	
			push ebx
			push ecx
			push edx
			mov ebx, offset writebuf		;字符内部数组首指针,指向显示缓冲区
			test eax,eax					;若为0,则直接输出
			jnz	write1						;若不为0,则进一步处理
			mov byte ptr[ebx],'0'			;直接填充字符0
			inc ebx							;数组指针后移
			jmp write4						;转至打印缓冲区
write1:		mov ecx,10						;被除数ecx= 10
			push ecx						;结束标志,当edx==ecx时结束pop
			
write2:		cmp eax,0						;判断商是否为0
			jz write3						;商为0,准备输出
			xor edx,edx						;被除数最高位清零
			div ecx							;商不为0,继续作除法
			add edx, 30h					;余数转化为ACSII码
			push edx						;余数(0~9区间)入栈
			jmp write2
write3:		pop edx							;从高位到低位依次pop出来
			cmp edx,ecx						;判断该数是否pop完毕
			jz write4						;pop完毕,转至输出缓冲区
			mov [ebx],dl					;把从栈中弹出的数位存至数组,ACSII<127,用dl即可
			inc ebx							;数字内部字符数组,每次增1
			jmp write3
write4:		mov byte ptr[ebx],0				;数组末尾加0
			mov eax, offset writebuf		;打印缓冲区内容
			call dispmsg	
			pop edx
			pop ecx
			pop ebx
			ret
write		endp	
			end start

在这里插入图片描述

(3) 无符号十进制数输入子程序
				include io32.inc
				.data
count 	= 5								;预留5个空间
array	dword	count	dup(0)			;初始化数组
temp	dword	?						;工具变量
readbuf	byte	30	dup(0)				;输入缓冲区	
	
				.code
start:		
			mov ecx,count		
			mov ebx,offset array			;ebx为数组指针
again:		call read						;调用子程序,输入一个数据
			mov eax,temp					;将返回的temp传回eax
			mov [ebx*4],eax					;存放到数据缓冲区
			inc ebx							;数组指针移动
			loop again						;循环将所有数据全部输出
			exit 0
			
			;子程序部分
read		proc	
			push ebx						;主程序中数组指针,需要保护
			push ecx						;主程序中计数器,需要保护
read0:		mov eax,offset readbuf			;输入缓冲区首地址传给eax
			call readmsg					;输入一个字符串
			test eax,eax					;没有输入数据,转向错误处理
			cmp eax,12						;输入若超过12个字符,则转向错误处理
			ja readerr
			mov edx, offset readbuf			;edx作为数组指针
			xor ebx,ebx						;ebx保存结果
read1:			
			mov al,[edx]					;从数组中取出一个字符
			test al,al						;判断是不是字符串结尾
			jz read2						;是结尾,输出该数
			inc edx
			cmp al,'0'						;若某一位小于0,输入错误
			jb readerr
			cmp al,'9'
			ja readerr
			sub al,30h						;ACSII码转化为0~9区间的数
			imul ebx,10						;ebx = ebx*10,给权重,初始时ebx=0
			jc readerr						;乘积溢出处理
			movzx eax,al					;零位扩展,便于前数ebx和当前位al相加
			add ebx,eax
			cmp ebx,0ffffffffh				;判断数据是否超过2^32-1
			jbe	read1						;没超过,继续取下一个字符
readerr:	mov eax,offset errmsg			;显示出错信息
			call dispmsg					
			jmp read0						;再次输入
read2:		mov temp,ebx					;设置出口参数
			pop ecx
			pop ebx
			ret
errmsg		byte 'error!!',13,10,0
read 		endp
			end start
			
			

在这里插入图片描述

  • 16
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值