天天看點

第四章 彙編語言程式設計

文章目錄

    • 分支程式結構
      • 無條件轉移指令
      • 條件轉移指令
      • 單分支程式結構
      • 雙分支程式結構
    • 循環程式結構
      • 循環指令
      • 計數控制循環
      • 條件控制循環
    • 子程式結構
      • 子程式指令
      • 子程式設計
      • 參數傳遞

分支程式結構

改變程式執行順序、形成分支、循環、調用等程式結構是很常見的程式設計問題。

進階語言采用IF等語句表達條件,并根據條件是否成立轉向不同的程式分支。

彙編語言需要首先利用比較CMP、測試TEST、加減運算、邏輯運算等影響狀态标志的指令形成條件,然後利用條件轉移指令判斷由标志表達的條件,并根據标志狀态控制程式轉移到不同的程式段。

無條件轉移指令

程式代碼在代碼段

CS:指明代碼段在主存中的段基位址

EIP:給出将要執行指令的偏移位址

程式順序執行,處理器自動增量EIP

程式控制轉移,EIP随之改變

程式轉移到另外的代碼段,EIP和CS都改變

控制轉移類指令:改變EIP(有些也改變CS),即改變程式執行順序(實作程式控制轉移)的指令

  1. 轉移範圍

    段内轉移

    在目前代碼段範圍内的程式轉移

    不需更改CS,隻要改變EIP(偏移位址)

    近轉移(Near):32位近轉移NEAR32,16位近轉移NEAR16

    短轉移(Short):轉移範圍在127~-128位元組

    段間轉移

    從目前代碼段跳轉到另一個代碼段

    需要更改CS(段位址)和EIP(偏移位址)

    遠轉移(Far): 48位遠轉移FAR32,32位遠轉移FAR16

  2. 指令尋址方式

    相對尋址方式

    提供目标位址相對于目前指令指針EIP的位移量

    目标位址(轉移後的EIP)=目前EIP+位移量

    相對尋址都是段内轉移,最常用、最靈活

    直接尋址方式

    直接提供目标位址

    目标位址(轉移後的CS和EIP)=指令操作數

    間接尋址方式

    訓示寄存器或存儲單元

    目标位址來自寄存器或存儲單元、間接獲得

    寄存器間接尋址:用寄存器儲存目标位址

    存儲器間接尋址:用存儲單元儲存目标位址

  3. JMP指令

    無條件轉移:程式無條件改變執行順序

    JMP指令相當于進階語言的goto語句

條件轉移指令

根據指定的條件确定程式是否發生轉移

Jcc  label  ;條件滿足,發生轉移;否則,順序執行下條指令
           

· LABEL表示目标位址,采用段内相對尋址

32位IA-32處理器:達到32位的全偏移量

16位80x86處理器:-128~+127間的短轉移

條件轉移指令不影響标志,但要利用标志

· cc表示利用标志判斷的條件,16種、兩類

單個标志狀态作為條件、兩數大小關系作為條件

  1. 單個标志狀态作為條件的條件轉移指令
JZ(JE)和JNZ(JNE):利用零位标志ZF
判斷結果是零(相等)還是非零(不等)
JS和JNS:利用符号标志SF
判斷結果是負還是正
JO和JNO:利用溢出标志OF
判斷結果是溢出還是沒有溢出
JP(JPE)和JNP(JPO):利用奇偶标志PF
判斷結果低位元組“1”的個數是偶數還是奇數
JC和JNC:利用進位标志CF
判斷結果是有進位(為1)還是無進位(為0)
           
第四章 彙編語言程式設計
  1. 單個标志狀态作為條件的條件轉移指令
無符号數用高(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指令調用子程式

· 壓入和彈出操作要成對使用,保持堆棧平衡

· 開始保護寄存器,傳回前相應恢複

· 安排在代碼段的主程式之外

· 子程式允許嵌套和遞歸

參數傳遞

主程式與子程式間通過參數傳遞建立聯系

入口參數(輸入參數):主程式→子程式

出口參數(輸出參數):子程式→主程式

傳遞參數的多少反映程式子產品間的耦合程度

參數的具體内容:資料本身(傳遞數值)、資料的存儲位址(傳遞位址,傳遞引用)

參數傳遞方法:寄存器、變量、堆棧

  1. 寄存器傳遞參數

    最簡單和常用的參數傳遞方法

    把參數存于約定的寄存器

    少量資料直接傳遞數值,大量資料隻能傳遞位址

    帶有出口參數的寄存器不能保護和恢複

    帶有入口參數的寄存器可以保護、也可以不保護,但最好能夠保持一緻

  2. 共享變量傳遞參數
  3. 堆棧傳遞參數

    主程式将入口參數壓入堆棧,子程式從堆棧中取出參數

    出口參數通常不使用堆棧傳遞

    進階語言進行函數調用時提供的參數,實質也利用堆棧傳遞

    采用堆棧傳遞參數是程式化的,它是編譯程式處理參數傳遞、以及彙編語言與進階語言混合程式設計時的正常方法