エンディアンの話
mov dword[eax+0x08],0x1234
アセンブル結果
c7 40 08 34 12 00 00
機械語解読のためにはオペコードのフォーマットに関する知識が必要で、詳しくはインテルのマニュアル参照ですが簡単にまとめると
prefix(1-4byte) opcode(1-3byte) ModR/M(1byte) SIB(1Byte) displacement(1,2,4byte) imm(1,2,4byte)
となります。伊達にCISCと呼ばれてないだけあります。絶対に必要なのはopcodeで、後は命令によってあったりなかったりです。
今回の場合はprefixはなく、c7がopcodeでレジスタorメモリに32bitの即値を転送する命令を示します。
実際にどこへ転送するかということは命令の次のバイトである ModR/M で指定されます。ModR/M の構造は次のようになっています。
Mod(2bit) Reg/Opcode(3bit) R/M(3bit)
このフィールドの解釈は複雑なのでマニュアル参照..ですがとりあえず Mod と R/M 合わせて5bitでレジスタやアドレス指定のモードを構成します。今回の場合は Mod と R/M は 01 000 で、これは[eax + disp8]を示します。つまりこの次に8bitのディスプレースメントが来ることになります。Reg/Opcodeのフィールドはオペランド拡張になっています。マニュアルをみると"オペコード c7/0"と書いてありますがこの/0が拡張オペコードです。
さて、ということで ModR/M の次は SIB はなくて8bitのディスプーレスメントになります。当然これは0x08です。そして次が4byteの即値で0x1234ですが、リトルエンディアンなので "00 00 12 34" ではなく "34 12 00 00"となっています。
・mipsの場合
add $1,$0,0x1234
mipsの場合はエンディアンを切り替えることができます。gasの場合は引数に-EBか-ELをつけることでエンディアンを指定できます(デフォルトはビッグエンディアン)。
ビッグエンディアンの場合
20 01 12 34
リトルエンディアンの場合
34 12 01 20
mipsのadd命令はI形式というフォーマットに分類されます。I形式の場合、
opcode(6bits) rs(5bits) rt(5bits) imm(16bits)
となります。つまり、今回の場合、
opcode: 001000 (add)
rs: 00000 ($0)
rt: 00001 ($1)
imm: 0x1234
となります。ということで命令は0x20011234ですが、ビッグエンディアンの場合は "20 01 12 34"、リトルエンディアンの場合は"34 12 01 20"となります。
エンディアンの話をするとき、機械語的にはどうなってるのか、と思ったので実際に調べてみましたが、x86の場合は命令自体は1byteごとに解釈をおこなっていくので、あくまで4byteのディスプレースメントや即値がリトルエンディアンとして逆向きに格納されます。一方mipsの場合は必ず1命令4byte固定なので、各命令はエンディアンに従って格納されます。結局のところ複数バイトで扱う場合にエンディアンが効いてくるということですね(って当たり前か