x86フォーマットまとめ

最近まとめページ化が激しいですね。
昨今のスクリプトランゲージへのなんたらかんたらが高まり要求されるパフォーマンスを実現するためにJITコンパイルは必須です。命令フォーマットに関する知識は全SEに欠かせないものとなっていくのである。
ライトウェイツなランゲージが流行する昨今において、機械語ぐらい読めないと生きていけないのだった。


とりあえず、nasmdocのAppendix Bが読めるくらいまでを目指す。
http://nasm.sourceforge.net/doc/html/nasmdocb.html



レジスタいっこずつに番号。左から順に 0..7

8bit register
al,cl,dl,bl,ah,ch,dh,bh
16bit register
ax,cx,dx,bx,sp,bp,si,di
32bit register
eax,ecx,edx,ebx,esp,ebp,esi,edi


CISCっぽい点として、キモいアドレスフォーマット。…と思ったけど、それだと、マニュアル見たほうがはやいような気がした。

長いmov

長いmovを書いてみよう。

.code16
lock	movl	%cs:0xf0e0d0c0(%eax,%edx,4), %eax
f0 67 66 2e 8b 84 90 c0 d0 e0 f0 

「わお!ジョニー!11byteだよ!素晴らしいね!一体どうやったんだい!?」
「これがCISCの力なのさ!RISCなんて軟弱な奴向けの命令フォーマットだってことがよくわかるなんじゃかんじゃ」


f0
lock プレフィクス。付いてるとなんか。
67
16bit環境でオペランドのアドレスが32bitのときのプレフィクス
66
16bit環境で32bitのmovするときのプレフィクス
	movw	(%ebx), %ax	# 67 8b 03
	movl	(%bx), %eax	# 66 8b 07
2e
CSセグメント使用するときのプレフィクス
8b
mem->reg の mov命令
84
ModR/Mバイトとかいうの
90
SIBとかいうの
c0d0e0f0
32bit値


と、ここまで書いて僕が理解できたのでいいや。(なんじゃそりゃ)
ModR/MとSIBについてはマニュアルを読もう!


0x8b の mov mem->reg 命令は、ほんとに、「mem->reg」の意味しかなくて、アドレスのフォーマットは何か、とか、どのレジスタを使うかとかは決まってないわけだ。そこで、その、アドレスのフォーマットと、どのレジスタを使うのか、が書いてあるのがModR/Mバイト。
ModR/Mのフォーマットは、

Mod R/M REG
76  543 210
movl	(%eax), %eax

こういうのだと、「%eaxが指してるメモリの値を%eaxにmov」で、ModR/Mは

Mod      REG R/M
00       000 000
モード00 EAX EAX

モード00がアレ。(マニュアル見て)
なので、

   0:	8b 00                	mov    (%eax),%eax

こう。アドレスが命令に埋まってる場合(disp32)

movl    0x12345678,%ecx

こういう場合は、ModR/Mが、

Mod      REG R/M
00       001 101
モード00 ECX disp32

こうなって、そんでdisp32が命令のあとに続くので、

   2:	8b 0d 78 56 34 12    	mov    0x12345678,%ecx

(今ここで、mov addr, eaxは別命令だということを知ったのだった)


んで。さらに、R/Mが100の場合、SIB(scale index base)で修飾できる。
いや…SIBがよくわからん…Base=101のときのはgasだとどう書けばいいんだ…あと、スケールの100はどう見ても使ってないのにESPがのけものにされてる件。いや、まあ、色々あるんだろうけど。


まあいいか。大体わかった。(僕しかわかってないだろうけど)

       OR r/m32,imm8                 ; o32 83 /1 ib         [386]

こういうのだと、83で、OR命令のsrc=imm8のdest=r/m32が指定されてて、imm8は命令でわかるので、ModR/MのREGの部分はいらん。(001になってるので/1これが100だと、ORじゃなくてAND)。ModとRegでr/m32が決まる。


理解してみれば一晩で理解できる内容だったな…もっとはやく勉強しとけばよかった。