ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

汇编语言编写增删改查的电话本

2021-10-31 22:02:53  阅读:142  来源: 互联网

标签:esp 汇编语言 电话本 改查 mov item add call push


汇编语言编写增删改查的电话本

主要难点

find_item 函数的编写
这个函数的参数是一个待查询名字的字符串首地址,若找到则返回保存名字,电话的首地址,否则返回0
这里涉及到两个循环,一个是比较字符串的小循环,一个保证所有数据都被比较过的大循环
每次大循环需要重置EDI和ESI这两个对比的地址

不足

关于增加函数计算地址的地方,可以做一个全局变量(在.data中定义)来保存,下一个增加位置,不用每次都计算一次地址

代码

以下是汇编完整的代码

;模式定义-------------------------------------------------
.386
.model flat,stdcall
option casemap:none


;头文件--------------------------------------------------
include	windows.inc
include msvcrt.inc
includelib msvcrt.lib

;数据区--------------------------------------------------
.data

;定义结构体,保存名字和电话
ITEM_STRUCT struct
	szName 			BYTE			25			dup(0)
	szPhNumber 		BYTE			25			dup(0)
ITEM_STRUCT ends


;全局变量			变量名			个数		初始值
g_stItem			ITEM_STRUCT 	100 		dup(<'0'>)
g_stItem_In			ITEM_STRUCT					<'0','0'>
g_nCount			DWORD						0
g_nCountMax			DWORD						100
g_cCmd				BYTE						0h

;格式控制符字符串,方便调用
g_szScanFormat		BYTE			'%s %s',0h
g_szScanNameFormat	BYTE			'%s',0h
g_szPrintItemFormat	BYTE			'%s:',09h,09h,'%s',0d,0ah,0h
g_szGetCmdFormat	BYTE			'%c',0h
g_szCountFormat		BYTE			'There are %d phone numbers:',0dh,0ah,0h

;错误信息
g_szErrMax			BYTE			'ERR->Storage is full',0dh,0ah,0h

;普通信息
g_szClr				BYTE			'cls',0h
g_szPause			BYTE			'pause',0h
g_szAddMsg			BYTE			'Please enter a name and a phone number, name first:',0dh,0ah,0h
g_szNameIn			BYTE			'Please enter a name:',0h
g_szPhoneNumberIn	BYTE			'Please enter a phone number:',0h
g_szMenu			BYTE			'a.Add phone number',0dh,0ah,'s.Show all',0dh,0ah,'g.Get phone number by name',0dh,0ah,'m.Modify phone number by name',0dh,0ah,'d.Delete phone number by name',0dh,0ah,'c.Clear all',0dh,0ah,'q.Quit',0dh,0ah,'Please enter the first letter as command:',0h
g_szLineFeed		BYTE			 0dh,0ah,0h
g_szNotFind			BYTE			'Not find!',0dh,0ah,0h
g_szAllClear		BYTE			'All clear!',0dh,0ah,0h


;代码区-------------------------------------------------
.code
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
add_item proc
;更新栈底             
	push ebp
	mov ebp,esp
	
;开始ADD_ITEM
;判断是否存满
	mov edx,g_nCount
	mov eax,g_nCountMax
	cmp edx,eax
	jae add_item_err_max
;调用scanf接受信息,根据count计算出当前地址,此时edx还是count
	;输出提示语
	push offset g_szAddMsg
	call crt_printf
	add esp,4
	;计算首地址
	lea edi,[g_stItem]
	mov ecx,g_nCount
	imul eax,ecx,sizeof(ITEM_STRUCT)
	add edi,eax
	;scanf函数参数入栈
	lea eax,[edi+ITEM_STRUCT.szPhNumber]
	push eax
	lea eax,[edi+ITEM_STRUCT.szName]
	push eax
	push offset g_szScanFormat
	call crt_scanf
	add esp,12
	inc g_nCount
	jmp add_item_return
