我不明白為什么我會收到一條非法指令,其中一段代碼在 C 程式中實作為匯編。我稍微解釋一下。
我在特定地址有一個值,我想將該值移動到 EAX x86 暫存器中,例如
MOV EAX, [address]
在 C 代碼中,我有該地址的指標。我是這樣準備了這條指令的二進制代碼的:
MOV OpCode:
7 6 5 4 3 2 1 0
|_|_|_|_|_|_|D|S|
D = 1 --> I want REG as destination
S = 1 --> 32 bit operand
D S
--> |1|0|0|0|1|0|1|1| --> 0x89
Mod R/M:
7 6 5 4 3 2 1 0
|_|_|_|_|_|_|_|_|
--> MOD = |7|6| bits
--> REG = |5|4|3| bits
--> R/M = |2|1|0| bits
MOD = Indirect --> |0|0|
REG = EAX = 0 --> |0|0|0|
地址不在暫存器中,我想將記憶體資料移動到 EAX 暫存器。我有記憶體位置的值,所以:
R/M = |1|1|0| --> direct
--> |0|0|0|0|0|1|1|0| --> 0x06
Address = [byte0] [byte1] [byte2] [byte3]
--> 0x8b 0x06 [byte3] [byte2] [byte1] [byte0] 0xc3
通過這種方式,我獲得了非法指令,但我不明白為什么。如果我使用 R/M = 101 我得到 0x8b 0x05 [byte3] [byte2] [byte1] [byte0] 0xc3 并且一切正常。
那么,問題出在哪里呢?有沒有人可以解釋這張表中 MOD=00, R/M=110 的用法?直接???

MOD=00, R/M=101 works but in the table I see memory location calculated from DI but I have a direct memory location...
Note: Code compiled on Ubuntu 20.04 (64 bit) with -m32 gcc switch
uj5u.com熱心網友回復:
關鍵問題是您在為 32 位模式組裝時正在查看 16 位 modr/m 表。每種操作模式都有自己的尋址模式,并且 modr/m 和 SIB 位元組在記憶體運算元的編碼方式上有所不同。
對于 32 位模式,直接尋址由 mod = 00, r/m = 101 選擇。 所以正確的 modr/m 位元組是:
00 000 101 XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
mod reg r/m ---------- displacement -----------
其中 reg = 000(編碼eax)和 mod = 00,r/m = 101 編碼直接地址。這是05您已經觀察到正在作業的modr/m 位元組。
在 16 位模式下,直接尋址由 mod = 00, r/m = 110 選擇,并帶有 2 個位元組的位移,給出 modr/m 位元組的06.
請注意,在 16 位和 32 位操作模式下,您可以通過提供67地址大小覆寫前綴在 16 位和 32 位 modr/m 位元組之間切換。
至于你的具體使用情況下的替代選項,您也可以使用A1操作碼mov eax, off32。該操作碼直接采用 32 位地址加載,沒有 modr/m 位元組,但尋址模式和目標暫存器都是硬編碼的。
uj5u.com熱心網友回復:
好吧,我用錯了桌子。我從英特爾網站上找到了正確的表格。感謝您的快速答復

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/347743.html
標籤:assembly x86 machine-code instruction-encoding
