彙編轉移指令jmp原理
在計算機中儲存的都是二進位制數,計算機將記憶體中的某些數當做程式碼,某些數當做資料。在根本上,將cs,ip暫存器所指向的記憶體當做程式碼,指令轉移就是修改cs,ip暫存器的指向,彙編中提供了一種修改它們的指令——jmp。
jmp指令可以修改IP或cs和IP的值來實現指令轉移,指令格式為:”jmp 標號“將指令轉移到標號處,例如:
CODES SEGMENT
ASSUME CS:CODES
START:
MOV AX,0
jmp s
inc ax
s: mov ax,3
MOV AH,4CH
INT 21H
CODES ENDS
END START
通過單步除錯可以看出在執行jmp後直接執行s標號後面的程式碼,此時ax為3,。jmp s所對應的機器碼為”EB01”,在“Inc ax”後面再加其他的指令(加兩個 nop指令)此時jmp所對應的機器碼為”EB03”,每一個nop指令佔一個位元組,在新增或刪除它們之間的程式碼可以看到jmp指令所對應的機器碼佔兩個位元組,第一個位元組的機器碼並不發生改變,改變的是第二個位元組的內容,並且第二個位元組的內容儲存的是跳轉目標指令所在記憶體與jmp指令所在記憶體之間的位移。
其實cup在執行jmp指令時並不會記錄標號所在的記憶體地址,而是通過標號與jmp指令之間的位移,假設jmp指令的下一條指令的地址為org,位移為idata,則目標的記憶體地址為dec = org + idata。(idata有正負之分)
在CPU中有指令累加器稱之為CA暫存器, 程式每執行一條,CA的值加1,jmp指令後可以有4中形式“jmp short s、jmp、 s jmp near ptr s、jmp far ptr s”編譯器在翻譯時,位移所對應的內粗大小為1、2、2、4(分別是cs和ip所對應的位移)。都是帶符號的整型。jmp指令的跳轉分為兩種情況:向前跳轉和向後跳轉。
向後跳轉:jmp (…..)s
……
……
s:……
這種情況下,編譯器將jmp指令讀完後,讀下一條指令,並將CA加1,一直讀到相應的標號處,此時CA的值就是位移,根據具體的偽指令來分配記憶體的大小(此時的數應該為正數)
向前跳轉 :
s:…….
……..
jmp (……) s
編譯器在遇到標號時會在標號後新增幾個nop指令(”jmp short s、jmp、 s jmp near ptr s、jmp far ptr s”分別新增1,2,2,4個),讀下一條指令時將CA暫存器的值加1,得到對應的位移,生成機器碼(此時為負數).
這兩種方式分別得到位移後,在執行過程中,利用上述公式計算出對應的地址,實現指令的轉移
下面的一段程式碼充分說明了jmp的這種實現跳轉的機制:
assume cs:code
code segment
mov ax,4c00h
int 21h
start: mov ax,0
s: nop
nop
mov di,offset s
mov si,offset s2
mov ax,cs:[si]
mov cs:[di],ax
s0: jmp short s
s1: mov ax,0
int 21h
mov ax,0
s2: jmp short s1
nop
code ends
end start
通過以上的分析可以得出,幾個jmp指令所佔的空間為2個位元組,一個儲存jmp本省的機器碼,EB,另一個儲存位移。因此兩個nop指令後面的四句是將s2處的“jmp short s1”所對應的機器碼拷貝到s處,利用debug下的-u命令可以看出該處的機器碼為“EB F6” f6轉化為十進位制是-10.
執行到s0處時,jmp指令使CPU下一次執行s處的程式碼,“EB F6”對應的操作利用公式可以得出IP = A - A = 0,下一步執行的程式碼是“MOV AX,4C00H”,也就是說該程式在此處結束。
用-t命令單步除錯: