匯編寫的電話本
阿新 • • 發佈:2018-04-14
asm頭文件
.data ;定義結構體 CONTACTSSTRUCT struct ;名字 szName BYTE 25 dup (0) ;電話號碼 szPhNumber BYTE 12 dup(0) CONTACTSSTRUCT ends ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;struct *pstruct PCONTACTSSTRUCT TYPEDEF PTR CONTACTSSTRUCT ;聲明全局變量 ;定義結構體數組 g_stContacts CONTACTSSTRUCT 100 dup(<‘0‘>) g_nCountMax DWORD 100 ;最大存放元素 g_strTemContacts CONTACTSSTRUCT <‘0‘,‘0‘> ;接收輸入信息 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> g_szOK BYTE ‘OK‘,0 g_start1 BYTE ‘ 1.添加用戶‘,0ah,0dh,0 g_start2 BYTE ‘2.刪除用戶‘,0ah,0dh,0 g_start3 BYTE ‘3.修改用戶‘,0ah,0dh,0 g_start4 BYTE ‘4.查找用戶‘,0ah,0dh,0 g_start7 BYTE ‘5.所有用戶‘,0ah,0dh,0 g_start5 BYTE ‘請輸入選項查:‘,0 g_szstartFormat BYTE ‘%s %s %s %s %s %s‘,0 ;錯誤提示 g_start6 BYTE ‘輸入錯誤請重新輸入!!!‘,0 g_szstart6Format BYTE ‘%s‘,0ah,0dh,0 ;用於接收 g_num DWORD 0 g_szstart7Format BYTE ‘%d‘,0 ;addfunc g_szAddStr BYTE ‘請輸入用戶名密碼格式如:allen 123‘,0ah,0dh,0 g_szretur BYTE ‘增加成功!!!‘,0ah,0dh,0 ;removefunc g_szremoveAddStr BYTE ‘請輸入要刪除的用戶名如:allen ‘,0ah,0dh,0 g_szremoveretur BYTE ‘刪除操作完畢!!!‘,0ah,0dh,0 g_szremovenot BYTE ‘沒有,刪除失敗!!!‘,0ah,0dh,0 ;changefunc ModifyData ;定義格式控制符 g_szScanfFormat BYTE ‘%s %s‘,0 g_szchangeAddStr BYTE ‘請輸入要修改的用戶名如:allen ‘,0ah,0dh,0 g_szchangeAdd BYTE ‘%s‘,0 g_szchangeretur BYTE ‘修改完畢!!!‘,0ah,0dh,0 g_szchangernot BYTE ‘沒有,修改失敗!!!‘,0ah,0dh,0 g_szchange BYTE ‘請輸入用戶名密碼格式如:allen 123‘,0ah,0dh,0 ;checkfunc g_szcheckAddStr BYTE ‘請輸入要查找的用戶名如:allen ‘,0ah,0dh,0 g_szcheck BYTE ‘沒找到!!!‘,0ah,0dh,0 ;接收一個名字 g_szScanName BYTE ‘%s‘,0 ;輸入這裏不通用這種方式0ah,0dh,0 ;輸出一個密碼 g_szScanPasswd BYTE ‘%s‘,0ah,0dh,0 ;元素個數 g_nCount DWORD 0 g_szCount BYTE ‘當前總個數%d‘,0ah,0dh,0 ;FindDataAll g_szFindDataAll BYTE ‘%s----%s‘,0ah,0dh,0 g_szcheckretur BYTE ‘查詢一條完畢!!!‘,0ah,0dh,0 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
main函數
.386 .model flat,stdcall option casemap:none include passwd.Inc include msvcrt.inc ;c函數頭文件 includelib msvcrt.lib;c函數庫 include kernel32.inc includelib kernel32.lib ;這裏都是用的全局要清理 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;push ebx ;mov ebx,sizeof(CONTACTSSTRUCT) ;push ebx ;push 0 ;push edi ;call crt_memset ;add esp,12 ;pop ebx ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .code ;添加用戶信息 ADD_USER proc ;無參數 pushad ;全部入棧 ;---------------------------------------------------------------- lea eax,g_szAddStr push eax call crt_printf ;調用格式 crt_xxx add esp,4 lea esi,[g_stContacts];保存數據的結構體數組 mov ecx,g_nCount;獲取當前已經插入的用戶個數 mov eax,sizeof(CONTACTSSTRUCT) ;計算大小 imul eax,ecx add esi,eax ;移動結構體數組的指針(用戶個數*結構體的大小) lea eax,[esi+CONTACTSSTRUCT.szPhNumber] ;電話號碼 lea edx,[esi+CONTACTSSTRUCT.szName] ;用戶名 push eax push edx push offset g_szScanfFormat ;g_szScanfFormat BYTE ‘%s %s‘,0 call crt_scanf add esp,12 ;元素個數 ;g_nCount DWORD 0 inc g_nCount ;---------------------------------------------------------------- lea eax,g_szretur ;g_szretur BYTE ‘增加成功!!!‘,0ah,0dh,0 push eax call crt_printf ;調用格式 crt_xxx add esp,4 popad ;全部出棧 ret ADD_USER endp ;查詢用戶信息 FindData proc pushad ;全部入棧 lea eax,g_szcheckAddStr push eax call crt_printf ;調用格式 crt_xxx add esp,4 ;---------------------------------------------------------------- ;1.輸入數據 ;定義結構體數組 ;接收用戶名 lea edi,[g_strTemContacts.szName];保存結構體中名字的地址 push edi ;g_szScanName BYTE ‘%s‘,0 push offset g_szScanName call crt_scanf add esp,8 ;開始查詢 mov ecx,0 ;初始化循環次數(默認從0開始循環) CYCLE_MARK: ;標號 cmp ecx,g_nCount ;如果相等就說明沒有數據了 je allennot ;ret mov eax,sizeof(CONTACTSSTRUCT) ;計算大小 imul eax,ecx ;相乘 ;2.1根據ecx的值找到下一個結構體名字數組的地址 lea esi,[g_stContacts] ;保存數據的結構體數組首地址 add esi,eax ;偏移 lea edi,[g_strTemContacts.szName];剛輸入的名字的地址 ;2.2比較字符串 mov eax,ecx ;保存外層循環的次數 mov ecx,6 ;初始化串操作循環次數(4字節比較) 4*6=24 加上最後一個==25 repe cmpsd dword ptr [esi],dword ptr [edi] ;查看repe系列指令的使用原理 je CARRIEDOUT_MAKR ;如果找到則跳轉(轉出信息) mov ecx,eax ;如果沒有 還原ecx inc ecx ;循環次數加1 jmp CYCLE_MARK ;無條件跳轉到外層循環開始位置 CARRIEDOUT_MAKR: ;輸出信息 mov ecx,eax ;先還原ecx lea esi,[g_stContacts] mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小 imul ebx,ecx add esi,ebx lea eax,[esi+CONTACTSSTRUCT.szPhNumber] ;電話號碼 push eax push offset g_szScanPasswd call crt_printf add esp,8 ;輸出完成退出 jmp allenretn ;---------------------------------------------------------------- allennot: ;沒有 lea eax,g_szcheck push eax call crt_printf ;調用格式 crt_xxx add esp,4 popad ;全部出棧 ret allenretn: ;找到了 lea eax,g_szcheckretur push eax call crt_printf ;調用格式 crt_xxx add esp,4 popad ;全部出棧 ret FindData endp ;查看所有信息 FindDataAll proc pushad ;全部入棧 ;---------------------------------------------------------------- ;開始查詢 ;i=0 mov ecx,0 ;初始化循環次數(默認從0開始循環) lea esi,[g_stContacts] ;保存數據的結構體數組 CYCLE_MARK: ;標號 cmp ecx,g_nCount ;如果相等就說明沒有數據了 je allenretn ;ret mov eax,sizeof(CONTACTSSTRUCT) ;計算大小 imul eax,ecx ;2.1根據ecx的值找到下一個結構體名字數組的地址 add esi,eax push ecx ;保存ecx lea edx,[esi+CONTACTSSTRUCT.szName];當前結構體在數組中的首地址 lea ebx,[esi+CONTACTSSTRUCT.szPhNumber];加上名字偏移就是電話了 push ebx push edx push offset g_szFindDataAll ;g_szFindDataAll BYTE ‘%s----%d‘,0ah,0dh,0 call crt_printf add esp,12 ;還原ecx pop ecx inc ecx ;++i jmp CYCLE_MARK ;---------------------------------------------------------------- allenretn: lea eax,g_szcheckretur push eax call crt_printf ;調用格式 crt_xxx add esp,4 popad ;全部出棧 ret FindDataAll endp ;修改用戶信息 ModifyData proc pushad ;全部入棧 lea eax,g_szchangeAddStr push eax call crt_printf ;調用格式 crt_xxx add esp,4 ;---------------------------------------------------------------- ;因為修改信息的第一步也是先要將當前輸入的信息在已保存的數組中查詢 ;1.輸入數據 g_strTemContacts CONTACTSSTRUCT <‘0‘,‘0‘> ;接收輸入信息 lea edi,[g_strTemContacts.szName];保存結構體中名字的地址 push edi ;g_szScanName BYTE ‘%s‘,0 push offset g_szchangeAdd call crt_scanf add esp,8 ;2.開始查詢 mov ecx,0 ;初始化循環次數(默認從0開始循環) CYCLE_MARK: ;標號 cmp ecx,g_nCount ;如果相等就說明查找完畢沒找到 je allennot ;ret ;2.1根據ecx 的值找到下一個結構體名字數組的地址 lea esi,[g_stContacts] ;保存數據的結構體數組 lea edi,[g_strTemContacts.szName];剛輸入的名字 mov eax,sizeof(CONTACTSSTRUCT) ;計算大小 imul eax,ecx add esi,eax ;2.2比較字符串 mov eax,ecx ;保存循環次數 mov ecx,6 ;初始化串操作循環次數(4字節比較) repe cmpsd dword ptr [esi],dword ptr [edi] ;查看repe系列指令的使用原理 je CARRIEDOUT_MAKR ;如果找到則跳轉(轉出信息) mov ecx,eax ;如果沒有 還原ecx inc ecx ;循環次數加1 jmp CYCLE_MARK ;無條件跳轉到外層循環開始位置 CARRIEDOUT_MAKR: ;---------------------------------------------------------------- pushad ;全部入棧 lea eax,g_szchange push eax call crt_printf ;g_szchange BYTE ‘請輸入用戶名密碼格式如:allen 123‘,0ah,0dh,0 add esp,4 popad ;全部出棧 ;---------------------------------------------------------------- ;修改信息 mov ecx,eax lea esi,[g_stContacts] mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小 imul ebx,ecx add esi,ebx lea edx,[esi+CONTACTSSTRUCT.szName] ;用戶名 lea eax,[esi+CONTACTSSTRUCT.szPhNumber] ;電話號碼 push eax push edx push offset g_szScanfFormat ;g_szScanfFormat BYTE ‘%s %s‘,0 call crt_scanf add esp,12 ;add esp,8 jmp allenretn ;---------------------------------------------------------------- allennot: ;沒有 lea eax,g_szchangernot push eax call crt_printf ;調用格式 crt_xxx add esp,4 popad ;全部出棧 ret allenretn: ;成功 lea eax,g_szchangeretur push eax call crt_printf ;調用格式 crt_xxx add esp,4 popad ;全部出棧 ret ModifyData endp ;刪除用戶信息 RemoveData proc pushad ;全部入棧 lea eax,g_szremoveAddStr push eax call crt_printf ;調用格式 crt_xxx add esp,4 ;---------------------------------------------------------------- ;1.輸入數據 lea edi,[g_strTemContacts.szName];保存要刪除的用戶名 push edi ;g_szScanName BYTE ‘%s‘,0 push offset g_szScanName call crt_scanf add esp,8 ;2.開始查詢 mov ecx,0 ;初始化循環次數(默認從0開始循環) CYCLE_MARK: ;標號 cmp ecx,g_nCount ;如果相等就說明查找完畢 je allennot ;ret ;2.1根據ecx 的值找到下一個結構體名字數組的地址 lea esi,[g_stContacts] ;保存數據的結構體數組 lea edi,[g_strTemContacts.szName];剛接收的用戶名 mov eax,sizeof(CONTACTSSTRUCT) ;計算大小 imul eax,ecx add esi,eax ;2.2比較字符串 mov eax,ecx ;保存循環次數 mov ecx,6 ;初始化串操作循環次數(4字節比較) repe cmpsd dword ptr [esi],dword ptr [edi] ;查看repe系列指令的使用原理 je CARRIEDOUT_MAKR ;如果找到則跳轉(轉出信息) mov ecx,eax ;如果沒有 還原ecx inc ecx ;循環次數加1 jmp CYCLE_MARK ;無條件跳轉到外層循環開始位置 CARRIEDOUT_MAKR: ;刪除 ;將esi設置為當前要刪除的結構體數組的首地址 mov ecx,eax ;eax 是在上面獲取到的表示當前找到的數據的位置 lea edi,[g_stContacts] mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小 imul ebx,ecx add edi,ebx ;edi此時保存的是當前要刪除的結構體數組的首地址 mov esi,edi ;esi此時也是當前要刪除的結構 體數組的首地址 mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小 add esi,ebx ;esi此時也是當前要刪除的結構體數組的下一個首地址 add ecx,1 ;因為保存數據時是從數組0開始的,所以加1用於計算需要 ;移動多少個元素,和數據結構中的線性表一樣,蹭某個元素 ;被刪除了後面的元素向前移動 mov eax,g_nCount sub eax,ecx ;需要移動的次數 mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小 imul ebx,ecx mov ecx,ebx ;計算需要移動的字節 rep movs BYTE ptr[edi],BYTE ptr[esi] ;開始移動(以一個字節的大小的移動) ;移動完成後刪除最後一個結構體中的信息 mov ebx,sizeof(CONTACTSSTRUCT) ;計算大小 push ebx ;大小 push 0 ;內容 push edi ;刪除的首地址 call crt_memset ;調用置初始化函數 add esp,12 dec g_nCount push offset g_szOK ;操作成功 call crt_printf add esp,4 push 20 call Sleep ;add esp,4 jmp allenretn ;---------------------------------------------------------------- allennot: ;沒有 lea eax,g_szremovenot push eax call crt_printf ;調用格式 crt_xxx add esp,4 popad ;全部出棧 ret allenretn: lea eax,g_szremoveretur push eax call crt_printf ;調用格式 crt_xxx add esp,4 popad ;全部出棧 ret RemoveData endp ;main start: ;元素個數 ;g_nCount DWORD 0 ;g_szCount BYTE ‘%d‘,0ah,0dh,0 ;輸出當前總個數 push g_nCount push offset g_szCount call crt_printf add esp,8 ;g_start5 BYTE ‘請輸入選項查:‘,0 push offset g_start5 push offset g_start7 push offset g_start4 push offset g_start3 push offset g_start2 push offset g_start1 push offset g_szstartFormat call crt_printf ;調用格式 crt_xxx add esp,24 allen: ;scanf() 接收一個整數保存到g_num mov g_num,0;清0 push offset g_num ;push eax 不能這樣必須是一個地址 ;g_szstart7Format BYTE ‘%d‘,0 push offset g_szstart7Format call crt_scanf add esp,8 cmp eax,1 ;與crt_scanf的返回值比較就是接收的本來是數字就返回成功1 如果你打的不是字母就返回0 jnz @T1 ;mov g_num,eax ;mov eax,g_num ;if ==1 cmp g_num,1 je myadd ;if==2 cmp g_num,2 je myremove ;if==3 cmp g_num,3 je mychange ;if===4 cmp g_num,4 je mycheck ;if===5 cmp g_num,5 je mycheckall ;else continue push offset g_start6 push offset g_szstart6Format call crt_printf ;調用格式 crt_xxx add esp,8 jmp start ;增 myadd: call ADD_USER jmp start ;刪 myremove: call RemoveData jmp start ;改 mychange: call ModifyData jmp start ;查 mycheck: call FindData jmp start ;查all mycheckall: call FindDataAll jmp start @T1: call crt_getchar ;用這個把字母緩沖掉 cmp eax,0ah ;一直比對到最後0ah表示換行或回車 jnz @T1 push offset g_start6 push offset g_szstart6Format call crt_printf ;調用格式 crt_xxx add esp,8 jmp start ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> invoke crt__exit, 0 end start end
有個 bug 要清緩沖(清緩沖的代碼在最上面的註釋裏)就是你所有接收都用的一個結構體所以導致有緩沖 清緩沖思路是你用完那個結構體在後面把他清為 0
win 32匯編 中有個非常嚴重的問題是你調用 scanf 接收的是%d如果你輸入字符串 會死循環下次不會再調 scanf (原因有緩沖)解決方案見代碼
匯編寫的電話本