彙編學習筆記之轉移指令

迷茫的蕉太狼 發表於 2021-06-09
  1. 什麼是轉移指令:

可以修改IP,或同時修改CS和IP的指令統稱為轉移指令。轉移指令可以通過修改CS和IP的值來實現對CPU執行記憶體某處程式碼的控制

  1. 段內轉移:指令轉移方式IP=IP+位移。等同於JMP 當前IP+需要位移位元組

    段內轉移只修改IP,還是處於一個CS段地址內,例如:JMP AX

    1. 段內短轉移JMP SHORT 標號

      段內短轉移,位移為8bit位,最高位為符號位。剩餘7個bit位可位移,位移間距是:-128~127,也就是說在編譯之後,使用JMP SHORT 標號指令往前轉移最多128個位元組,往後轉移最多127個位元組。

      程式碼示例:

      ASSUME CS:CODE
      CODE SEGMENT
      	START:
      		MOV AX,0
      		MOV BX,0
      		JMP SHORT S
      		ADD AX,1 ; 機器碼:B80100
      		ADD AX,3 ; 機器碼:B80300
      		DB 121 DUP(0) 
      		S:
      			INC AX
      CODE ENDS
      END START
      

      編譯後的機器碼為121個00位元組的機器碼。121+3(B80100)+3(B80300)=127個位元組,如果將DB 121 DUP(0)改成DB 122 DUP(0),那麼程式在MASM 編譯時期就無法通過,因為129個位元組已經完全超過了8位bit。不信的話可以試試

    2. 段內近轉移:JMP NEAR PTR 標號

      段內近轉移,位移為16個bit位,最高位為符號bit位,剩餘15個bit為可進行位移,位移間距是-32768~32767,在編譯之後,使用JMP NEAR PTR 標號轉移指令至多往前轉移32768個位元組,往後至多轉移32767位元組。

      程式碼示例:

      ASSUME CS:CODE
      CODE SEGMENT
      	START:
      		MOV AX,0
      		MOV BX,0
      		JMP NEAR PTR S 
      		ADD AX,2
      		DB 128 DUP(0)
      		S:
      		INC AX
      CODE ENDS
      END START
      

      JMP NEAR PTR 標號編譯後的機器碼為E90000。後面四位就是位移範圍,低位在前,高位在後。用法與JMP SHORT基本一致,只不過前者適用於需要更大幅度的單元跳轉的場景

    3. 為啥近轉移比短轉移多了個PTR關鍵字?

      這是網上搜尋到的一句話:彙編裡面 ptr 是規定 的 字 (既保留字),是用來臨時指定型別的

  2. 段間轉移:JMP FAR PTR 標號

    段間轉移,同時修改CS和IP的值,可跨越不同段直接進行指令轉移。等同於JMP CS:IP。同時CS=標號所在段地址,IP=標號所在段地址偏移量。也就是說最大轉移幅度應該是(cs*10H)+IP=FFFFF。相當於20個bit位進行位移。最大幅度應該是-1,048,576~1,048,575個位元組。

  3. 使用記憶體單元進行指令轉移

    1. 使用記憶體單元進行近轉移:JMP WORD PTR 記憶體單元地址

      從記憶體單元地址處開始存放著一個字,是轉移目的地指令的偏移地址。

      偏移地址計算方式:JMP DS:[BX]。將BX指向的記憶體單元中的資料用於IP暫存器的值。跳轉到指定的位置。偏移量範圍參考:段內近轉移

    2. 使用記憶體單元進行段間轉移:JMP DWORD PTR 記憶體單元地址

  4. 有條件轉移

    所有有條件轉移指令都是短轉移,在對應的機器碼中包含轉移的位移,而不是目的地址。對IP的修改範圍參考段內短轉移

    1. JCXZ 指令

      JCXZ 標號為有條件轉移指令之一,它用於判斷CX是否等於0,如果等於0,則執行指令轉移,否則它什麼都不做,程式繼續往下執行,用Java語言的語法表示為:if(cx == 0){jmp ip}。這樣舉例或許更好理解JCXZ指令的作用

      程式碼示例:

      ASSUME CS:CODE,DS:DATA
      CODE SEGMENT
      	START:
      		MOV AX,DATA
      		MOV DS,AX
      		MOV AX,0
      		MOV BX,0
      		S:
      			MOV CL,DS:[BX]	; 將記憶體單元中的值取出,儲存到CL中
      			JCXZ SAVE		; 如果CX==0時,轉移到SAVA標號處,儲存當前BX的偏移量
      			INC BX			; 如果CX!=0時,BX+1,也就是偏移量+1。繼續轉移到S標號處執行
      			JMP SHORT S
      		SAVE:
      			MOV DX,BX
      		MOV AH,4CH
      		INT 21H
      CODE ENDS
      DATA SEGMENT
      	DB 12,20,32,00,36
      DATA ENDS
      END START
      
    2. LOOP 指令

      LOOP 標號是一個迴圈指令,但是也是屬於有條件轉移指令的一種。需要注意的是所有迴圈指令都是短轉移。它判斷CX中的值,是否需要進行指令轉移。跟JCXZ指令恰恰相反,LOOP指令用判斷CX-1之後是否不等於0,如果不等於0則轉移到標號處。如果等於0,則程式往下執行。用Java語言表示的話,應該是下面程式碼所執行的效果,其中while就相當於LOOP指令,每次指令LOOP指令轉移時,先將CX中的值-1,然後在判斷CX不等於0

      Assembly程式碼:

      ASSUME CS:CODE
      CODE SEGMENT
      	MOV CX,32
      	S:
      		; LOOP迴圈體程式碼段,這裡只能有125個位元組哦
      	LOOP S
      COED ENDS
      

      Java程式碼:

      public class Test{
          public static void main(String[] args){
              int cx = 32;
              while((--c) != 0){
                  // 標號處到LOOP指令之間的程式碼段
              }
          }
      }
      

    以上舉的兩個例子都是使用CX暫存器是否為0進行條件判斷的。還有使用標誌暫存器作為條件進行指令轉移的指令,詳情檢視:《條件轉移指令之使用標誌暫存器進行指令轉移》