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が決まる。
理解してみれば一晩で理解できる内容だったな…もっとはやく勉強しとけばよかった。