;如果大了,就用printf输出错误信息
add_item_err_max:
	push offset g_szErrMax
	call crt_printf
	add esp,4
	
;恢复栈底,返回
add_item_return:
	pop ebp
	ret
add_item endp

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
show_item proc
;保存栈状态
	push ebp
	mov ebp,esp
	
;利用loop与printf输出数据
	;获取当前count,并减一,加载源地址到esi
	
	;输出下当前数量
	push dword ptr g_nCount
	push offset g_szCountFormat
	call crt_printf
	add esp,8
	mov ecx,g_nCount
	;将首地址入edi
	lea edi,[g_stItem]
	;判断是否为零
	or ecx,ecx
	jne show_loop
	;显示提示语
	push offset g_szNotFind
	call crt_printf
	add esp,4
	
	jmp show_item_return
show_loop:
	;保存ecx
	push ecx
	;printf函数参数入栈
	lea eax,[edi+ITEM_STRUCT.szPhNumber]
	push eax
	lea eax,[edi+ITEM_STRUCT.szName]
	push eax
	push offset g_szPrintItemFormat
	call crt_printf
	add esp,12
	;换行
	push offset g_szLineFeed
	call crt_printf
	add esp,4
	;计算下一个读取地址
	add edi,sizeof(ITEM_STRUCT)
	;恢复ecx
	pop ecx
	loop show_loop
	
;恢复栈底,返回
show_item_return:
	;暂停看结果....
	push offset g_szPause
	call crt_system
	add esp,4
	;恢复栈
	pop ebp
	ret
show_item endp

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++
find_item proc
;保存栈状态
	push ebp
	mov ebp,esp
	;开辟16个字节空间
	sub esp,10
;初始化比较首地址,保存当前计数
	lea edi,[g_stItem]	
	mov [ebp-4],edi
	mov ecx,g_nCount
	;初始化方向
	cld
;重置比较地址,最大长度
find_tiem_loop_big:
	;重置待比较地址
	mov edi,[ebp-4]
	mov esi,[ebp+8]
;字符串比较,一样就下一个字符比较
find_tiem_loop_small:
	;判断是否有一个为零
	cmp byte ptr [edi],0
	je find_item_loop_small_find_0
	cmp byte ptr [esi],0
	je find_item_loop_small_find_0
;到这里就说明俩个都不是\0,就正常比较
	;判断当前字节是否相同,cmpsb自动加地址!
	cmpsb
;若不同就直接到大循环
	jne find_tiem_loop_big_next
;跳到小循环
	jmp find_tiem_loop_small
	
;找到\0了,到这里说明至少有一个为零!
find_item_loop_small_find_0:
	;先判断是否两个数都为\0
	mov al,[edi]
	add al,[esi]
	;若结果为零则说明一样,直接找到了,到这里说明前面是判断完的,至少有个零才会到这里
	je find_item_success
;到这里就说明,不一样,可以进行下一个字符串比较了
find_tiem_loop_big_next:
	;判断ecx是否为零
	;计数器自减,判断是否为零,判断是否查询完毕
	dec ecx
	or ecx,ecx
;为零就说明到了最后一个字符串了,就该退出了
	je find_item_fail
;不为零就继续下一个
	;没有到最后一个就自增一个结构体大小
	;保存带比较的局部变量自增
	mov edi,[ebp-4]
	add edi,sizeof(ITEM_STRUCT)
	mov [ebp-4],edi
	jmp find_tiem_loop_big
	
find_item_success:	
;调用printf输出找到的值
	;edi即需要返回的值的地址
	mov eax,[ebp-4]
	jmp find_item_return

find_item_fail:
	;若没找到,返回0
	mov eax,0
	
;恢复栈底,返回
find_item_return:
	;返回开辟的栈
	add esp,10
	pop ebp
	ret
find_item endp

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
get_item_number proc
;保存栈状态
	push ebp
	mov ebp,esp
;显示提示语
	push offset g_szNameIn
	call crt_printf
	add esp,4
