文章目錄
-
- 分支程式結構
-
- 無條件轉移指令
- 條件轉移指令
- 單分支程式結構
- 雙分支程式結構
- 循環程式結構
-
- 循環指令
- 計數控制循環
- 條件控制循環
- 子程式結構
-
- 子程式指令
- 子程式設計
- 參數傳遞
分支程式結構
改變程式執行順序、形成分支、循環、調用等程式結構是很常見的程式設計問題。
進階語言采用IF等語句表達條件,并根據條件是否成立轉向不同的程式分支。
彙編語言需要首先利用比較CMP、測試TEST、加減運算、邏輯運算等影響狀态标志的指令形成條件,然後利用條件轉移指令判斷由标志表達的條件,并根據标志狀态控制程式轉移到不同的程式段。
無條件轉移指令
程式代碼在代碼段
CS:指明代碼段在主存中的段基位址
EIP:給出将要執行指令的偏移位址
程式順序執行,處理器自動增量EIP
程式控制轉移,EIP随之改變
程式轉移到另外的代碼段,EIP和CS都改變
控制轉移類指令:改變EIP(有些也改變CS),即改變程式執行順序(實作程式控制轉移)的指令
-
轉移範圍
段内轉移
在目前代碼段範圍内的程式轉移
不需更改CS,隻要改變EIP(偏移位址)
近轉移(Near):32位近轉移NEAR32,16位近轉移NEAR16
短轉移(Short):轉移範圍在127~-128位元組
段間轉移
從目前代碼段跳轉到另一個代碼段
需要更改CS(段位址)和EIP(偏移位址)
遠轉移(Far): 48位遠轉移FAR32,32位遠轉移FAR16
-
指令尋址方式
相對尋址方式
提供目标位址相對于目前指令指針EIP的位移量
目标位址(轉移後的EIP)=目前EIP+位移量
相對尋址都是段内轉移,最常用、最靈活
直接尋址方式
直接提供目标位址
目标位址(轉移後的CS和EIP)=指令操作數
間接尋址方式
訓示寄存器或存儲單元
目标位址來自寄存器或存儲單元、間接獲得
寄存器間接尋址:用寄存器儲存目标位址
存儲器間接尋址:用存儲單元儲存目标位址
-
JMP指令
無條件轉移:程式無條件改變執行順序
JMP指令相當于進階語言的goto語句
條件轉移指令
根據指定的條件确定程式是否發生轉移
Jcc label ;條件滿足,發生轉移;否則,順序執行下條指令
· LABEL表示目标位址,采用段内相對尋址
32位IA-32處理器:達到32位的全偏移量
16位80x86處理器:-128~+127間的短轉移
條件轉移指令不影響标志,但要利用标志
· cc表示利用标志判斷的條件,16種、兩類
單個标志狀态作為條件、兩數大小關系作為條件
- 單個标志狀态作為條件的條件轉移指令
JZ(JE)和JNZ(JNE):利用零位标志ZF
判斷結果是零(相等)還是非零(不等)
JS和JNS:利用符号标志SF
判斷結果是負還是正
JO和JNO:利用溢出标志OF
判斷結果是溢出還是沒有溢出
JP(JPE)和JNP(JPO):利用奇偶标志PF
判斷結果低位元組“1”的個數是偶數還是奇數
JC和JNC:利用進位标志CF
判斷結果是有進位(為1)還是無進位(為0)

