je write5 mov [ebx],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
习题5.10
参考例5-6,编写实现32位无符号整数输入的子程序,并设计一个主程序验证。 答: include io32.inc .data count = 5 array dword count dup(0) tempdword ? ;共享变量 readbuf byte 30 dup(0) .code start: mov ecx,count mov ebx,offset array
again: call read ;调用子程序,输入一个数据 mov eax,temp ;获得出口参数 mov [ebx],eax ;存放到数据缓冲区 add ebx,4 dec ecx jnz again exit 0 read proc push eax push ebx push ecx push edx read0: mov eax,offset readbuf
call readmsg test eax,eax jz readerr cmp eax,10 ja readerr mov edx,offset readbuf xor ebx,ebx read1: mov al,[edx] read2: inc edx cmp al,'0' jb readerr cmp al,'9' ja readerr sub al,30h imul ebx,10 jc readerr movzx eax,al add ebx,eax cmp ebx,0ffffffffh ja readerr dec cx jnz read1 jmp read5
readerr: mov eax,offset errmsg call dispmsg jmp read0 ;
read5: mov temp,ebx pop edx pop ecx pop ebx pop eax ret
errmsg byte 'Input error, enter again: ',0 read endp end start
习题5.11
编写一个计算字节校验和的子程序。(所谓“校验和”是指不记进位的累加,常用于检查信息的正确性。)主程序提供入口参数,包括数据个数和数据缓冲区的首地址。子程序回送求
和结果这个出口参数。 答:
;计算字节校验和的通用过程
;入口参数:DS:EBX=数组的段地址:偏移地址 ECX=元素个数 ;出口参数:AL=校验和
;说明:除EAX/EBX/ECX外,不影响其他寄存器 checksumproc xor al,al ;累加器清0 sum: add al,[ebx] ;求和 inc ebx ;指向下一个字节 loop sum ret
checksumendp
习题5.12
编制3个子程序把一个32位二进制数用8位十六进制形式在屏幕上显示出来,分别运用如下3种参数传递方法,并配合3个主程序验证它。 (1)采用EAX寄存器传递这个32位二进制数。 (2)采用temp变量传递这个32位二进制数。 (3)采用堆栈方法传递这个32位二进制数。 答: (1) .code start: mov eax, 1234abcdh ;假设一个要显示的数据 call Bin2Hex exit 0 Bin2Hex proc push ecx mov ecx,8 ;8位十六进制数 again: rol eax,4 ;高4位循环移位进入低4位 push eax ;子程序利用AL返回结果,所以需要保存EAX中的数据 call htoasc ;调用子程序 pop eax ;恢复保存的数据 loop again pop ecx ret
htoasc proc ;将AL低4位表达的一位十六进制数转换为ASCII码 and al,0fh;只取AL的低4位 or al,30h ;AL高4位变成3,实现加30H cmp al,39h ;是0~9,还是A~F jbe htoend
add al,7 ;是A~F,其ASCII码再加上7 htoend: call dispc ret ;子程序返回 htoasc endp Bin2Hex endp end start
习题5.13
利用十六进制字节显示子程序DISPHB设计一个从低地址到高地址逐个字节显示某个主存区域内容的子程序DISPMEM。其入口参数:EAX=主存偏移地址,ECX=字节个数(主存区域的长度)。同时编写一个主程序进行验证。 答: ;数据段
var byte 'This is a test!' ;主程序 mov eax,offset var mov ecx,sizeof var call dispmem ;子程序
dispmem proc push ebx mov ebx,eax dispm1: cmp ecx,0 jz dispm2 mov al,[ebx] call disphb mov al,' ' call dispc inc ebx dec ecx jmp dispm1 dispm2: pop ebx ret
dispmem endp
习题5.14
数据输入输出程序。使用有符号十进制数据输入(例5-6)、求平均值(例5-7)以及输出子程序(例5-4),编程实现从键盘输入10个数据,并输出它们的平均值。
(1)编写主程序文件:定义必要的变量和交互信息,调用子程序输入10个数据,求平均值然后输出。
(2)编写子程序文件:包括3个子程序的过程定义。 (3)说明进行模块连接的开发过程,并上机实现。
(4)将子程序文件形成一个子程序库,说明开发过程并上机实现。 答: .data ; 数据定义 count = 10 array dword count dup(0) tempdword ? ;共享变量 readbuf byte 30 dup(0)
writebuf byte 12 dup(0) ;显示缓冲区 .code ; 主程序 start: mov ecx,count mov ebx,offset array
again: call read ;调用子程序,输入一个数据 mov eax,temp ;获得出口参数 mov [ebx],eax ;存放到数据缓冲区 add ebx,4 dec ecx jnz again push lengthof array ;压入数据个数 push offset array ;压数组的偏移地址 call mean ;调用求平均值子程序,出口参数:EAX=平均值(整数部分) add esp,8 ;平衡堆栈(压入了8个字节数据) call write exit 0
习题5.18
编写一个宏swap,参数是两个32位寄存器或存储器操作数,宏定义体实现两个操作数位置交换,包括两个都是存储器操作数的情况。 答:
SWAP MACRO op1,op2
PUSH OP1 PUSH OP2 POP OP1 POP OP2 ENDM
习题5.19
定义一个使用逻辑指令的宏LOGICAL。
(1)用它代表4条逻辑运算指令:AND/OR/XOR/TEST,可以使用3个形式参数,并给出一个宏调用以及对应宏展开的例子。
(2)必要时做一点修改,使该宏能够把NOT指令包括进去,给出一个使用NOT指令的宏