;判断count是否为0,若零返回????????????????????????????????????????????????

;scanf 输入查询名字
	push offset g_stItem_In.szName
	push offset g_szScanNameFormat
	call crt_scanf
	add esp,8
;获取名字后调用find_item 返回找到的地址或者null
	push offset g_stItem_In.szName
	call find_item
	add esp,4
;判断是否找到
	or eax,eax
	je get_item_number_not_find
;找到了
	;printf输出
	lea ebx,[eax+ITEM_STRUCT.szPhNumber]
	push ebx
	push eax
	push offset g_szPrintItemFormat
	call crt_printf
	add esp,12
	jmp get_item_number_return


;没有找到,输出提示语
get_item_number_not_find:
	push offset g_szNotFind
	call crt_printf
	add esp,4

;恢复栈底,返回
get_item_number_return:
	;暂停看结果....
	push offset g_szPause
	call crt_system
	add esp,4

	pop ebp
	ret
get_item_number endp

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
modify_item proc
;保存栈状态
	push ebp
	mov ebp,esp
;判断count是否为0
	mov ecx,g_nCount
	or ecx,ecx
	;若不等于零就继续,否则输出找不到并返回
	jne modify_item_normal
	;输出提示语
	push offset g_szNotFind
	call crt_printf
	add esp,4
	;直接调到结尾
	jmp modify_item_return
modify_item_normal:
;显示提示语,输入名字
	push offset g_szNameIn
	call crt_printf
	add esp,4

;scanf 输入查询名字
	push offset g_stItem_In.szName
	push offset g_szScanNameFormat
	call crt_scanf
	add esp,8
;获取名字后调用find_item 返回找到的地址或者null
	push offset g_stItem_In.szName
	call find_item
	add esp,4
;判断是否找到
	or eax,eax
	je modify_item_number_not_find
;这里就找到了,显示提示语,输入号码
	;先保存eax数据
	push eax
	;printf
	push offset g_szPhoneNumberIn
	call crt_printf
	add esp,4
;scanf参数,直接保存到位置
	pop eax
	add eax,ITEM_STRUCT.szPhNumber
	push eax
	push offset g_szScanNameFormat
	call crt_scanf
	add esp,8
	jmp modify_item_return
	
;这里是没找到	
modify_item_number_not_find:	
	push offset g_szNotFind
	call crt_printf
	add esp,4
	
	
;恢复栈底,返回
modify_item_return:
	;暂停看结果....
	push offset g_szPause
	call crt_system
	add esp,4
	
	pop ebp
	ret
modify_item endp

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
copy_item proc
;保存栈状态
	push ebp
	mov ebp,esp
	cld
;将参数,存入寄存器,第一个参数是复制目的地址,第二个参数是源地址
;复制name
	mov edi,[esp+8]
	mov esi,[esp+0ch]
copy_item_name_loop:
	mov al,[esi]
	movsb
	;判断esi指向是否为\0,若是则结束,若不是则继续复制
	or al,al
	jne copy_item_name_loop
;复制phone number
	mov edi,[esp+8]
	add edi,ITEM_STRUCT.szPhNumber
	mov esi,[esp+0ch]
	add esi,ITEM_STRUCT.szPhNumber
copy_item_phone_number_loop:
	mov al,[esi]
	movsb
;判断esi指向是否为\0,若是则结束,若不是则继续复制
	or al,al
	jne copy_item_phone_number_loop
		
;恢复栈底,返回
copy_item_return:
	pop ebp
	ret
copy_item endp

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
delete_item proc
;保存栈状态
	push ebp
	mov ebp,esp
	;获取当前个数
	mov ecx,g_nCount
	;判断是否为0
	cmp ecx,0
	je delete_item_not_find
;获取输入
	;显示提示语,输入名字
	push offset g_szNameIn
	call crt_printf
	add esp,4

	;scanf 输入查询名字
	push offset g_stItem_In.szName
	push offset g_szScanNameFormat
	call crt_scanf
	add esp,8