- 單個标志狀态作為條件的條件轉移指令
無符号數用高(Above)、低(Below)
低于(不高于等于):JB(JNAE)
不低于(高于等于):JNB(JAE)
低于等于(不高于):JBE(JNA)
不低于等于(高于):JNBE(JA)
有符号數用大(Greater)、小(Less)
小于(不大于等于):JL(JNGE)
不小于(大于等于):JNL(JGE)
小于等于(不大于):JLE(JNG)
不小于等于(大于):JNLE(JG)
單分支程式結構
隻有一個分支的程式,類似進階語言的IF-THEN語句結構
注意采用正确的條件轉移指令
當條件滿足(成立),發生轉移,跳過分支體;條件不滿足,順序向下執行分支體
條件轉移指令與進階語言的IF語句正好相反;IF語句是條件成立,執行分支體
雙分支程式結構
雙分支程式結構有兩個分支,條件為真執行一個分支;條件為假,執行另一個分支,相當于進階語言的IF-THEN-ELSE語句
順序執行的分支體1最後一定要有一條JMP指令跳過分支體2
JMP指令必不可少,實作結束前一個分支回到共同的出口作用
雙分支結構有時可以改變為單分支結構,事先執行其中一個分支(選擇出現機率較高的分支)
循環程式結構
三個部分組成:
循環初始——為開始循環準備必要的條件,如循環次數、循環體需要的初始值等;
循環體——重複執行的程式代碼,其中包括對循環條件的修改等;
循環控制——判斷循環條件是否成立,決定是否繼續循環
“先判斷、後循環”的循環程式結構,對應進階語言的WHILE語句
“先循環、後判斷”的循環程式結構,對應進階語言的DO語句
循環指令
LOOP label
;ECX←ECX-1;若ECX≠0,循環到LABEL
;否則,順序執行
JECXZ label
;ECX=0,轉移;否則順序執行
目标位址采用相對短轉移,實位址存儲模型使用CX作為計數器
計數控制循環
通過次數控制循環,利用LOOP指令屬于計數控制,常見是“先循環、後判斷”循環結構
計數可以減量進行,即減到0結束;計數可以增量進行,即達到規定值結束
條件控制循環
· 根據條件決定是否進行循環
需要使用有條件轉移指令實作,多見“先判斷、後循環”結構
· 先行判斷的條件控制循環程式
很像雙分支結構,主要分支需要重複執行多次(JMP的目标位置是循環開始),另一個分支用于跳出這個循環
· 先行循環的條件控制循環程式
類似單分支結構,循環體就是分支體,順序執行就跳出循環
子程式結構
子程式(Subroutine)=函數(Function)=過程(Procedure)
子程式指令
子程式:與主程式分開的、完成特定功能的一段程式
當主程式(調用程式)執行調用指令CALL調用子程式
子程式(被調用程式)執行傳回指令RET傳回主程式
MASM利用過程定義僞指令獲得子程式資訊
過程名 PROC
…… ;過程體
過程名 ENDP
;過程名為符合文法的辨別符
PROC後面可加參數:NEAR或FAR
簡化段定義源程式格式中,通常不需指定
子程式調用的堆棧
子程式設計
子程式的編寫方法與主程式一樣
但需要留意幾個問題:
· 利用過程定義,獲得子程式名和調用屬性
· RET指令傳回主程式,CALL指令調用子程式
· 壓入和彈出操作要成對使用,保持堆棧平衡
· 開始保護寄存器,傳回前相應恢複
· 安排在代碼段的主程式之外
· 子程式允許嵌套和遞歸
參數傳遞
主程式與子程式間通過參數傳遞建立聯系
入口參數(輸入參數):主程式→子程式
出口參數(輸出參數):子程式→主程式
傳遞參數的多少反映程式子產品間的耦合程度
參數的具體内容:資料本身(傳遞數值)、資料的存儲位址(傳遞位址,傳遞引用)
參數傳遞方法:寄存器、變量、堆棧
-
寄存器傳遞參數
最簡單和常用的參數傳遞方法
把參數存于約定的寄存器
少量資料直接傳遞數值,大量資料隻能傳遞位址
帶有出口參數的寄存器不能保護和恢複
帶有入口參數的寄存器可以保護、也可以不保護,但最好能夠保持一緻
- 共享變量傳遞參數
-
堆棧傳遞參數
主程式将入口參數壓入堆棧,子程式從堆棧中取出參數
出口參數通常不使用堆棧傳遞
進階語言進行函數調用時提供的參數,實質也利用堆棧傳遞
采用堆棧傳遞參數是程式化的,它是編譯程式處理參數傳遞、以及彙編語言與進階語言混合程式設計時的正常方法