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 も便利。