;判断 找到了咩?
	push offset g_stItem_In
	call find_item
	add esp,4
	;判断是否为零,为零则找不到,直接退出,eax保留地址!
	je delete_item_not_find
	;到这里就说明找到了,判断下是否是一个,一个的话直接清零
	;先删掉再说
	mov byte ptr [eax],0
	;放到目的寄存器中
	mov edi,eax
	;获取当前个数
	mov ecx,g_nCount
	;个数减一
	dec ecx
	;更新到全局变量
	mov g_nCount,ecx
;判断是否在最后一位!若是直接返回,若不是,则将最后一位复制到这里,eax保留地址!ecx可以用了
	imul eax,ecx,sizeof(ITEM_STRUCT)
	add eax,offset g_stItem
	mov esi,eax
	cmp esi,edi
;判断是否是最后一个,若是直接返回,若不是则将最后一位移到删除位置
	je delete_item_return
;调用复制函数,第一个参数是复制目的地址,第二个参数是源地址
	;保存复制地址
	push esi
	;调用复制
	push esi
	push edi
	call copy_item
	add esp,8
	;弹出复制地址,首地址赋值为零
	pop eax
	mov byte ptr [eax],0
		
	;下面是特殊处理,所以要跳过了
	jmp delete_item_return	

;到这里就说明找不到
delete_item_not_find:
	push offset g_szNotFind
	call crt_printf
	add esp,4
	;暂停输出
	push offset g_szPause
	call crt_system
	add esp,4
	
;恢复栈底,返回
delete_item_return:
	pop ebp
	ret
delete_item endp

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++
clear_all proc
;保存栈状态
	push ebp
	mov ebp,esp
	
;所有的首地址改为\0,并将count改为0
	;判断count是否为0
	mov ecx,g_nCount
	or ecx,ecx
	je clear_all_return
		
	;改\0
	lea edi,[g_stItem]
clear_all_loop:
	mov byte ptr [edi],0
	add edi,sizeof(ITEM_STRUCT)
	dec ecx
	or ecx,ecx
	;若ecx不是零就继续循环
	jne clear_all_loop
	
	;改count
	mov g_nCount,0
	
;恢复栈底,返回
clear_all_return:
	;输出提示语
	push offset g_szAllClear
	call crt_printf
	add esp,4
	;暂停输出
	push offset g_szPause
	call crt_system
	add esp,4
	
	pop ebp
	ret
clear_all endp

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
main:

main_loop:
;清屏
	push offset g_szClr
	call crt_system
	add esp,4
;获取命令
	;显示菜单
	push offset g_szMenu
	call crt_printf
	add esp,4
	;获取命令
	push offset g_cCmd
	push offset g_szGetCmdFormat
	call crt_scanf
	add esp,8
;1 判断命令是否为Add phone number
case_1:
	cmp g_cCmd,'a'
	jne case_2
	call add_item
	jmp main_loop
;2 判断命令是否为Show all
case_2:
	cmp g_cCmd,'s'
	jne case_3
	call show_item
	jmp main_loop
;3 判断命令是否为Get phone number by name
case_3:
	cmp g_cCmd,'g'
	jne case_4
	call get_item_number
	jmp main_loop
;4 判断命令是否为Modify phone number by name
case_4:
	cmp g_cCmd,'m'
	jne case_5
	call modify_item
	jmp main_loop
;5 判断命令是否为Delete phone number by name
case_5:
	cmp g_cCmd,'d'
	jne case_6
	call delete_item
	jmp main_loop
;6 判断命令是否为Clear all
case_6:
	cmp g_cCmd,'c'
	jne case_7
	call clear_all
	jmp main_loop 
;7 判断命令是否为Quit
case_7:
	cmp g_cCmd,'q'
	jne main_loop
main_return:
	ret
	
end main
end


标签:esp,汇编语言,电话本,改查,mov,item,add,call,push
来源: https://blog.csdn.net/qq_26489485/article/details/121069906

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有