x86 Instruction Prefix Bytes - HobbyOSs/opennask GitHub Wiki

x86 Instruction Prefix Bytes

さらっと紹介されているけどわからんので、特に 0x66, 0x67 について

32bitモードの最初の2バイトはOverride prefixesと呼ばれる。なぜならそれらは常に存在するとは限らないからだ。 最初の1バイト目(0x67)は命令に使われるオペランドのアドレスのサイズを変更する。 次の2バイト目(0x66)はオペランドサイズを変更する。

この規則はわりとどこでも適用されるのだが、インテルの仕様ドキュメントに記載があまりない。

  • はじめて読む486 のp.164~166に色々と載っていたので、その情報とWEBの情報をもとにまとめる

アドレスサイズとは

アドレスサイズとはアセンブラ命令が扱うメモリのサイズのこと

MOV AX, [0x1234]    ; これは16bitサイズなのでアドレスサイズ16bit
MOV AX, [SI]        ; これは16bitサイズなのでアドレスサイズ16bit

MOV AX, [0x12345678] ; これは32bitサイズなのでアドレスサイズ32bit
MOV AX, [ESI]        ; これは32bitサイズなのでアドレスサイズ32bit

オペランドサイズとは

オペランドサイズとはアセンブラ命令が扱う数値のサイズのこと

MOV AX,  0x1234        ; これは16bitサイズなのでオペランドサイズ16bit
MOV EAX, 0x12345678    ; これは32bitサイズなのでオペランドサイズ32bit

アドレスサイズとオペランドサイズのおさらい

オペランドサイズ16bit オペランドサイズ32bit
アドレスサイズ16bit MOV AX, [BX] MOV EAX, [BX]
アドレスサイズ32bit MOV AX, [EBX] MOV EAX, [EBX]

以下のことがわかる

  • オペランドサイズはメモリーアドレス表現関係なしにレジスタと即値を見てやれば決まる
  • アドレスサイズはメモリーアドレス表現のみ見てやれば決まる

そして、デフォルトのモードは16bit命令モード/32bit命令モードのどちらかで決まる

0x67(アドレスサイズ・プレフィックス)

  • もし、CPUが16bit命令モードとして(プロテクトモードのみ)動き、メモリーアドレス表現に32bitレジスタが使われていれば
    • Address-size prefixは無視される。(※naskではこの場合0x67は機械語として付与されない)
  • もし、32bit命令モードでメモリーアドレス表現に16bitレジスタが現れるのであれば、
    • ➔ 16bitレジスタを選択するためにAddress-size prefixが現れる。

0x66(オペランドサイズ・プレフィックス)

  • Pentium IIで80386が16bit命令モードとして(リアルモードもしくはプロテクトモード)動く
  • 32bitレジスタが使われていれば、 Operand-size prefixes(0x66) が命令の前に付加される。

逆に、

  • リアルモードで32bitのアドレッシング・モードを使うことが出来る、それは命令の最初に Operand-size prefix を付加することで可能だ

機械語の概略

(a) 16-bit instruction mode
 _________  ___________  ____________  _________
| Opcode  ||MOD-REG-R/M||Displacement||Immediate|
|         ||           ||            ||0-4 bytes|
|1-2 bytes|| 0-1 bytes ||            ||         |
|         ||           ||            ||         |
|         ||           ||            ||         |
 ---------  -----------  ------------  ---------

(b) 32-bit instruction mode (80386 through Pentium 4 only)
 ........  ........  _________  ___________  .........  __________________
:Address ::Operand :| Opcode  ||MOD-REG-R/M|:Scaled   :|Displace-||Immediate|
:size    ::size    :|         ||           |:Index    :|ment     ||0-4bytes |
:0-1bytes::0-1bytes:|1-2 bytes|| 0-1 bytes |:0-1 bytes:|         ||         |
:Prefix  ::        :|         ||           |:         :|         ||         |
:67H     ::66H     :|         ||           |:         :|         ||         |
 ''''''''  ''''''''  ---------  -----------  '''''''''  ------------------

実例

  • (1) [BITS 32]を宣言してないので16bit命令モードである
; プロテクトモード移行
[INSTRSET "i486p"]              ; 486の命令まで使いたいという記述
MOV     ECX,[EBX+16]            ; 0x67 0x66 0x8b 0x4b 0x10
  • 0x67

    • 16bit命令モード かつ メモリーアドレス表現に32bitレジスタが使われている よって 0x67 を付加
  • 0x66

    • 16bit命令モード かつ 32bitレジスタを使っている よって 0x66 を付加
  • (2) [BITS 32]を宣言している

[BITS 32]
[INSTRSET "i486p"]

MOV ECX,[ESP+4] ; 0x8b, 0x4c, 0x24, 0x04 
MOV AL,[ESP+8]  ; 0x8a, 0x44, 0x24, 0x08
  • 0x67
    • 32bit命令モード32bitレジスタが使われている よって 0x67 は不要
  • 0x66
    • 32bit命令モード なので 0x66 は不要