前言
JMP
指令根據跳轉目的地遠近分成短跳轉 (Short jump)、近跳轉 (Near jump)、遠跳轉 (Far jump)、他們所代表的含意不一樣,使得機械碼 opcode 呈現的方式也不一樣。
閱讀手冊
引用指令手冊(Intel® 64 and IA-32 Architectures Software Developer's Manual)裡面一些對於 JMP
的敘述:
- Short jump—A near jump where the jump range is limited to –128 to +127 from the current EIP value.
- Near jump—A jump to an instruction within the current code segment (the segment currently pointed to by the CS register), sometimes referred to as an intrasegment jump.
- Far jump—A jump to an instruction located in a different segment than the current code segment but at the same privilege level, sometimes referred to as an intersegment jump.
它們主要是以所要跳的目的地位址與現在的 IP
(instruction pointer) 位址差值來區分:
- 短跳轉:差值在 -128 ~ +127 (8-bit) 之內。
- 近跳轉:目的地在同一個區段內,且差值在 32-bit 可以表示的範圍內,又稱段內跳轉。
- 遠跳轉:目的地在別的區段,又稱段間跳轉。
雖然在組合語言都是以 JMP
來實現跳轉,但在組譯轉成 opcode 時翻譯出來的卻不一樣,短跳轉 (EB
)、近跳轉 (E9
)、遠跳轉 (EA
)。當然,opcode 不一樣就代表是不同的指令,其後的參數要怎麼給是該瞭解的事情。參考手冊說明摘要如下:
Jump | Opcode | Instruction |
---|---|---|
Short Jump | EB cb | JMP rel8 |
Near Jump | E9 cw/cd | JMP rel16/rel32 |
Far Jump | EA cd/cp | JMP ptr16:16/ptr16:32 |
參數解釋
rel8
/rel16
/rel32
:偏移量(也就是上面提到的差值)能用有號 8/16/32-bit 來表示的相對位址。ptr16:16
/ptr16:32
:一個相對遠的指標 (pointer),通常與IP
不同區段,前面的 16/16 表示 16-bit 的區段暫存器,後面的 16/32 表示目的地在那個區段的偏移量。cb
/cw
/cd
/cp
:用來描述代碼的偏移量和新的區段暫存器的值,分別為 1-byte、2-byte、4-byte、6-byte。
程式驗證
有概念之後,用程式來對上面敘述做驗證吧:
短跳轉
Address | Opcode | Instruction |
---|---|---|
003F1010 | EB 06 | JMP 003F1018 |
003F1012 | EB 04 | JMP 003F1018 |
003F1014 | EB 02 | JMP 003F1018 |
因為指令位址距目的很近,所以為短跳轉 (EB
),EB
後的數字為目的地與 EIP
的偏移量,但可能有人會問,為什麼對不起來?
像是第一個的 偏移量 = 003F1018h - 003F1010h = 08h
結果不是 EB 08
,而是 EB 06
。這是因為 CPU 在運作時,看到 EB 06
知道要跳轉,也由於它已經讀了這一指令,EIP
會再加 2 指向下一指令,再執行 EB 06
這個指令。可以看得出關鍵嗎?在執行 EB 06
時 EIP
已經又加 2 了,實際上的算法應為 偏移量 = 003F1018h - (003F1010h + opcode的長度) = 06h
近跳轉
Address | Opcode | Instruction |
---|---|---|
013D1035 | E9 85 00 00 00 | JMP 013D10BF |
013D103A | E9 80 00 00 00 | JMP 013D10BF |
013D103F | EB 7E | JMP 013D10BF |
偏移量的算法和短跳轉相同,不同在於近跳轉的 opcode 且 E9
與長度為 5-byte,在計算時要注意。在此特地用跳轉至同目的地但分別為近跳轉與短跳轉來說明,當從 1-byte 的 7E 要進位到 80 時,就會變成 4-byte 的 00 00 00 80h
,因為其超出有號 8-bit 可表示範圍。