x86-64 アドレッシングまとめ

このまとめは、間違い勘違いを含んでいる可能性があります。ご注意を。

基本

mov [base-reg + index-reg * scale + displacement], src-reg ; intel 形式
movq src-reg, displacement(base-reg, index-reg, scale) ; gas 形式	
(movq (& base-reg + (* index-reg scale) + displacement) src-reg) ; sassy 形式
=> メモリ[base-reg の値 + index-regの値 * scale] = src-reg
  • displacement は disp8(8bit整数) か disp32(32bit整数)
  • scale は 1, 2, 4, 8 のいずれか
  • index-reg と scale は配列アクセスに使われる。
    • index-reg が配列の index
    • scale は、その型のサイズ
add dest-reg, [base-reg + index-reg * scale]
=> dest-reg = dest-reg + メモリ[base-reg の値 + index-regの値 * scale]	

なので注意。

SIB

上の index-reg と scale を利用するアドレッシングでは SIB バイトを利用する。
具体的には

  • ModR/M の r/m を 100 にする
  • mod を 00, 01, 10 のいずれかに指定する
  • sib バイトに scale, base-red, index-reg を encode する
    • register が r8-r15 の場合はビット数が足りないので REX プレフィックスを利用する

種々のアドレッシングと解釈

その1
mov [base-reg], src-reg
movq src-reg, (base-reg)
(movq (& base-reg) src-reg)
=> メモリ[base-reg] = src-reg

displacement, SIB が省略されたパターン。

その2
mov [base-reg + disp8], src-reg
movq src-reg, disp8(base-reg)
(movq (& base-reg disp8) src-reg)
=> メモリ[base-reg + disp8] = src-reg

disp8 は 8bit 整数。SIB バイトは省略。ModR/m の mod で 01 を指定すれば良い。
disp8 が disp32 になった場合は 32bit 整数で、mod = 10 。

その3
mov [base-reg + scale * index-reg + disp8], src-reg
movq disp8(base-reg, index-reg, scale), src-reg
(movq (& base-reg disp8 (* index-reg scale)) src-reg)	
=> メモリ[base-reg + scale * index-reg + disp8] = src-reg

SIB バイトを設定しつつ、mod を 01 に。disp32 も同様。

その4
mov [scale * index-reg + disp32], src-reg
movq disp32(, index-reg, scale), src-reg
(movq (& disp8 (* index-reg scale)) src-reg)		
=> メモリ[scale * index-reg + disp32] = src-reg

base-reg 無指定バージョン。この形式は disp8 は許されない。
base = 101, mod = 00 とするとこの形式になる。


こんな感じかな。RIP 相対は使わないので省略。
アドレッシングモード自体は自然に感じるが、encode 方法が以下略。


ちなみに objdump には --disassembler-options=intel というオプションがあり比較時に便利。
同様に gcc -S -masm=intel も便利。