X86汇编——简易通讯录
生活随笔
收集整理的這篇文章主要介紹了
X86汇编——简易通讯录
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
尚未解決:輸入的姓名、號碼不能超過11位,否則將會覆蓋到后面結構體分配的內存
頭文件
include windows.inc include msvcrt.inc ;包含C語言的庫 includelib msvcrt.lib ;包含C語言庫對應的lib文件include kernel32.inc includelib kernel32.lib.data ;定義結構體、聲明全局變量 CONTACTSSTRUCT structszName BYTE 25 dup(0) ;名字szPhNumber BYTE 12 dup(0) ;電話號碼 CONTACTSSTRUCT ends ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PCONTACTSSTRUCT TYPEDEF PTR CONTACTSSTRUCT ;取別名(指針類型) ;[新的類型名] TYPEDEF PTR [原來的類型名] ;表示取一個指針類型的類型 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;聲明全局變量 g_stContacts CONTACTSSTRUCT 100 dup(<'0','0'>) ;定義結構體數組 g_nCount DWORD 0 ;元素個數 g_nCountMax DWORD 100 ;最大存放元素 g_strTemContacts CONTACTSSTRUCT <'0','0'> ;接收輸入信息 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;定義格式控制符 用于輸入輸出時用到的格式控制符 g_szScanfFormat BYTE '%s %s',0 g_szScanName BYTE '%s',0 g_nChoose dword 100 ;菜單選擇 g_numScanfFormat byte '%d',0 ;菜單選擇格式化輸入符;文件操作 g_szFileWB BYTE 'wb',0 g_szFileRB byte 'rb',0 g_pFile dword 0 g_szFile byte 'data.text',0;system功能 g_szCls byte 'cls',0 ;清屏 g_szPause byte 'pause',0 ;暫停 g_szZero byte ' ',0dh,0ah,0 ;用于換行;提示 g_szAddStr byte '請輸入:用戶名 電話號碼',0dh,0ah,0 g_szFindInfo byte "請輸入姓名:",0dh,0ah,0 g_szInputError byte '輸入錯誤!',0dh,0ah,0 g_szTipNewName byte '請輸入新用戶名 電話號碼',0dh,0ah,0 g_szTipNoExist byte '用戶不存在...',0dh,0ah,0 g_szTipNoDate byte '沒有數據...',0dh,0ah,0 g_szTipListOver byte '查詢完成...',0dh,0ah,0 g_szOK byte '操作成功!',0 g_szMenu byte '請根據選項輸入序號',0dh,0ah,'1 - 查看用戶',0dh,0ah,'2 - 添加用戶',0dh,0ah,'3 - 搜索用戶',0dh,0ah,'4 - 修改用戶',0dh,0ah,'5 - 刪除用戶',0dh,0ah,'0 - 退出',0dh,0ah,0g_szTipSizeError byte '輸入數據超出限制',0dh,0ah,0 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.code ;添加用戶信息 ADD_USER proc ;無參數push eaxpush ebx ;下面是用到該寄存器,先保存一下原來寄存器的值lea eax, g_szAddStr ;表示第二個操作數的地址,放入第一個操作數中 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;1.通過push給函數傳參(4字節) ;2.調用函數 這是調用的是C語言的庫函數,所以要包含頭文件: ; include msvcrt.inc ; includelib msvcrt.lib ; 庫函數的格式為:crt_xxx ;3.C庫函數的是由調用者平衡堆棧 ; 每個參數的大小為4字節,所以傳入幾個參數則在之后esp加回來 ; add esp,[參數個數*4] ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>push eax ;push r/m32(imu32) 可以是寄存器或內存或立即數call crt_printfadd esp,4;根據ecx的值找到下一個結構體名字數組的地址lea esi,[g_stContacts] ;保存數據的結構體數組mov ecx,g_nCount ;獲取當前已插入的用戶個數mov eax,sizeof(CONTACTSSTRUCT) ;計算結構體的大小(sizeof宏)imul eax,ecxadd esi,eax ;移動結構體數組的指針(用戶個數*結構體的大小);調用crt_scanf函數接收輸入的數據lea eax,[esi+CONTACTSSTRUCT.szPhNumber] ;第一個參數(電話號碼)lea edx,[esi+CONTACTSSTRUCT.szName] ;第一個參數(姓名)push eaxpush edxpush offset g_szScanfFormat ;格式控制符call crt_scanfadd esp,0ch ;平衡堆棧inc g_nCount ;用戶個數加1;保存數據call SaveDate;輸入成功push offset g_szOK ;操作成功call crt_printfadd esp,4;暫停push offset g_szPausecall crt_systemadd esp,4pop eax ;函數開始push指令對應pop ebx retADD_USER endp;查詢用戶信息 FindData proc ;1.輸入數據;輸入查找信息push offset g_szFindInfocall crt_printfadd esp,4;清空存放臨時數據的結構體lea edi,[g_strTemContacts] ;保存結構體的地址mov ebx,sizeof(CONTACTSSTRUCT)push ebxpush 0hpush edicall crt_memsetadd esp,12lea edi,[g_strTemContacts.szName] ;保存結構體中名字的地址push edipush offset g_szScanName ;格式控制符call crt_scanf add esp,8 ;平衡堆棧;2.開始查詢mov ecx,0 ;初始化循環次數(默認從0開始循環) CYCLE_MARK:cmp ecx,g_nCount ;判斷是否結束循環jz END_F;2.1根據ecx的值找到下一個結構體名字數組的地址mov eax,sizeof(CONTACTSSTRUCT) ;計算結構體的大小(sizeif宏)imul eax,ecxlea esi,[g_stContacts] ;保存數據的結構體數組add esi,eax;2.2比較字符串mov eax,ecx ;保存外層循環的次數mov ecx,6 ;初始化串操作的循環操作(4字節比較)lea edi,[g_strTemContacts.szName] ;保存當前插入的用戶名字的地址repe cmpsd dword ptr[esi],dword ptr[edi] ;查看repe系列指令的使用原理je CARRIEDOUT_MARK ;如果找到則跳轉(輸出信息)mov ecx,eax ;如果沒有找到則繼續外層循環inc ecx ;層循環次數加1jmp CYCLE_MARK ;無條件跳轉到外層循環開始位置CARRIEDOUT_MARK:;輸出信息mov ecx,eaxlea esi,[g_stContacts]mov ebx,sizeof(CONTACTSSTRUCT)imul ebx,ecxadd esi,ebxlea eax,[esi+CONTACTSSTRUCT.szPhNumber]push eaxpush offset g_szScanNamecall crt_printfadd esp,8;換行push offset g_szZerocall crt_printfadd esp,4push offset g_szOK ;操作成功call crt_printfadd esp,4;暫停push offset g_szPause call crt_systemadd esp,4ret END_F:push offset g_szTipNoExistcall crt_printfadd esp,4;暫停push offset g_szPausecall crt_systemadd esp,4ret FindData endp;修改用戶信息 ModifyData proc;因為修改信息的第一步也是先要將當前輸入的信息在已保存的數組中查詢 ;1.輸入數據;輸入查找信息push offset g_szFindInfo;push offset g_szScanNamecall crt_printfadd esp,4;清空存放臨時數據的結構體lea edi,[g_strTemContacts] ;保存結構體的地址mov ebx,sizeof(CONTACTSSTRUCT)push ebxpush 0hpush edicall crt_memsetadd esp,12lea edi,[g_strTemContacts.szName] ;保存結構體中名字的地址push edipush offset g_szScanName ;格式控制符call crt_scanfadd esp,8 ;平衡堆棧 ;2.開始查詢mov ecx,0 ;初始化循環次數(默認從0開始) CYCLE_MARK: ;標號cmp ecx,g_nCount ;判斷是否結束循環jz END_M;2.1根據ecx的值找到下一個結構體名字數組的地址lea esi,[g_stContacts] ;保存數據的結構體數組lea edi,[g_strTemContacts.szName] ;獲取當前輸入要查詢的用戶名字地址mov eax,sizeof(CONTACTSSTRUCT) ;計算結構體的大小(sizeof宏)imul eax,ecxadd esi,eax;2.2比較字符串mov eax,ecx ;保存外層循環的次數mov ecx,6 ;初始化串串操作的循環次數(4字節比較)repe cmpsd dword ptr[esi],dword ptr[edi] je CARRIEDOUT_MARK ;如果找到則跳轉(修正信息)mov ecx,eax ;如果沒有找到則繼續外層循環inc ecx ;層循環次數加1jmp CYCLE_MARK ;無條件跳轉到外層循環開始位置CARRIEDOUT_MARK:;修改信息mov ecx,eaxlea esi,[g_stContacts]mov ebx,sizeof(CONTACTSSTRUCT)imul ebx,ecxadd esi,ebx;輸入新信息push offset g_szTipNewNamecall crt_printfadd esp,4lea ebx,[esi+CONTACTSSTRUCT.szName]lea eax,[esi+CONTACTSSTRUCT.szPhNumber]push eaxpush ebxpush offset g_szScanfFormatcall crt_scanfadd esp,0Ch;保存數據call SaveDatepush offset g_szOK ;操作成功call crt_printfadd esp,4;暫停push offset g_szPausecall crt_systemadd esp,4ret END_M:push offset g_szTipNoExistcall crt_printfadd esp,4;暫停push offset g_szPausecall crt_systemadd esp,4ret ModifyData endp;刪除用戶信息 RemoveDate proc ;1.輸入數據;輸入查找信息push offset g_szFindInfo;push offset g_szScanNamecall crt_printfadd esp,4;清空存放臨時數據的結構體lea edi,[g_strTemContacts] ;保存結構體的地址mov ebx,sizeof(CONTACTSSTRUCT)push ebxpush 0hpush edicall crt_memsetadd esp,12lea edi,[g_strTemContacts.szName] ;保存結構體中名字的地址push edipush offset g_szScanName ;格式控制符call crt_scanfadd esp,8 ;平衡堆棧;2.開始查詢mov ecx,0 ;初始化循環次數(默認從0開始循環) CYCLE_MARK:cmp ecx,g_nCount ;判斷是否結束循環jz END_M;2.1根據ecx的值找到下一個結構體名字數組的地址lea esi,[g_stContacts] ;保存數據的結構體數組lea edi,[g_strTemContacts.szName] ;獲取當前輸入的要查詢用戶名字地址mov eax,sizeof(CONTACTSSTRUCT) ;計算結構體的大小imul eax,ecxadd esi,eax;2.2比較字符串mov eax,ecx ;保存外層循環的次數mov ecx,6 ;初始化串操作的循環次數(4字節比較)repe cmpsd dword ptr[esi],dword ptr[edi] je CARRIEDOUT_MARKmov ecx,eax ;沒有找到則繼續外層循環inc ecx ;層循環次數加1jmp CYCLE_MARK ;無條件跳轉到外層循環開始位置CARRIEDOUT_MARK:;刪除;將esi設置為當前要刪除的結構體數組的首地址 mov ecx,eax ;eax是在上面獲取到的表示當前找到的數組的位置lea edi,[g_stContacts]mov ebx,sizeof(CONTACTSSTRUCT)imul ebx,ecxadd edi,ebx ;edi此時保存的是當前要刪除的結構體數組的首地址mov esi,edi 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,eax ;計算需要移動的字節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,12dec g_nCount;保存數據call SaveDate push offset g_szOK ;操作成功call crt_printfadd esp,4;暫停push offset g_szPausecall crt_systemadd esp,4ret END_M:push offset g_szTipNoExistcall crt_printfadd esp,4;暫停push offset g_szPausecall crt_systemadd esp,4retRemoveDate endp;菜單 Menu proc;打印菜單push offset g_szMenucall crt_printfadd esp,4 ;平衡堆棧retMenu endp;菜單選項分支跳轉 MenuJump proc;比較兩個操作數,操作數1-操作數2cmp g_nChoose,0 jz OP0 cmp g_nChoose,1 jz OP1cmp g_nChoose,2jz OP2cmp g_nChoose,3 jz OP3cmp g_nChoose,4 jz OP4cmp g_nChoose,5jz OP5;輸入錯誤push offset g_szInputErrorcall crt_printfadd esp,4;暫停push offset g_szPausecall crt_systemadd esp,4;INVOKE GetStdHandle, STD_INPUT_HANDLE ;讀取輸入句柄,STD_INPUT_HANDLE是win32常數;mov consoleInHandle,eax ;保存;INVOKE FlushConsoleInputBuffer,consoleInHandle ;清除輸入(通常是鍵盤)緩沖函式jmp EndMenu_Mark;退出 OP0:;exitProcess(0)push 0call ExitProcessadd esp,4jmp EndMenu_Mark;查詢 OP1:call ListAlljmp EndMenu_Mark;添加 OP2:call ADD_USERjmp EndMenu_Mark;搜索 OP3:call FindDatajmp EndMenu_Mark;修改 OP4:call ModifyData jmp EndMenu_Mark;刪除 OP5:call RemoveDatejmp EndMenu_MarkEndMenu_Mark: retMenuJump endp;查看所有用戶 ListAll procxor ecx,ecx ;1.對比當前容量cmp g_nCount,0je NODATEjne CYCLE_lIST;無數據 NODATE:push offset g_szTipNoDatecall crt_printfadd esp,4jmp EndList_Mark;列出所有CYCLE_lIST:push ecx;2.1地址lea esi,[g_stContacts]mov ebx,sizeof(CONTACTSSTRUCT)imul ebx,ecxadd esi,ebx ;第ecx個結構體地址;printf("%s%s",a,b)lea eax,[esi+CONTACTSSTRUCT.szPhNumber]push eaxlea eax,[esi+CONTACTSSTRUCT.szName] push eaxpush offset g_szScanfFormatcall crt_printfadd esp,0chpush offset g_szZerocall crt_printfadd esp,4pop ecxinc ecx ;第一個聯系人ecx是0,所以比較前需要加1cmp dword ptr [g_nCount],ecx ;比較當前輸出位置ecx 通訊錄人數g_nCountjle EndList_Mark ;相等代表全部打印完,跳到查詢結束;還有聯系人沒有打印;inc ecx ;前面已經加1了 ,這里不需要再加 jmp CYCLE_lIST;查詢結束 EndList_Mark:;查詢完成push offset g_szTipListOvercall crt_printfadd esp,4;暫停push offset g_szPausecall crt_systemadd esp,4ret ListAll endp;保存 SaveDate procpush ebpmov ebp,esp;重置文件指針mov g_pFile,0;打開文件push offset g_szFileWBpush offset g_szFilecall crt_fopenadd esp ,04hmov dword ptr [g_pFile],eax;size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream); ;-- buffer:指向數據塊的指針 ;-- size:每個數據的大小,單位為Byte(例如:sizeof(int)就是4) ;-- count:數據個數 ;-- stream:文件指針;存儲聯系人數量push g_pFile ;文件指針push 1 ;數據個數push 4 ;每個數據的大小 這里是dword 4字節lea ebx,[g_nCount] ;數據指針push ebxcall crt_fwriteadd esp,10h ;存儲文件結構體數組;文件指針push g_pFile ;文件指針 ;數據個數lea eax,g_nCountpush eax;數據大小mov ebx,sizeof(CONTACTSSTRUCT)push ebx;結構體數組首地址lea esi,[g_stContacts]push esicall crt_fwriteadd esp,10h ;關閉文件push g_pFile call crt_fcloseadd esp,4mov dword ptr [g_pFile],0mov esp,ebppop ebpret SaveDate endpLoadDate procpush ebpmov ebp,esp;重置文件指針mov g_pFile,0;打開文件push offset g_szFileRBpush offset g_szFilecall crt_fopenadd esp,08hmov g_pFile,eax ;打開文件返回值eax,eax為0打開失敗,成功為1cmp g_pFile,0je End_Load ;打開失敗,跳轉;size_t fread(void *buffer, size_t size, size_t count, FILE *stream); ;-- buffer:指向數據塊的指針 ;-- size:每個數據的大小,單位為Byte(例如:sizeof(int)就是4) ;-- count:數據個數 ;-- stream:文件指針 ;讀取聯系人數量push g_pFile ;文件指針push 1push 4lea esi,[g_nCount] ;數據地址push esicall crt_freadadd esp,10h;讀取聯系人結構體數組數據push g_pFilemov eax,g_nCountpush eaxmov ebx,sizeof(CONTACTSSTRUCT)push ebxlea esi,[g_stContacts]push esicall crt_freadadd esp,10hEnd_Load:;關閉文件push g_pFilecall crt_fcloseadd esp,4mov g_pFile,0mov esp,ebppop ebpretLoadDate endp主函數
.386 ;匯編語言的偽指令,在80386及以后的處理器中使用該指令集 .model flat,stdcall ;模式定義“model內存模式[,調用模式]” option casemap:none ;選項模式(設定為對大小寫敏感)include Contacts.inc.code ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> start: ;主函數 main procpush ebp ;備份ebpmov ebp,espcall LoadDateCYCLE_MAIN:;清屏push offset g_szClscall crt_systemadd esp,4;顯示菜單call Menu;重置g_nChooselea ebx,[g_numScanfFormat]mov dword ptr[g_nChoose],0hpush offset g_nChoose ;輸入整型格式控制符;push offset g_numScanfFormat push ebxcall crt_scanfadd esp,8cmp eax,1 jnz @T1;菜單跳轉call MenuJump ;循環jmp CYCLE_MAIN@T1:call crt_getcharcmp eax,0ahjnz @T1jmp CYCLE_MAINMAIN_END:mov esp,ebppop ebpret main endp end start end?
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的X86汇编——简易通讯录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: X86汇编——输出三角形星星
- 下一篇: 内核层CS段描述符信息