CODE blog (アンテナ) どころか tDiary で書くのも初めて、ってことで、練習を兼ねて。
x86, IA-32 というと 80386 互換プロセッサだと思って間違いない (?) んですが、 486 で追加された命令、Pentium 4 で追加された命令等々があって、 例えば Pentium 4 以降向けにコンパイルされたバイナリが、 より古いプロセッサでは動かなかったりするわけです。 こういった命令としては SIMD 命令、つまり MMX, SSE, SSE2 命令が有名ですが、 それ以外にもちょこちょことあります。
そういった命令にはどんなものがあったけな?というときに僕が見るのが、 binutils に入ってる i386.h。例えばこんな感じです。
binutils-2.16.1/include/opcode/i386.h:557-558
557: /* i386sl, i486sl, later 486, and Pentium. */
558: {"rsm", 0, 0x0faa, X, Cpu386, NoSuf, { 0, 0, 0} },
binutils-2.16.1/include/opcode/i386.h:894-901
894: /* 486 extensions. */
895:
896: {"bswap", 1, 0x0fc8, X, Cpu486, lq_Suf|ShortForm, { Reg32|Reg64, 0, 0 } },
897: {"xadd", 2, 0x0fc0, X, Cpu486, bwlq_Suf|W|Modrm, { Reg, Reg|AnyMem, 0 } },
898: {"cmpxchg", 2, 0x0fb0, X, Cpu486, bwlq_Suf|W|Modrm, { Reg, Reg|AnyMem, 0 } },
899: {"invd", 0, 0x0f08, X, Cpu486, NoSuf, { 0, 0, 0} },
900: {"wbinvd", 0, 0x0f09, X, Cpu486, NoSuf, { 0, 0, 0} },
901: {"invlpg", 1, 0x0f01, 7, Cpu486, NoSuf|Modrm|IgnoreSize, { AnyMem, 0, 0} },
bswap は、htonl(3)、ntohl(3) で使われてます。
cmpxchg (compare and exchange) はロック関係の実装に使われます。
binutils-2.16.1/include/opcode/i386.h:903-910
903: /* 586 and late 486 extensions. */
904: {"cpuid", 0, 0x0fa2, X, Cpu486, NoSuf, { 0, 0, 0} },
905:
906: /* Pentium extensions. */
907: {"wrmsr", 0, 0x0f30, X, Cpu586, NoSuf, { 0, 0, 0} },
908: {"rdtsc", 0, 0x0f31, X, Cpu586, NoSuf, { 0, 0, 0} },
909: {"rdmsr", 0, 0x0f32, X, Cpu586, NoSuf, { 0, 0, 0} },
910: {"cmpxchg8b",1,0x0fc7, 1, Cpu586, q_Suf|Modrm, { LLongMem, 0, 0} },
rdtsc は、1クロックあたり1だけ増やされるカウンタの値を取得できます。
つまり、クロック単位での時間計測に使えます。
akr さんが大好き (?) な命令です。
binutils-2.16.1/include/opcode/i386.h:912-980
912: /* Pentium II/Pentium Pro extensions. */
913: {"sysenter",0, 0x0f34, X, Cpu686, NoSuf, { 0, 0, 0} },
914: {"sysexit", 0, 0x0f35, X, Cpu686, NoSuf, { 0, 0, 0} },
915: {"fxsave", 1, 0x0fae, 0, Cpu686, q_Suf|Modrm, { LLongMem, 0, 0} },
916: {"fxrstor", 1, 0x0fae, 1, Cpu686, q_Suf|Modrm, { LLongMem, 0, 0} },
917: {"rdpmc", 0, 0x0f33, X, Cpu686, NoSuf, { 0, 0, 0} },
918: /* official undefined instr. */
919: {"ud2", 0, 0x0f0b, X, Cpu686, NoSuf, { 0, 0, 0} },
920: /* alias for ud2 */
921: {"ud2a", 0, 0x0f0b, X, Cpu686, NoSuf, { 0, 0, 0} },
922: /* 2nd. official undefined instr. */
923: {"ud2b", 0, 0x0fb9, X, Cpu686, NoSuf, { 0, 0, 0} },
924:
925: {"cmovo", 2, 0x0f40, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
926: {"cmovno", 2, 0x0f41, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
927: {"cmovb", 2, 0x0f42, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
928: {"cmovc", 2, 0x0f42, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
929: {"cmovnae", 2, 0x0f42, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
930: {"cmovae", 2, 0x0f43, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
931: {"cmovnc", 2, 0x0f43, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
932: {"cmovnb", 2, 0x0f43, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
933: {"cmove", 2, 0x0f44, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
934: {"cmovz", 2, 0x0f44, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
935: {"cmovne", 2, 0x0f45, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
936: {"cmovnz", 2, 0x0f45, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
937: {"cmovbe", 2, 0x0f46, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
938: {"cmovna", 2, 0x0f46, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
939: {"cmova", 2, 0x0f47, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
940: {"cmovnbe", 2, 0x0f47, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
941: {"cmovs", 2, 0x0f48, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
942: {"cmovns", 2, 0x0f49, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
943: {"cmovp", 2, 0x0f4a, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
944: {"cmovnp", 2, 0x0f4b, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
945: {"cmovl", 2, 0x0f4c, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
946: {"cmovnge", 2, 0x0f4c, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
947: {"cmovge", 2, 0x0f4d, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
948: {"cmovnl", 2, 0x0f4d, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
949: {"cmovle", 2, 0x0f4e, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
950: {"cmovng", 2, 0x0f4e, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
951: {"cmovg", 2, 0x0f4f, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
952: {"cmovnle", 2, 0x0f4f, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} },
953:
954: {"fcmovb", 2, 0xdac0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
955: {"fcmovnae",2, 0xdac0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
956: {"fcmove", 2, 0xdac8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
957: {"fcmovbe", 2, 0xdad0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
958: {"fcmovna", 2, 0xdad0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
959: {"fcmovu", 2, 0xdad8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
960: {"fcmovae", 2, 0xdbc0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
961: {"fcmovnb", 2, 0xdbc0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
962: {"fcmovne", 2, 0xdbc8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
963: {"fcmova", 2, 0xdbd0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
964: {"fcmovnbe",2, 0xdbd0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
965: {"fcmovnu", 2, 0xdbd8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
966:
967: {"fcomi", 2, 0xdbf0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
968: {"fcomi", 0, 0xdbf1, X, Cpu686, FP|ShortForm, { 0, 0, 0} },
969: {"fcomi", 1, 0xdbf0, X, Cpu686, FP|ShortForm, { FloatReg, 0, 0} },
970: {"fucomi", 2, 0xdbe8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
971: {"fucomi", 0, 0xdbe9, X, Cpu686, FP|ShortForm, { 0, 0, 0} },
972: {"fucomi", 1, 0xdbe8, X, Cpu686, FP|ShortForm, { FloatReg, 0, 0} },
973: {"fcomip", 2, 0xdff0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
974: {"fcompi", 2, 0xdff0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
975: {"fcompi", 0, 0xdff1, X, Cpu686, FP|ShortForm, { 0, 0, 0} },
976: {"fcompi", 1, 0xdff0, X, Cpu686, FP|ShortForm, { FloatReg, 0, 0} },
977: {"fucomip", 2, 0xdfe8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
978: {"fucompi", 2, 0xdfe8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} },
979: {"fucompi", 0, 0xdfe9, X, Cpu686, FP|ShortForm, { 0, 0, 0} },
980: {"fucompi", 1, 0xdfe8, X, Cpu686, FP|ShortForm, { FloatReg, 0, 0} },
sysenter/sysexit
は、システムコール呼び出しを高速化するために用意された命令です。
cmov*, fcmov* は、条件付 move 命令です。
binutils-2.16.1/include/opcode/i386.h:982-988
982: /* Pentium4 extensions. */
983:
984: {"movnti", 2, 0x0fc3, X, CpuP4, wlq_Suf|Modrm, { WordReg, WordMem, 0 } },
985: {"clflush", 1, 0x0fae, 7, CpuP4, NoSuf|Modrm|IgnoreSize, { ByteMem, 0, 0 } },
986: {"lfence", 0, 0x0fae, 0xe8, CpuP4, NoSuf|ImmExt, { 0, 0, 0 } },
987: {"mfence", 0, 0x0fae, 0xf0, CpuP4, NoSuf|ImmExt, { 0, 0, 0 } },
988: {"pause", 0, 0xf390, X, CpuP4, NoSuf, { 0, 0, 0 } },
binutils-2.16.1/include/opcode/i386.h:1374-1384
1374: /* VIA PadLock extensions. */
1375: {"xstorerng", 0, 0x000fa7c0, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
1376: {"xcryptecb", 0, 0xf30fa7c8, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
1377: {"xcryptcbc", 0, 0xf30fa7d0, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
1378: {"xcryptcfb", 0, 0xf30fa7e0, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
1379: {"xcryptofb", 0, 0xf30fa7e8, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
1380: {"montmul", 0, 0xf30fa6c0, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
1381: {"xsha1", 0, 0xf30fa6c8, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
1382: {"xsha256", 0, 0xf30fa6d0, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },
1383: /* Alias for xstorerng. */
1384: {"xstore", 0, 0x000fa7c0, X, Cpu686|CpuPadLock, NoSuf|IsString, { 0, 0, 0} },