全 x86 プロセッサにあるわけではない命令

首藤 一幸

2006年 7月 23日


Back to


CODE blog (アンテナ) どころか tDiary で書くのも初めて、ってことで、練習を兼ねて。

x86, IA-32 というと 80386 互換プロセッサだと思って間違いない (?) んですが、 486 で追加された命令、Pentium 4 で追加された命令等々があって、 例えば Pentium 4 以降向けにコンパイルされたバイナリが、 より古いプロセッサでは動かなかったりするわけです。 こういった命令としては SIMD 命令、つまり MMX, SSE, SSE2 命令が有名ですが、 それ以外にもちょこちょことあります。

そういった命令にはどんなものがあったけな?というときに僕が見るのが、 binutils に入ってる i386.h。例えばこんな感じです。

386SL, 486SL, 後期の486, Pentium 以降で追加された命令群

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} },

486 で追加された命令群

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) はロック関係の実装に使われます。

Pentium で追加された命令群

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 さんが大好き (?) な命令です。

Pentium Pro で追加された命令群

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 命令です。

Pentium 4 で追加された命令群

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 } },

VIA のセキュリティ向け拡張命令 (日記2003年10/16分)

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} },