版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、第 4 章匯編語言程序設計4.1 分支程序結構4.2 循環(huán)程序結構4.3 子程序結構4.4 Windows應用程序編程4.5 與C+語言的混合編程4.1 分支程序結構改變程序執(zhí)行順序、形成分支、循環(huán)、調用等程序結構是很常見的程序設計問題高級語言采用IF等語句表達條件,并根據(jù)條件是否成立轉向不同的程序分支匯編語言需要首先利用比較CMP、測試TEST、加減運算、邏輯運算等影響狀態(tài)標志的指令形成條件然后利用條件轉移指令判斷由標志表達的條件,并根據(jù)標志狀態(tài)控制程序轉移到不同的程序段4.1.1 無條件轉移指令程序代碼在代碼段CS:指明代碼段在主存中的段基地址EIP:給出將要執(zhí)行指令的偏移地址程序順序執(zhí)行
2、,處理器自動增量EIP程序控制轉移,EIP隨之改變程序轉移到另外的代碼段,EIP和CS都改變控制轉移類指令:改變EIP(有些也改變CS),即改變程序執(zhí)行順序(實現(xiàn)程序控制轉移)的指令本章學習控制轉移類指令1. 轉移范圍段內轉移在當前代碼段范圍內的程序轉移不需更改CS,只要改變EIP(偏移地址)近轉移(Near):32位近轉移NEAR32,16位近轉移NEAR16短轉移(Short):轉移范圍在127-128字節(jié)段間轉移從當前代碼段跳轉到另一個代碼段需要更改CS(段地址)和EIP(偏移地址)遠轉移(Far): 48位遠轉移FAR32,32位遠轉移FAR162. 指令尋址方式相對尋址方式提供目標地
3、址相對于當前指令指針EIP的位移量目標地址(轉移后的EIP)當前EIP位移量相對尋址都是段內轉移,最常用、最靈活直接尋址方式直接提供目標地址目標地址(轉移后的CS和EIP)指令操作數(shù)間接尋址方式指示寄存器或存儲單元目標地址來自寄存器或存儲單元、間接獲得寄存器間接尋址:用寄存器保存目標地址存儲器間接尋址:用存儲單元保存目標地址目標地址目的地址轉移地址3. JMP指令無條件轉移:程序無條件改變執(zhí)行順序JMP指令相當于高級語言的goto語句JMP label;程序轉向label標號指定的地址;段內相對尋址,段間直接尋址JMP reg32/reg16;程序轉向寄存器指定的地址;寄存器間接尋址JMP m
4、em48/mem32/mem16;程序轉向存儲單元指定的地址;存儲器間接尋址JMP指令的4種類型1. 段內轉移、相對尋址標號指明目標地址,指令代碼包含位移量2. 段內轉移、間接尋址通用寄存器或主存單元包含目標指令偏移地址3. 段間轉移、直接尋址標號包含目標指令的段地址和偏移地址4. 段間轉移、間接尋址32位段用3字存儲單元包含目標地址16位段用雙字存儲單元包含目標地址MASM會根據(jù)存儲模式等信息自動識別例4-1無條件轉移程序1; 數(shù)據(jù)段0000000000000000nvardword ? ; 代碼段00000000EB 01jmp labl1; 相對尋址0000000290nop000000
5、03E9 00000001labl1:jmp near ptr labl2; 相對近轉移0000000890nop00000009B8 00000011 Rlabl2:mov eax,offset labl3 例4-1無條件轉移程序20000000EFF E0jmp eax; 寄存器間接尋址0000001090nop00000011B8 00000022 Rlabl3:mov eax,offset labl400000016A3 00000000 Rmov nvar,eax0000001BFF 25 00000000 Rjmp nvar; 存儲器間接尋址0000002190noplabl4:
6、mov ebx,offset nvarjmp near ptr ebx;數(shù)據(jù)的寄存器間接尋址數(shù)據(jù)的存儲器直接尋址4.1.2 條件轉移指令根據(jù)指定的條件確定程序是否發(fā)生轉移Jcc label;條件滿足,發(fā)生轉移;否則,順序執(zhí)行下條指令LABEL表示目標地址,采用段內相對尋址32位IA-32處理器:達到32位的全偏移量16位80 x86處理器:-128+127間的短轉移條件轉移指令不影響標志,但要利用標志cc表示利用標志判斷的條件,16種、兩類單個標志狀態(tài)作為條件兩數(shù)大小關系作為條件轉移條件cc:單個標志狀態(tài)JZ/JEZF=1Jump if Zero/EqualJNZ/JNEZF=0Jump if
7、 Not Zero/Not EqualJSSF=1Jump if SignJNSSF=0Jump if Not SignJP/JPEPF=1Jump if Parity/Parity EvenJNP/JPOPF=0Jump if Not Parity/Parity OddJOOF=1Jump if OverflowJNOOF=0Jump if Not OverflowJCCF=1Jump if CarryJNCCF=0Jump if Not Carry多個助記符方便記憶轉移條件cc:兩數(shù)大小關系JB/JNAECF=1Jump if Below/Not Above or EqualJNB/JAE
8、CF=0Jump if Not Below/Above or EqualJBE/JNACF=1或ZF=1Jump if Below/Not AboveJNBE/JACF=0且ZF=0Jump if Not Below or Equal/AboveJL/JNGESFOFJump if Less/Not Greater or EqualJNL/JGESF=OFJump if Not Less/Greater or EqualJLE/JNGSFOF或ZF=1Jump if Less or Equal/Not GreaterJNLE/JGSF=OF且ZF=0Jump if Not Less or Eq
9、ual/Greater1. 單個標志狀態(tài)作為條件的條件轉移指令JZ(JE)和JNZ(JNE):利用零位標志ZF判斷結果是零(相等)還是非零(不等)JS和JNS:利用符號標志SF判斷結果是負還是正JO和JNO:利用溢出標志OF判斷結果是溢出還是沒有溢出JP(JPE)和JNP(JPO):利用奇偶標志PF判斷結果低字節(jié)“1”的個數(shù)是偶數(shù)還是奇數(shù)JC和JNC:利用進位標志CF判斷結果是有進位(為1)還是無進位(為0)例4-2個數(shù)折半程序1mov eax,885; 假設一個數(shù)據(jù)shr eax,1; 數(shù)據(jù)右移進行折半jnc goeven; 余數(shù)為0,即CF0條件成立,轉移add eax,1; 否則余數(shù)為1
10、,即CF1,進行加1操作goeven:call dispuid; 顯示結果 443運行結果例4-2個數(shù)折半程序2mov eax,886; 假設一個數(shù)據(jù)shr eax,1; 數(shù)據(jù)右移進行折半jc goodd; 余數(shù)為1,即CF1條件成立,轉移到分支體,進行加1操作jmp goeven; 余數(shù)為0,即CF0,不需要處理,轉移到顯示!goodd:add eax,1; 進行加1操作goeven:call dispuid; 顯示結果jnc goeven 何不合二為一?例4-2個數(shù)折半程序3mov eax,887; 假設一個數(shù)據(jù)shr eax,1; 數(shù)據(jù)右移進行折半adc eax,0; 余數(shù)CF1,進行加
11、1操作;余數(shù)CF0,沒有加1call dispuid; 顯示結果mov eax,888; 假設一個數(shù)據(jù)add eax,1; 個數(shù)加1rcr eax,1; 數(shù)據(jù)右移進行折半call dispuid; 顯示結果改進算法消除分支例4-3位測試程序1; 數(shù)據(jù)段no_msgbyte Not Ready!,0yes_msgbyte Ready to Go!,0; 代碼段mov eax,56h; 假設一個數(shù)據(jù)test eax,02h; 測試D1位(D11,其他位為0)jz nom; D10條件成立,轉移mov eax,offset yes_msg; D11,顯示準備好jmp done; 跳轉過另一個分支體!
12、nom:mov eax,offset no_msg; 顯示沒有準備好done:call dispmsg例4-3位測試程序2; 數(shù)據(jù)段no_msgbyte Not Ready!,0yes_msgbyte Ready to Go!,0; 代碼段mov eax,56h; 假設一個數(shù)據(jù)test eax,02h; 測試D1位(D11,其他位為0)jnz yesm; D11條件成立,轉移mov eax,offset no_msg; D10,顯示沒有準備好jmp done; 跳轉過另一個分支體!yesm:mov eax,offset yes_msg; 顯示準備好done:call dispmsg例4-4奇校
13、驗程序call readc; 鍵盤輸入, AL返回值call dispcrlf; 回車換行(用于分隔)call dispbb; 以二進制形式顯示數(shù)據(jù)call dispcrlf; 回車換行(用于分隔)and al,7fh; 最高位置“0”、其他位不變; 同時標志PF反映“1”的個數(shù)jnp next; 個數(shù)為奇數(shù),不需處理,轉移or al,80h; 個數(shù)為偶數(shù),最高位置“1”、其他位不變 next:call dispbb; 顯示含校驗位的數(shù)據(jù)2. 兩數(shù)大小關系作為條件的條件轉移指令無符號數(shù)用高(Above)、低(Below)低于(不高于等于):JB(JNAE)不低于(高于等于):JNB(JAE)低
14、于等于(不高于):JBE(JNA)不低于等于(高于):JNBE(JA)有符號數(shù)用大(Greater)、?。↙ess)小于(不大于等于):JL(JNGE)不小于(大于等于):JNL(JGE)小于等于(不大于):JLE(JNG)不小于等于(大于):JNLE(JG)例4-5數(shù)據(jù)比較程序1; 數(shù)據(jù)段in_msg1byte Enter a number: ,0in_msg2byte Enter another number: ,0out_msg1byte Two numbers are equal: ,0out_msg2byte The less number is: ,0out_msg3byte 13
15、,10,The greater number is: ,0; 代碼段mov eax,offset in_msg1; 提示輸入call dispmsgcall readsid; 輸入第一個數(shù)據(jù)mov ebx,eax; 保存到EBXmov eax,offset in_msg2; 提示輸入call dispmsgcall readsid; 輸入第二個數(shù)據(jù)mov ecx,eax; 保存到ECX例4-5數(shù)據(jù)比較程序2cmp ebx,ecx; 二個數(shù)據(jù)進行比較jne nequal; 兩數(shù)不相等,轉移mov eax,offset out_msg1call dispmsg; 顯示兩數(shù)相等mov eax,ebx
16、call dispsid; 顯示相等的數(shù)據(jù)jmp done; 轉移到結束nequal:jl first; EBX較小,不需要交換,轉移xchg ebx,ecx; EBX保存較小數(shù),ECX保存較大數(shù)例4-5數(shù)據(jù)比較程序3first:mov eax,offset out_msg2; 顯示較小數(shù)call dispmsgmov eax,ebx; 較小數(shù)在EBX中call dispsidmov eax,offset out_msg3; 顯示較大數(shù)call dispmsgmov eax,ecx; 較大數(shù)在ECX中call dispsid done:4.1.3 單分支結構只有一個分支的程序類似高級語言的IF
17、-THEN語句結構注意采用正確的條件轉移指令當條件滿足(成立),發(fā)生轉移,跳過分支體條件不滿足,順序向下執(zhí)行分支體條件轉移指令與高級語言的IF語句正好相反IF語句是條件成立,執(zhí)行分支體例4-6求絕對值程序; 代碼段call readsid; 輸入一個有符號數(shù),從EAX返回值cmp eax,0; 比較EAX與0jge nonneg; 條件滿足:EAX0,轉移neg eax; 條件不滿足:EAX0,為負數(shù); 需求補得正值nonneg:call dispuid;分支結束,顯示結果示意圖單分支結構的流程圖返回neg eax例4-7字母判斷程序call readc; 輸入一個字符,從AL返回值cmp a
18、l,A; 與大寫字母A比較jb done; 比大寫字母A小,不是大寫字母,轉移cmp al,Z; 與大寫字母Z比較ja done; 比大寫字母Z大,不是大寫字母,轉移or al,20h; 轉換為小寫call dispcrlf; 回車換行call dispc; 顯示小寫字母done: 4.1.4 雙分支結構雙分支程序結構有兩個分支,條件為真執(zhí)行一個分支;條件為假,執(zhí)行另一個分支相當于高級語言的IF-THEN-ELSE語句順序執(zhí)行的分支體1最后一定要有一條JMP指令跳過分支體2JMP指令必不可少,實現(xiàn)結束前一個分支回到共同的出口作用雙分支結構有時可以改變?yōu)閱畏种ЫY構事先執(zhí)行其中一個分支(選擇出現(xiàn)概
19、率較高的分支) 例4-8顯示數(shù)據(jù)最高位程序1; 數(shù)據(jù)段dvardword 0bd630422h; 假設一個數(shù)據(jù); 代碼段mov ebx,dvarshl ebx,1; EBX最高位移入CF標志jc one; CF1,即最高位為1,轉移mov al,0; CF0,即最高位為0:AL0jmp two; 一定要跳過另一個分支one:mov al,1; AL1two:call dispc; 顯示 示意圖雙分支結構雙分支結構的流程圖返回例4-8顯示數(shù)據(jù)最高位程序2mov ebx,dvarmov al,0; 假設最高位為0:AL0shl ebx,1; EBX最高位移入CF標志jnc two; CF0,即最高
20、位為0,轉移mov al,1; CF1,即最高位為1,AL1two:call dispc; 顯示單分支結構例4-9有符號數(shù)運算溢出程序; 數(shù)據(jù)段dvar1dword 1234567890; 假設兩個數(shù)據(jù)dvar2dword -999999999dvar3dword ?okmsgbyte Correct!,0; 正確信息errmsgbyte ERROR ! Overflow!,0; 錯誤信息; 代碼段mov eax,dvar1 sub eax,dvar2; 求差jo error; 有溢出,轉移mov dvar3,eax; 無溢出,保存差值mov eax,offset okmsg; 顯示正確jmp
21、 disperror:mov eax,offset errmsg; 顯示錯誤disp:call dispmsg 4.2 循環(huán)程序結構三個部分組成:循環(huán)初始為開始循環(huán)準備必要的條件,如循環(huán)次數(shù)、循環(huán)體需要的初始值等;循環(huán)體重復執(zhí)行的程序代碼,其中包括對循環(huán)條件的修改等;循環(huán)控制判斷循環(huán)條件是否成立,決定是否繼續(xù)循環(huán)“先判斷、后循環(huán)”的循環(huán)程序結構對應高級語言的WHILE語句“先循環(huán)、后判斷”的循環(huán)程序結構對應高級語言的DO語句示意圖循環(huán)程序結構的流程圖返回4.2.1 循環(huán)指令LOOP label;ECXECX1;若ECX0,循環(huán)到LABEL;否則,順序執(zhí)行JECXZ label;ECX0,轉移;
22、否則順序執(zhí)行目標地址采用相對短轉移實地址存儲模型使用CX作為計數(shù)器DEC ECXJNZ labelCMP ECX,0JZ label例4-10數(shù)組求和程序mov ecx,lengthof array; ECX數(shù)組元素個數(shù)xor eax,eax; 求和初值為0mov ebx,eax; 數(shù)組指針為0again:add eax,arrayebx*(type array); 求和 inc ebx; 指向下一個數(shù)組元素loop againmov sum,eax; 保存結果call dispsid; 顯示結果循環(huán)體循環(huán)控制循環(huán)初始4.2.2 計數(shù)控制循環(huán)通過次數(shù)控制循環(huán)利用LOOP指令屬于計數(shù)控制常見是“
23、先循環(huán)、后判斷”循環(huán)結構計數(shù)可以減量進行,即減到0結束計數(shù)可以增量進行,即達到規(guī)定值結束循環(huán)程序結構的關鍵是如何控制循環(huán)例4-11簡單加密解密程序1; 數(shù)據(jù)段keybyte 234bufnum= 255bufferbyte bufnum+1 dup(0); 定義鍵盤輸入需要的緩沖區(qū)msg1byte Enter messge: ,0msg2byte Encrypted message: ,0msg3byte 13,10,Original messge: ,0; 代碼段mov eax,offset msg1; 提示輸入字符串call dispmsgmov eax,offset buffer; 設置
24、入口參數(shù)EAXcall readmsg; 調用輸入字符串子程序push eax; 字符個數(shù)保存進入堆棧例4-11簡單加密解密程序2mov ecx,eax; ECX實際輸入的字符個數(shù),作為循環(huán)的次數(shù)xor ebx,ebx; EBX指向輸入字符mov al,key; AL加密關鍵字encrypt:xor bufferebx,al; 異或加密inc ebxdec ecx; 等同于指令:loop encryptjnz encrypt; 處理下一個字符mov eax,offset msg2call dispmsgmov eax,offset buffer; 顯示密文call dispmsg例4-11簡單
25、加密解密程序3pop ecx; 從堆棧彈出字符個數(shù),作為循環(huán)的次數(shù)xor ebx,ebx; EBX指向輸入字符mov al,key; AL解密關鍵字decrypt:xor bufferebx,al; 異或解密inc ebxdec ecxjnz decrypt; 處理下一個字符mov eax,offset msg3call dispmsgmov eax,offset buffer; 顯示明文call dispmsg示意圖簡單加密解密程序運行實例返回4.2.3 條件控制循環(huán)根據(jù)條件決定是否進行循環(huán)需要使用有條件轉移指令實現(xiàn)多見“先判斷、后循環(huán)”結構先行判斷的條件控制循環(huán)程序很像雙分支結構主要分支需
26、要重復執(zhí)行多次(JMP的目標位置是循環(huán)開始)另一個分支用于跳出這個循環(huán)先行循環(huán)的條件控制循環(huán)程序類似單分支結構,循環(huán)體就是分支體順序執(zhí)行就跳出循環(huán)例4-12字符個數(shù)統(tǒng)計程序; 數(shù)據(jù)段stringbyte Do you have fun with Assembly?,0; 以0結尾的字符串; 代碼段xor ebx,ebx; EBX用于記錄字符個數(shù),也用于指向字符的指針again:mov al,stringebxcmp al,0; 用指令“test al,al”更好jz doneinc ebx; 個數(shù)加1jmp again; 繼續(xù)循環(huán)done:mov eax,ebx; 顯示個數(shù)call dispu
27、id例4-13字符剔除程序1mov eax,offset string; 顯示處理前字符串call dispmsgmov esi,offset stringoutlp:cmp byte ptr esi,0; 外循環(huán),先判斷后循環(huán)jz done; 為0結束again:cmp byte ptr esi, ; 是否是空格jnz next; 不是空格繼續(xù)循環(huán)mov edi,esi; 是空格,剔除空格分支inlp:inc edi; 該分支是循環(huán)程序mov al,edi; 前移一個位置mov edi-1,al例4-13字符剔除程序2cmp byte ptr edi,0; 內循環(huán),先循環(huán)后判斷jnz inl
28、p; 內循環(huán)結束處jmp again; 再次判斷是否為空格(處理連續(xù)空格)next:inc esi; 繼續(xù)對后續(xù)字符進行判斷處理jmp outlp; 外循環(huán)結束處done:mov eax,offset string; 顯示處理后字符串call dispmsg4.3 子程序結構經(jīng)常用到的應用問題編寫成一個通用子程序大型處理過程分解成能夠解決的模塊使用子程序可以使程序的結構更為清楚程序的維護更為方便有利于大程序開發(fā)時的多個程序員分工合作子程序(Subroutine)函數(shù)(Function)過程(Procedure)4.3.1 子程序指令子程序:與主程序分開的、完成特定功能的一段程序當主程序(調用程
29、序)執(zhí)行調用指令CALL調用子程序子程序(被調用程序)執(zhí)行返回指令RET返回主程序CALL label主程序RET子程序回到CALL指令后的指令處1. 子程序調用指令CALLCALL指令用在主程序中,實現(xiàn)子程序的調用分成段內調用(近調用)和段間調用(遠調用)目標地址采用相對尋址、直接尋址或間接尋址入棧返回地址:將CALL下條指令的地址壓入堆棧CALL label;調用標號指定的子程序CALL reg16/reg32;調用寄存器指定地址的子程序CALL mem16/mem32/mem48;調用存儲單元指定地址的子程序2. 子程序返回指令RETRET指令用在子程序結束,實現(xiàn)返回主程序RET;無參數(shù)
30、返回:出棧返回地址RET i16;有參數(shù)返回:出棧返回地址;ESPESPi16MASM會根據(jù)存儲模型等信息確定子程序的遠近調用,并相應產(chǎn)生返回指令3. 過程定義偽指令MASM利用過程定義偽指令獲得子程序信息 過程名PROC;過程體過程名ENDP;過程名為符合語法的標識符PROC后面可加參數(shù):NEAR或FAR簡化段定義源程序格式中,通常不需指定例4-14子程序調用程序1; 代碼段,主程序00000000B8 00000001mov eax,100000005BD 00000005mov ebp,50000000AE8 00000016call subp; 子程序調用0000000FB9 0000
31、0003retp1:mov ecx,300000014BA 00000004retp2:mov edx,400000019E8 00000000 Ecall disprd例4-14子程序調用程序2; 子程序subpproc; 過程定義,過程名為subppush ebpmov ebp,espmov esi,ebp+4; ESICALL下條指令(標號RETP1)偏移地址mov edi,offset retp2; EDI標號RETP2的偏移地址mov ebx,2pop ebp; 彈出堆棧,保持堆棧平衡ret; 子程序返回subpendp; 過程結束MOV EBP+4,EDI?示意圖子程序調用的堆棧返
32、回4.3.2 子程序設計子程序的編寫方法與主程序一樣但需要留意幾個問題:利用過程定義,獲得子程序名和調用屬性RET指令返回主程序,CALL指令調用子程序壓入和彈出操作要成對使用,保持堆棧平衡開始保護寄存器,返回前相應恢復安排在代碼段的主程序之外子程序允許嵌套和遞歸最好有完整的注釋難點是參數(shù)傳遞回車換行子程序DPCRLFdpcrlfproc;回車換行子程序push eax;保護寄存器mov al,0dh;輸出回車字符call dispc;子程序中調用子程序,實現(xiàn)子程序嵌套mov al,0ah;輸出換行字符call dispc;子程序中調用子程序,實現(xiàn)子程序嵌套pop eax;恢復寄存器ret;子
33、程序返回dpcrlfendp4.3.3 參數(shù)傳遞主程序與子程序間通過參數(shù)傳遞建立聯(lián)系入口參數(shù)(輸入?yún)?shù)):主程序子程序出口參數(shù)(輸出參數(shù)):子程序主程序傳遞參數(shù)的多少反映程序模塊間的耦合程度參數(shù)的具體內容數(shù)據(jù)本身(傳遞數(shù)值)數(shù)據(jù)的存儲地址(傳遞地址,傳遞引用)參數(shù)傳遞方法寄存器變量堆棧1. 寄存器傳遞參數(shù)最簡單和常用的參數(shù)傳遞方法把參數(shù)存于約定的寄存器少量數(shù)據(jù)直接傳遞數(shù)值大量數(shù)據(jù)只能傳遞地址帶有出口參數(shù)的寄存器不能保護和恢復帶有入口參數(shù)的寄存器可以保護、也可以不保護,但最好能夠保持一致例4-15十六進制顯示程序1mov eax, 1234abcdh; 假設一個數(shù)據(jù)xor ebx,ebxmov
34、ecx,8; 8位十六進制數(shù)again:rol eax,4; 高4位循環(huán)移位進入低4位push eax; mov edx,eaxcall htoasc; 調用子程序mov regd+4ebx,al; 保存轉換后的ASCII碼pop eax; mov eax,edxinc ebxdec ecxjnz againmov eax,offset regdcall dispmsg; 顯示regd byte EAX=,8 dup(0),H,0例4-15十六進制顯示程序2; 子程序htoascproc; 將AL低4位表達的一位十六進制數(shù)轉換為ASCII碼and al,0fh; 只取AL的低4位or al,3
35、0h; AL高4位變成3cmp al,39h; 是09,還是AFjbe htoendadd al,7; 是AF,ASCII碼再加上7htoend:ret; 子程序返回htoascendp例4-15十六進制顯示程序3; 子程序htoascproc and eax,0fh; 取AL低4位mov al,ASCIIeax ; 換碼ret; 子程序的局部數(shù)據(jù)(只讀)ASCIIbyte 0123456789ABCDEFhtoascendpEAX=1234ABCDH運行結果例4-16有符號十進制數(shù)顯示程序1轉換的算法如下:(1)首先判斷數(shù)據(jù)是零、正數(shù)或負數(shù),是零顯示“0”退出(2)是負數(shù),顯示負號“”,求數(shù)
36、據(jù)的絕對值(3)接著數(shù)據(jù)除以10,余數(shù)為十進制數(shù)碼,加30H轉換為ASCII碼保存(4)重復(3)步,直到商為0結束(5)依次從高位開始顯示各位數(shù)字例4-16有符號十進制數(shù)顯示程序2; 數(shù)據(jù)段arraydword 1234567890,-1234,0,1,.writebufbyte 12 dup(0); 顯示緩沖區(qū); 代碼段mov ecx,lengthof arraymov ebx,0again:mov eax,arrayebx*4 ; EAX入口參數(shù)call write; 調用子程序,顯示一個數(shù)據(jù)call dispcrlf; 換行以便顯示下一個數(shù)據(jù)inc ebxdec ecxjnz agai
37、n寄存器傳遞參數(shù)例4-16有符號十進制數(shù)顯示程序3; 顯示有符號十進制數(shù)的子程序writeproc; EAX入口參數(shù)push ebx; 保護寄存器push ecxpush edxmov ebx,offset writebuf ; EBX指向顯示緩沖區(qū)test eax,eax; 判斷數(shù)據(jù)是零、正數(shù)或負數(shù)jnz write1; 不是零,跳轉mov byte ptr ebx,0; 是零,設置“0”inc ebxjmp write5; 轉向顯示write1:jns write2; 是正數(shù),跳轉mov byte ptr ebx,- ; 是負數(shù),設置負號inc ebxneg eax; 數(shù)據(jù)求補(絕對值)寄
38、存器傳遞參數(shù)例4-16有符號十進制數(shù)顯示程序4write2:mov ecx,10push ecx; 10壓入堆棧,作為退出標志write3:cmp eax,0; 數(shù)據(jù)(商)為零,轉向保存jz write4 xor edx,edx; 零位擴展被除數(shù)為EDX.EAXdiv ecx; 數(shù)據(jù)除以10:EDX.EAX10add edx,30h; 余數(shù)(09)轉換為ASCII碼push edx; 數(shù)據(jù)先低位后高位壓入堆棧jmp write3例4-16有符號十進制數(shù)顯示程序5write4:pop edx; 數(shù)據(jù)先高位后低位彈出堆棧cmp edx,ecx; 是結束標志10,轉向顯示je write5mov e
39、bx,dl; 數(shù)據(jù)保存到緩沖區(qū)inc ebxjmp write4write5:mov byte ptr ebx,0; 顯示內容加上結尾標志mov eax,offset writebufcall dispmsgpop edx; 恢復寄存器pop ecxpop ebxret; 子程序返回writeendp2. 共享變量傳遞參數(shù)子程序和主程序使用同一個變量名存取數(shù)據(jù)如果變量定義和使用不在同一個程序模塊中,需要利用PUBLIC、EXTREN聲明共享變量傳遞參數(shù),子程序的通用性較差特別適合在多個程序段間、尤其在不同的程序模塊間傳遞數(shù)據(jù)例4-17二進制數(shù)輸入程序1輸入一個字符,判斷是否合法是字符“0”或“
40、1”合法減去30H轉換成數(shù)值“0”或“1”重復轉換每個字符將前一次的數(shù)值左移1位并與新數(shù)值進行組合輸入非法字符,或超過數(shù)據(jù)位數(shù)提示錯誤重新輸入例4-17二進制數(shù)輸入程序2; 數(shù)據(jù)段count= 5arraydword count dup(0)tempdword ?; 代碼段mov ecx,countmov ebx,offset arrayagain:call rdbd; 調用子程序,輸入一個數(shù)據(jù)mov eax,temp; 獲得出口參數(shù)mov ebx,eax; 存放到數(shù)據(jù)緩沖區(qū)add ebx,4loop again共享變量傳遞參數(shù)例4-17二進制數(shù)輸入程序3; 輸入二進制數(shù)的子程序rdbdpro
41、c; 出口參數(shù):變量TEMP補碼表示的二進制數(shù)值push eax; 說明:負數(shù)用“”引導push ebxpush ecxrdbd1:xor ebx,ebx;EBX用于存放二進制結果mov ecx,32;限制輸入字符的個數(shù)rdbd2:call readc;輸入一個字符cmp al,0;檢測鍵入字符是否合法jb rderr;不合法則返回重新輸入cmp al,1ja rderr例4-17二進制數(shù)輸入程序4sub al,0;對輸入的字符進行轉化shl ebx,1;EBX的值乘以2or bl,al;BL和AL相加loop rdbd2;循環(huán)鍵入字符mov temp,ebx;把EBX的二進制結果存放TEMP
42、返回call dispcrlf;分行pop ecxpop ebxpop eaxret;子程序返回例4-17二進制數(shù)輸入程序5rderr:mov eax,offset errmsg;顯示錯誤信息call dispmsgjmp rdbd1errmsgbyte 0dh,0ah,Input error, enter again: ,0rdbdendp共享變量傳遞參數(shù)例4-18有符號十進制數(shù)輸入程序1十進制有符號整數(shù)轉換為補碼的算法如下:(1)判斷輸入了正數(shù)、還是負數(shù),用一個寄存器記錄(2)判斷下一個字符是否為有效數(shù)碼字符無效,提示錯誤重新輸入,并轉向(1)字符有效,繼續(xù)(3)字符有效,減30H轉換為二
43、進制數(shù);然后將前面輸入的數(shù)值乘10,并與剛輸入的數(shù)字相加得到新的數(shù)值(4)判斷輸入的數(shù)據(jù)是否超出有效范圍超出范圍,提示錯誤重新輸入,并轉向(1)沒有超出范圍,則繼續(xù)(5)重復(2)(4)步,輸入字符都有效,一直處理完(6)是負數(shù)進行求補,轉換成補碼;否則直接將數(shù)值保存例4-18有符號十進制數(shù)輸入程序2; 數(shù)據(jù)段count= 10arraydword count dup(0)tempdword ?readbufbyte 30 dup(0); 代碼段mov ecx,countmov ebx,offset arrayagain:call read; 調用子程序,輸入一個數(shù)據(jù)mov eax,temp;
44、 獲得出口參數(shù)mov ebx,eax; 存放到數(shù)據(jù)緩沖區(qū)add ebx,4dec ecxjnz again共享變量傳遞參數(shù)例4-18有符號十進制數(shù)輸入程序3; 輸入有符號十進制數(shù)的子程序readproc; 出口參數(shù):變量TEMP補碼表示的二進制數(shù)值push eax; 說明:負數(shù)用“”引導push ebxpush ecxpush edxread0:mov eax,offset readbufcall readmsg; 輸入一個字符串test eax,eaxjz readerr; 沒有輸入數(shù)據(jù),錯誤cmp eax,12ja readerr; 輸入超過12個字符,錯誤例4-18有符號十進制數(shù)輸入程序
45、4mov edx,offset readbuf ; EDX指向輸入緩沖區(qū)xor ebx,ebx; EBX保存結果xor ecx,ecx;ECX為正負標志,0為正,1為負mov al,edx; 取一個字符cmp al,+; 是“”,繼續(xù)jz read1cmp al,-; 是“”,設置1標志jnz read2mov ecx,-1read1:inc edx; 取下一個字符mov al,edxtest al,al; 是結尾0,轉向求補碼jz read3例4-18有符號十進制數(shù)輸入程序5read2:cmp al,0; 不是09之間的數(shù)碼,錯誤jb readerrcmp al,9ja readerrsub
46、 al,30h; 是09之間的數(shù)碼,轉換imul ebx,10; 原數(shù)值乘10:EBXEBX10jc readerr; CF1,乘積溢出,出錯movzx eax,al; 零位擴展,便于相加add ebx,eax; 原數(shù)乘10后,與新數(shù)碼相加cmp ebx,80000000h; 數(shù)據(jù)超過231,出錯jbe read1; 繼續(xù)轉換下一個數(shù)位例4-18有符號十進制數(shù)輸入程序6readerr:mov eax,offset errmsg; 顯示出錯信息call dispmsgjmp read0;read3:test ecx,ecx; 判斷是正數(shù)還是負數(shù)jz read4neg ebx; 是負數(shù),進行求補j
47、mp read5read4:cmp ebx,7fffffffh; 正數(shù)超過231-1,出錯ja readerr例4-18有符號十進制數(shù)輸入程序7read5:mov temp,ebx; 設置出口參數(shù)pop edxpop ecxpop ebxpop eaxret; 子程序返回errmsgbyte Input error, enter again: ,0readendp共享變量傳遞參數(shù)3. 堆棧傳遞參數(shù)主程序將入口參數(shù)壓入堆棧,子程序從堆棧中取出參數(shù)出口參數(shù)通常不使用堆棧傳遞高級語言進行函數(shù)調用時提供的參數(shù),實質也利用堆棧傳遞采用堆棧傳遞參數(shù)是程式化的,它是編譯程序處理參數(shù)傳遞、以及匯編語言與高級語
48、言混合編程時的常規(guī)方法例4-19計算有符號數(shù)平均值程序1; 數(shù)據(jù)段arraydword 675,354,-34, .; 代碼段push lengthof array; 壓入數(shù)據(jù)個數(shù)push offset array; 壓數(shù)組的偏移地址call mean; 調用求平均值子程序;出口參數(shù):EAX平均值(整數(shù)部分)add esp,8; 平衡堆棧(壓入了8個字節(jié)數(shù)據(jù))call dispsid; 顯示堆棧傳遞參數(shù)例4-19計算有符號數(shù)平均值程序2; 計算32位有符號數(shù)平均值子程序meanproc; 入口參數(shù):順序壓入數(shù)據(jù)個數(shù)和數(shù)組偏移地址push ebp;出口參數(shù):EAX平均值mov ebp,esppu
49、sh ebx; 保護寄存器push ecxpush edxmov ebx,ebp+8; EBX取出的偏移地址mov ecx,ebp+12; ECX取出的數(shù)據(jù)個數(shù)xor eax,eax; EAX保存和值xor edx,edx; EDX指向數(shù)組元素堆棧傳遞參數(shù)例4-19計算有符號數(shù)平均值程序3mean1:add eax,ebx+edx*4; 求和add edx,1; 指向下一個數(shù)據(jù)cmp edx,ecx; 比較個數(shù)jb mean1; 循環(huán)cdq; 將累加和EAX符號擴展到EDXidiv ecx; 有符號數(shù)除法,EAX平均值pop edx; 恢復寄存器pop ecxpop ebxpop ebpret
50、meanendp示意圖求和溢出與個數(shù)為0的問題?利用堆棧傳遞參數(shù)返回4.3.4 程序模塊程序分段、子程序等是進行程序模塊化開發(fā)大型程序時采用的方法子程序模塊子程序庫庫文件包含宏匯編源文件包含1. 子程序模塊子程序單獨編寫,匯編形成目標模塊OBJ文件連接時輸入子程序模塊文件名用共用偽指令PUBLIC和外部偽指令EXTERN聲明PUBLIC 標識符 ,標識符 ;定義標識符的模塊使用EXTERN 標識符:類型 ,標識符:類型 ;調用標識符的模塊使用子程序在代碼段,與主程序文件采用相同的存儲模型,沒有開始執(zhí)行和結束執(zhí)行點處理好子程序與主程序之間的參數(shù)傳問題例4-20數(shù)據(jù)輸入輸出程序1; eg0420s
51、.asm(子程序文件)include io32.incpublicread,write,mean; 子程序共用externtemp:dword; 外部變量.data; 定義的變量集中起來writebufbyte 12 dup(0); 顯示緩沖區(qū)readbufbyte 30 dup(0).code; 代碼段writeproc c; 明確采用C語言規(guī)范; 輸出子程序readproc c; 輸入子程序meanproc c; 計算平均值子程序end例4-20數(shù)據(jù)輸入輸出程序2; eg0420.asm(主程序文件)include io32.incexternread:near,write:near,me
52、an:near; 外部子程序publictemp; 變量共用.datacount= 10arraydword count dup(0)tempdword ?msg1byte Enter 10 numbers:,13,10,0msg2byte The mean is: ,0.codestart:mov eax,offset msg1; 提示輸入10個數(shù)據(jù)call dispmsg例4-20數(shù)據(jù)輸入輸出程序3xor ebx,ebx mov ecx,count; ECX數(shù)據(jù)個數(shù)again:call read; 調用子程序,輸入一個數(shù)據(jù)mov eax,temp; 獲得出口參數(shù)mov array ebx*
53、4,eax add ebx,1cmp ebx,ecxjb again例4-20數(shù)據(jù)輸入輸出程序4push ecx; 傳遞參數(shù)push offset arraycall mean; 調用子程序,求平均值add esp,8mov ebx,eax; EAX返回值轉存到EBXmov eax,offset msg2; 提示輸出平均值call dispmsg mov eax,ebx; 提示輸出平均值call write; 調用子程序,顯示平均值exit 0end start2. 子程序庫子程序庫:統(tǒng)一管理子程序模塊遵循更加嚴格的子程序模塊要求子程序文件編寫完成、匯編形成目標模塊利用庫管理工具程序LIB.E
54、XE:把子程序模塊逐個加入到子程序庫(.LIB)使用子程序庫:在連接主程序模塊時提供子程序庫文件名操作演示數(shù)據(jù)輸入輸出程序子程序模塊數(shù)據(jù)輸入輸出程序執(zhí)行實例數(shù)據(jù)輸入輸出程序子程序庫END3. 庫文件包含直接在主程序源文件中用庫文件包含偽指令INCLUDELIB說明不用在連接時輸入庫文件名INCLUDELIB 文件名子程序庫文件名要符合操作系統(tǒng)規(guī)范必要時含有路徑,用于指明文件的存儲位置如果沒有路徑名,匯編程序將在默認目錄、當前目錄和指定目錄下尋找 4. 宏匯編宏(Macro):具有宏名的一段匯編語句序列宏需要先定義宏名MACRO 形參表;宏定義體ENDM然后程序中進行宏調用宏名 實體參數(shù)在匯編時
55、,宏指令被匯編程序用宏定義的代碼序列替代,實現(xiàn)宏展開宏匯編示例宏定義WriteStringmacro msgpush eaxlea eax,msgcall dispmsgpop eaxendm宏展開push eaxlea eax,msgcall dispmsgpop eax宏調用WriteString msg5. 源文件包含INCLUDE 文件名將INCLUDE偽指令指定的文本文件內容插入源程序可以包含任何文本文件一些常用的或有價值的宏定義存放在.MAC宏定義文件各種常量定義、聲明語句等組織在.INC包含文件常用的子程序形成.ASM匯編語言源文件利用INCLUDE偽指令包含其他文件,其實質仍然
56、是一個源程序,只不過是分在了幾個文件書寫組合兩種文件包含、以及宏匯編等方法,可以精簡程序框架、簡化程序設計IO32.INCIO32.INC.nolist; 不列表內容;filename: io32.inc.;declare proceduresexternreadc:near,readmsg:nearexterndispc:near,dispmsg:near,dispcrlf:near;declare I/O librariesincludelib io32.lib;define macrosWriteString MACRO string.list; 列表內容返回4.4 Windows應用程
57、序編程匯編語言可以編寫32位Windows應用程序調用Windows的應用程序接口API運行于Windows操作系統(tǒng)平臺可以利用Windows的高級特性,生成的可執(zhí)行文件相對較小、性能更高從更深層次理解Windows運行機制及程序設計思想4.4.1 操作系統(tǒng)函數(shù)調用操作系統(tǒng)以其提供的系統(tǒng)函數(shù)(系統(tǒng)功能System function)支持程序員進行編程Windows的系統(tǒng)函數(shù)(功能)以動態(tài)連接庫DLL(Dynamic-Link Library)形式提供,利用其應用程序接口API(Application Program Interface)調用DDL庫中的函數(shù)API是一些類型、常量和函數(shù)的集合,提
58、供了編程中使用庫函數(shù)的途徑Win16:16位Windows的APIWin32:32位Windows的API1. 動態(tài)連接庫靜態(tài)連接:連接程序從庫文件中抽取需要的子程序插入到最終的可執(zhí)行代碼中動態(tài)連接:程序運行時才將代碼加載到主存動態(tài)連接庫:保存程序運行時需要重復使用的代碼的文件3個最重要的Windows動態(tài)連接庫KERNEL32.DLL:主要處理內存管理和進程調度USER32.DLL:主要控制用戶界面GDI32.DLL:負責圖形方面的操作導入庫(Import Library):程序開發(fā)的連接階段使用,與一個動態(tài)連接庫DLL對應2. MASM的高級語言特性條件控制偽指令:.IF .ELSEIF
59、.ELSE .ENDIF流程控制偽指令:.WHILE .ENDW .REPEAT .UNTIL.REPEAT .UNTILCXZ .BREAK .CONTINUE過程聲明偽指令PROTO:事先聲明過程的結構(包括操作系統(tǒng)API函數(shù)、高級語言的函數(shù))過程名PROTO調用距離 語言類型 ,參數(shù)類型.過程調用偽指令INVOKE:實現(xiàn)過程調用INVOKE過程名,參數(shù),.3. 程序退出函數(shù)Win32程序員參考手冊VOID ExitProcess( UINT uExitCode/ exit code for all threads );匯編語言聲明ExitProcess PROTO ,:DWORD匯編語言
60、調用invoke ExitProcess,0將函數(shù)調用定義成宏exitMACRO dwexitcodeinvoke ExitProcess,dwexitcodeENDM宏調用exit04.4.2 控制臺應用程序Windows應用程序開始運行創(chuàng)建控制臺(Console)窗口或創(chuàng)建圖形界面窗口32位Windows控制臺程序像增強版的MS-DOS程序使用標準控制臺標準輸入設備(鍵盤)標準輸出設備(顯示器)32位控制臺程序運行在保護方式通過API使用Windows的動態(tài)鏈接庫函數(shù)1. 處理器識別指令CPUID返回處理器特征信息的指令當EAX0時執(zhí)行CPUID指令EAX返回CPUID指令中能夠賦給EAX
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 第1單元 古代亞非文明(高頻非選擇題25題)(原卷版)
- 《波蘭歪屋設計》課件
- 《證券市場概述周》課件
- 玩具設計美工工作總結
- 2023-2024年項目管理人員安全培訓考試題帶答案(黃金題型)
- 關于認識實習報告匯編六篇
- 《系統(tǒng)安全評價概述》課件
- 《婦產(chǎn)科學緒論》課件
- 《監(jiān)理工作程序》課件
- 《應用開發(fā)和管理》課件
- 青島市2022-2023學年七年級上學期期末道德與法治試題
- 高空作業(yè)安全免責協(xié)議書范本
- 石油化學智慧樹知到期末考試答案章節(jié)答案2024年中國石油大學(華東)
- 手術后如何防止排尿困難
- 特種設備“日管控、周排查、月調度”表格
- 重點關愛學生幫扶活動記錄表
- 2021年10月自考00850廣告設計基礎試題及答案含解析
- 結構化面試表格
- 地熱能資源的潛力及在能源領域中的應用前景
- 2023版:美國眼科學會青光眼治療指南(全文)
- 家長會課件:小學寒假家長會課件
評論
0/150
提交評論