metasm 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.hgtags +3 -0
  4. data/Gemfile +1 -0
  5. data/INSTALL +61 -0
  6. data/LICENCE +458 -0
  7. data/README +29 -21
  8. data/Rakefile +10 -0
  9. data/TODO +10 -12
  10. data/doc/code_organisation.txt +2 -0
  11. data/doc/core/DynLdr.txt +247 -0
  12. data/doc/core/ExeFormat.txt +43 -0
  13. data/doc/core/Expression.txt +220 -0
  14. data/doc/core/GNUExports.txt +27 -0
  15. data/doc/core/Ia32.txt +236 -0
  16. data/doc/core/SerialStruct.txt +108 -0
  17. data/doc/core/VirtualString.txt +145 -0
  18. data/doc/core/WindowsExports.txt +61 -0
  19. data/doc/core/index.txt +1 -0
  20. data/doc/style.css +6 -3
  21. data/doc/usage/debugger.txt +327 -0
  22. data/doc/usage/index.txt +1 -0
  23. data/doc/use_cases.txt +2 -2
  24. data/metasm.gemspec +22 -0
  25. data/{lib/metasm.rb → metasm.rb} +11 -3
  26. data/{lib/metasm → metasm}/compile_c.rb +13 -7
  27. data/metasm/cpu/arc.rb +8 -0
  28. data/metasm/cpu/arc/decode.rb +425 -0
  29. data/metasm/cpu/arc/main.rb +191 -0
  30. data/metasm/cpu/arc/opcodes.rb +588 -0
  31. data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
  32. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  33. data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
  34. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  35. data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
  36. data/metasm/cpu/arm/opcodes.rb +324 -0
  37. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  38. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  39. data/metasm/cpu/arm64.rb +15 -0
  40. data/metasm/cpu/arm64/debug.rb +38 -0
  41. data/metasm/cpu/arm64/decode.rb +289 -0
  42. data/metasm/cpu/arm64/encode.rb +41 -0
  43. data/metasm/cpu/arm64/main.rb +105 -0
  44. data/metasm/cpu/arm64/opcodes.rb +232 -0
  45. data/metasm/cpu/arm64/parse.rb +20 -0
  46. data/metasm/cpu/arm64/render.rb +95 -0
  47. data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
  48. data/metasm/cpu/bpf/decode.rb +142 -0
  49. data/metasm/cpu/bpf/main.rb +60 -0
  50. data/metasm/cpu/bpf/opcodes.rb +81 -0
  51. data/metasm/cpu/bpf/render.rb +41 -0
  52. data/metasm/cpu/cy16.rb +9 -0
  53. data/metasm/cpu/cy16/decode.rb +253 -0
  54. data/metasm/cpu/cy16/main.rb +63 -0
  55. data/metasm/cpu/cy16/opcodes.rb +78 -0
  56. data/metasm/cpu/cy16/render.rb +41 -0
  57. data/metasm/cpu/dalvik.rb +11 -0
  58. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
  59. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
  60. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
  61. data/metasm/cpu/ia32.rb +17 -0
  62. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
  63. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
  64. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
  65. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
  66. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  67. data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
  68. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  69. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
  70. data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
  71. data/metasm/cpu/mips.rb +14 -0
  72. data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
  73. data/metasm/cpu/mips/debug.rb +42 -0
  74. data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
  75. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  76. data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
  77. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
  78. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  79. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  80. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  81. data/metasm/cpu/msp430/decode.rb +247 -0
  82. data/metasm/cpu/msp430/main.rb +62 -0
  83. data/metasm/cpu/msp430/opcodes.rb +101 -0
  84. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  85. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  86. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  87. data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
  88. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
  89. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  90. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  91. data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
  92. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
  93. data/metasm/cpu/ppc/parse.rb +55 -0
  94. data/metasm/cpu/python.rb +8 -0
  95. data/metasm/cpu/python/decode.rb +136 -0
  96. data/metasm/cpu/python/main.rb +36 -0
  97. data/metasm/cpu/python/opcodes.rb +180 -0
  98. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  99. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
  100. data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
  101. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  102. data/metasm/cpu/x86_64.rb +15 -0
  103. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
  104. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  105. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
  106. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
  107. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
  108. data/metasm/cpu/x86_64/opcodes.rb +136 -0
  109. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
  110. data/metasm/cpu/x86_64/render.rb +35 -0
  111. data/metasm/cpu/z80.rb +9 -0
  112. data/metasm/cpu/z80/decode.rb +313 -0
  113. data/metasm/cpu/z80/main.rb +67 -0
  114. data/metasm/cpu/z80/opcodes.rb +224 -0
  115. data/metasm/cpu/z80/render.rb +59 -0
  116. data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
  117. data/{lib/metasm → metasm}/decode.rb +35 -4
  118. data/{lib/metasm → metasm}/decompile.rb +15 -16
  119. data/{lib/metasm → metasm}/disassemble.rb +201 -45
  120. data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
  121. data/{lib/metasm → metasm}/dynldr.rb +220 -133
  122. data/{lib/metasm → metasm}/encode.rb +10 -1
  123. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  124. data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
  125. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  126. data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
  127. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
  128. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
  129. data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
  130. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  131. data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
  132. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
  133. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
  134. data/metasm/exe_format/gb.rb +65 -0
  135. data/metasm/exe_format/javaclass.rb +424 -0
  136. data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
  137. data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
  138. data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
  139. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  140. data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
  141. data/metasm/exe_format/pyc.rb +167 -0
  142. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  143. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  144. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  145. data/metasm/exe_format/swf.rb +205 -0
  146. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  147. data/metasm/exe_format/zip.rb +335 -0
  148. data/metasm/gui.rb +13 -0
  149. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  150. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  151. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
  152. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  153. data/metasm/gui/dasm_graph.rb +1695 -0
  154. data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
  155. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  156. data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
  157. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  158. data/{lib/metasm → metasm}/gui/debug.rb +93 -27
  159. data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
  160. data/{lib/metasm → metasm}/gui/qt.rb +12 -2
  161. data/{lib/metasm → metasm}/gui/win32.rb +179 -42
  162. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  163. data/{lib/metasm → metasm}/main.rb +389 -264
  164. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  165. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  166. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  167. data/metasm/os/main.rb +330 -0
  168. data/{lib/metasm → metasm}/os/windows.rb +132 -42
  169. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  170. data/{lib/metasm → metasm}/parse.rb +26 -24
  171. data/{lib/metasm → metasm}/parse_c.rb +221 -116
  172. data/{lib/metasm → metasm}/preprocessor.rb +55 -40
  173. data/{lib/metasm → metasm}/render.rb +14 -38
  174. data/misc/hexdump.rb +2 -1
  175. data/misc/lint.rb +58 -0
  176. data/misc/txt2html.rb +9 -7
  177. data/samples/bindiff.rb +3 -4
  178. data/samples/dasm-plugins/bindiff.rb +15 -0
  179. data/samples/dasm-plugins/bookmark.rb +133 -0
  180. data/samples/dasm-plugins/c_constants.rb +57 -0
  181. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  182. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  183. data/samples/dasm-plugins/dasm_all.rb +70 -0
  184. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  185. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  186. data/samples/dasm-plugins/dump_text.rb +35 -0
  187. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  188. data/samples/dasm-plugins/findgadget.rb +75 -0
  189. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  190. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  191. data/samples/dasm-plugins/imm2off.rb +34 -0
  192. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  193. data/samples/dasm-plugins/patch_file.rb +95 -0
  194. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  195. data/samples/dasm-plugins/scanxrefs.rb +26 -0
  196. data/samples/dasm-plugins/selfmodify.rb +197 -0
  197. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  198. data/samples/dasmnavig.rb +1 -1
  199. data/samples/dbg-apihook.rb +24 -9
  200. data/samples/dbg-plugins/heapscan.rb +283 -0
  201. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  202. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  203. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  204. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  205. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  206. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  207. data/samples/dbg-plugins/trace_func.rb +214 -0
  208. data/samples/disassemble-gui.rb +35 -5
  209. data/samples/disassemble.rb +31 -6
  210. data/samples/dump_upx.rb +24 -12
  211. data/samples/dynamic_ruby.rb +12 -3
  212. data/samples/exeencode.rb +6 -5
  213. data/samples/factorize-headers-peimports.rb +1 -1
  214. data/samples/lindebug.rb +175 -381
  215. data/samples/metasm-shell.rb +1 -2
  216. data/samples/peldr.rb +2 -2
  217. data/tests/all.rb +1 -1
  218. data/tests/arc.rb +26 -0
  219. data/tests/dynldr.rb +22 -4
  220. data/tests/expression.rb +55 -0
  221. data/tests/graph_layout.rb +285 -0
  222. data/tests/ia32.rb +79 -26
  223. data/tests/mips.rb +9 -2
  224. data/tests/x86_64.rb +66 -18
  225. metadata +330 -218
  226. data/lib/metasm/arm/opcodes.rb +0 -177
  227. data/lib/metasm/gui.rb +0 -23
  228. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  229. data/lib/metasm/ia32.rb +0 -14
  230. data/lib/metasm/ia32/opcodes.rb +0 -873
  231. data/lib/metasm/ppc/parse.rb +0 -52
  232. data/lib/metasm/x86_64.rb +0 -12
  233. data/lib/metasm/x86_64/opcodes.rb +0 -118
  234. data/samples/gdbclient.rb +0 -583
  235. data/samples/rubstop.rb +0 -399
@@ -4,7 +4,7 @@
4
4
  # Licence is LGPL, see LICENCE in the top-level directory
5
5
 
6
6
 
7
- require 'metasm/ia32/main'
7
+ require 'metasm/cpu/ia32/main'
8
8
 
9
9
  module Metasm
10
10
  class Ia32
@@ -52,7 +52,7 @@ class Ia32
52
52
  # returns { blockaddr => [list of vars that are needed by a following block] }
53
53
  def decompile_func_finddeps(dcmp, blocks, func)
54
54
  deps_r = {} ; deps_w = {} ; deps_to = {}
55
- deps_subfunc = {} # things read/written by subfuncs
55
+ deps_subfunc = {} # things read/written by subfuncs
56
56
 
57
57
  # find read/writes by each block
58
58
  blocks.each { |b, to|
@@ -70,7 +70,7 @@ class Ia32
70
70
  end
71
71
  }
72
72
  a << :eax if di.opcode.name == 'ret' and (not func.type.kind_of? C::BaseType or func.type.type.name != :void) # standard ABI
73
-
73
+
74
74
  deps_r[b] |= a.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] - deps_w[b]
75
75
  deps_w[b] |= w.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown]
76
76
  }
@@ -121,7 +121,7 @@ class Ia32
121
121
  end
122
122
  }
123
123
  a << :eax if di.opcode.name == 'ret' and (not func.type.kind_of? C::BaseType or func.type.type.name != :void) # standard ABI
124
-
124
+
125
125
  next true if (a.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown] - bw).include? r
126
126
  bw |= w.map { |ee| Expression[ee].externals.grep(::Symbol) }.flatten - [:unknown]
127
127
  false
@@ -369,7 +369,7 @@ class Ia32
369
369
  # to.delete addr
370
370
  # next if not l = dcmp.dasm.get_label_at(addr)
371
371
  # sw.body.statements << C::Goto.new(l)
372
- # }
372
+ # }
373
373
  # stmts << sw
374
374
  a = di.instruction.args.first
375
375
  if a.kind_of? Expression
@@ -512,9 +512,9 @@ class Ia32
512
512
  dcmp.dasm.decoded[b_].block.list.each { |di|
513
513
  di.backtrace_binding = nil
514
514
  }
515
- }
515
+ }
516
516
  end
517
-
517
+
518
518
  def decompile_check_abi(dcmp, entry, func)
519
519
  a = func.type.args || []
520
520
  a.delete_if { |arg| arg.has_attribute_var('register') and arg.has_attribute('unused') }
@@ -4,7 +4,7 @@
4
4
  # Licence is LGPL, see LICENCE in the top-level directory
5
5
 
6
6
 
7
- require 'metasm/ia32/opcodes'
7
+ require 'metasm/cpu/ia32/opcodes'
8
8
  require 'metasm/encode'
9
9
 
10
10
  module Metasm
@@ -195,27 +195,28 @@ class Ia32
195
195
  case k
196
196
  when :jmp; {:jmp => 0x3e, :nojmp => 0x2e}[v]
197
197
  when :lock; 0xf0
198
- when :rep; {'repnz' => 0xf2, 'repz' => 0xf3, 'rep' => 0xf2}[v] # TODO
198
+ when :rep; {'repnz' => 0xf2, 'repz' => 0xf3, 'rep' => 0xf2}[v]
199
+ when :jmphint; {'hintjmp' => 0x3e, 'hintnojmp' => 0x2e}[v]
200
+ when :seg; [0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65][v.val]
199
201
  end
200
202
  }.compact.pack 'C*'
201
- pfx << op.props[:needpfx] if op.props[:needpfx]
202
203
 
203
204
  if op.name == 'movsx' or op.name == 'movzx'
204
205
  pfx << 0x66 if size == 48-i.args[0].sz
206
+ elsif op.name == 'crc32'
207
+ pfx << 0x66 if size == 48-i.args[1].sz
205
208
  else
206
209
  opsz = op.props[:argsz]
207
210
  oi.each { |oa, ia|
208
211
  case oa
209
- when :reg, :reg_eax, :modrm, :modrmA, :mrm_imm
212
+ when :reg, :reg_eax, :modrm, :mrm_imm
210
213
  raise EncodeError, "Incompatible arg size in #{i}" if ia.sz and opsz and opsz != ia.sz
211
214
  opsz = ia.sz
212
215
  end
213
216
  }
214
- pfx << 0x66 if (not op.props[:argsz] or opsz != op.props[:argsz]) and (
215
- (opsz and size == 48 - opsz) or (op.props[:opsz] and op.props[:opsz] != size))
216
- if op.props[:opsz] and size == 48 - op.props[:opsz]
217
- opsz = op.props[:opsz]
218
- end
217
+ pfx << 0x66 if (op.props[:opsz] and size == 48 - op.props[:opsz]) or
218
+ (not op.props[:argsz] and opsz and size == 48 - opsz)
219
+ opsz ||= op.props[:opsz]
219
220
  end
220
221
  opsz ||= size
221
222
 
@@ -226,7 +227,7 @@ class Ia32
226
227
  adsz ||= size
227
228
  # addrsize override / segment override
228
229
  if mrm = i.args.grep(ModRM).first
229
- if not op.props[:adsz] and ((mrm.b and mrm.b.sz != adsz) or (mrm.i and mrm.i.sz != adsz))
230
+ if not op.props[:adsz] and ((mrm.b and mrm.b.sz == 48 - adsz) or (mrm.i and mrm.i.sz == 48 - adsz))
230
231
  pfx << 0x67
231
232
  adsz = 48 - adsz
232
233
  end
@@ -240,10 +241,12 @@ class Ia32
240
241
  postponed = []
241
242
  oi.each { |oa, ia|
242
243
  case oa
243
- when :reg, :seg3, :seg3A, :seg2, :seg2A, :eeec, :eeed, :eeet, :regfp, :regmmx, :regxmm
244
+ when :reg, :seg3, :seg3A, :seg2, :seg2A, :eeec, :eeed, :eeet, :regfp, :regmmx, :regxmm, :regymm
244
245
  # field arg
245
246
  set_field[oa, ia.val]
246
247
  pfx << 0x66 if oa == :regmmx and op.props[:xmmx] and ia.sz == 128
248
+ when :vexvreg, :vexvxmm, :vexvymm
249
+ set_field[:vex_vvvv, ia.val ^ 0xf]
247
250
  when :imm_val1, :imm_val3, :reg_cl, :reg_eax, :reg_dx, :regfp0
248
251
  # implicit
249
252
  else
@@ -251,7 +254,7 @@ class Ia32
251
254
  end
252
255
  }
253
256
 
254
- if !(op.args & [:modrm, :modrmA, :modrmxmm, :modrmmmx]).empty?
257
+ if !(op.args & [:modrm, :modrmmmx, :modrmxmm, :modrmymm]).empty?
255
258
  # reg field of modrm
256
259
  regval = (base[-1] >> 3) & 7
257
260
  base.pop
@@ -265,6 +268,8 @@ class Ia32
265
268
  postponed.first[1] = Expression[target, :-, postlabel]
266
269
  end
267
270
 
271
+ pfx << op.props[:needpfx] if op.props[:needpfx]
272
+
268
273
  #
269
274
  # append other arguments
270
275
  #
@@ -273,7 +278,7 @@ class Ia32
273
278
  postponed.each { |oa, ia|
274
279
  case oa
275
280
  when :farptr; ed = ia.encode(@endianness, "a#{opsz}".to_sym)
276
- when :modrm, :modrmA, :modrmmmx, :modrmxmm
281
+ when :modrm, :modrmmmx, :modrmxmm, :modrmymm
277
282
  if ia.kind_of? ModRM
278
283
  ed = ia.encode(regval, @endianness)
279
284
  if ed.kind_of?(::Array)
@@ -295,6 +300,7 @@ class Ia32
295
300
  when :mrm_imm; ed = ia.imm.encode("a#{adsz}".to_sym, @endianness)
296
301
  when :i8, :u8, :u16; ed = ia.encode(oa, @endianness)
297
302
  when :i; ed = ia.encode("a#{opsz}".to_sym, @endianness)
303
+ when :i4xmm, :i4ymm; ed = ia.val << 4 # u8
298
304
  else raise SyntaxError, "Internal error: want to encode field #{oa.inspect} as arg in #{i}"
299
305
  end
300
306
 
@@ -34,6 +34,10 @@ class Ia32 < CPU
34
34
  @val = v
35
35
  end
36
36
 
37
+ def ==(o)
38
+ self.class == o.class and val == o.val
39
+ end
40
+
37
41
  def self.from_str(s) new(@s_to_i[s]) end
38
42
  }
39
43
  end
@@ -53,13 +57,16 @@ class Ia32 < CPU
53
57
  @sz = sz
54
58
  end
55
59
 
60
+ def ==(o)
61
+ self.class == o.class and val == o.val and sz == o.sz
62
+ end
63
+
56
64
  def self.from_str(s)
57
65
  raise "Bad #{name} #{s.inspect}" if not x = @s_to_i[s]
58
66
  new(*x)
59
67
  end
60
68
  }
61
69
  end
62
-
63
70
  end
64
71
 
65
72
 
@@ -88,10 +95,11 @@ class Ia32 < CPU
88
95
  simple_map((0..7).map { |i| [i, "ST(#{i})"] } << [nil, 'ST'])
89
96
  end
90
97
 
91
- # a single operation multiple data register (mm0..mm7, xmm0..xmm7)
98
+ # Single Instr Multiple Data register (mm0..mm7, xmm0..xmm7, ymm0..ymm7)
92
99
  class SimdReg < Argument
93
100
  double_map 64 => (0..7).map { |n| "mm#{n}" },
94
- 128 => (0..7).map { |n| "xmm#{n}" }
101
+ 128 => (0..7).map { |n| "xmm#{n}" },
102
+ 256 => (0..7).map { |n| "ymm#{n}" }
95
103
  def symbolic(di=nil) ; to_s.to_sym end
96
104
  end
97
105
 
@@ -133,12 +141,16 @@ class Ia32 < CPU
133
141
  def initialize(seg, addr)
134
142
  @seg, @addr = seg, addr
135
143
  end
144
+
145
+ def ==(o)
146
+ self.class == o.class and seg == o.seg and addr == o.addr
147
+ end
136
148
  end
137
149
 
138
150
  # ModRM represents indirections in x86 (eg dword ptr [eax+4*ebx+12h])
139
151
  class ModRM < Argument
140
152
  # valid combinaisons for a modrm
141
- # ints are reg indexes, symbols are immediates, except :sib
153
+ # ints are reg indexes, symbols are immediates, except :sib
142
154
  Sum = {
143
155
  16 => {
144
156
  0 => [ [3, 6], [3, 7], [5, 6], [5, 7], [6], [7], [:i16], [3] ],
@@ -180,6 +192,10 @@ class Ia32 < CPU
180
192
  p = Expression["segment_base_#@seg", :+, p] if seg and seg.val != ((b && (@b.val == 4 || @b.val == 5)) ? 2 : 3)
181
193
  Indirection[p.reduce, @sz/8, (di.address if di)]
182
194
  end
195
+
196
+ def ==(o)
197
+ self.class == o.class and s == o.s and i == o.i and b == o.b and imm == o.imm and seg == o.seg and adsz == o.adsz and sz == o.sz
198
+ end
183
199
  end
184
200
 
185
201
 
@@ -222,17 +238,44 @@ class Ia32 < CPU
222
238
  pp.define_weak('__i386__')
223
239
  end
224
240
 
225
- # returns a Reg object if the arg is a valid register (eg 'ax' => Reg.new(0, 16))
241
+ # returns a Reg/SimdReg object if the arg is a valid register (eg 'ax' => Reg.new(0, 16))
226
242
  # returns nil if str is invalid
227
243
  def str_to_reg(str)
228
- Reg.from_str(str) if Reg.s_to_i.has_key? str
244
+ Reg.s_to_i.has_key?(str) ? Reg.from_str(str) : SimdReg.s_to_i.has_key?(str) ? SimdReg.from_str(str) : nil
245
+ end
246
+
247
+ # returns the list of Regs in the instruction arguments
248
+ # may be converted into symbols through Reg#symbolic
249
+ def instr_args_regs(i)
250
+ i = i.instruction if i.kind_of?(DecodedInstruction)
251
+ i.args.grep(Reg)
252
+ end
253
+
254
+ # returns the list of ModRMs in the instruction arguments
255
+ # may be converted into Indirection through ModRM#symbolic
256
+ def instr_args_memoryptr(i)
257
+ i = i.instruction if i.kind_of?(DecodedInstruction)
258
+ i.args.grep(ModRM)
259
+ end
260
+
261
+ # return the 'base' of the ModRM (Reg/nil)
262
+ def instr_args_memoryptr_getbase(mrm)
263
+ mrm.b || (mrm.i if mrm.s == 1)
264
+ end
265
+
266
+ # return the offset of the ModRM (Expression/nil)
267
+ def instr_args_memoryptr_getoffset(mrm)
268
+ mrm.imm
269
+ end
270
+
271
+ # define ModRM offset (eg to changing imm into an ExpressionString)
272
+ def instr_args_memoryptr_setoffset(mrm, imm)
273
+ mrm.imm = (imm ? Expression[imm] : imm)
229
274
  end
230
275
 
231
276
  def shortname
232
277
  "ia32#{'_16' if @size == 16}#{'_be' if @endianness == :big}"
233
278
  end
234
279
  end
235
-
236
280
  X86 = Ia32
237
-
238
281
  end
@@ -0,0 +1,1424 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+
7
+ require 'metasm/cpu/ia32/main'
8
+
9
+ module Metasm
10
+ class Ia32
11
+ def init_cpu_constants
12
+ @opcode_list ||= []
13
+ @fields_mask.update :w => 1, :s => 1, :d => 1, :modrm => 0xC7,
14
+ :reg => 7, :eeec => 7, :eeed => 7, :eeet => 7, :seg2 => 3, :seg3 => 7,
15
+ :regfp => 7, :regmmx => 7, :regxmm => 7, :regymm => 7,
16
+ :vex_r => 1, :vex_b => 1, :vex_x => 1, :vex_w => 1,
17
+ :vex_vvvv => 0xF
18
+ @fields_mask[:seg2A] = @fields_mask[:seg2]
19
+ @fields_mask[:seg3A] = @fields_mask[:seg3]
20
+
21
+ [:i, :i8, :u8, :u16, :reg, :seg2, :seg2A,
22
+ :seg3, :seg3A, :eeec, :eeed, :eeet, :modrm, :mrm_imm,
23
+ :farptr, :imm_val1, :imm_val3, :reg_cl, :reg_eax,
24
+ :reg_dx, :regfp, :regfp0, :modrmmmx, :regmmx,
25
+ :modrmxmm, :regxmm, :modrmymm, :regymm,
26
+ :vexvxmm, :vexvymm, :vexvreg, :i4xmm, :i4ymm
27
+ ].each { |a| @valid_args[a] = true }
28
+
29
+ [:strop, :stropz, :opsz, :adsz, :argsz, :setip,
30
+ :stopexec, :saveip, :unsigned_imm, :random, :needpfx,
31
+ :xmmx, :modrmR, :modrmA, :mrmvex
32
+ ].each { |a| @valid_props[a] = true }
33
+ end
34
+
35
+ # only most common instructions from the 386 instruction set
36
+ # inexhaustive list :
37
+ # no aaa, arpl, mov crX, call/jmp/ret far, in/out, bts, xchg...
38
+ def init_386_common_only
39
+ init_cpu_constants
40
+
41
+ addop_macro1 'adc', 2
42
+ addop_macro1 'add', 0
43
+ addop_macro1 'and', 4, :unsigned_imm
44
+ addop 'bswap', [0x0F, 0xC8], :reg
45
+ addop 'call', [0xE8], nil, :stopexec, :setip, :i, :saveip
46
+ addop 'call', [0xFF], 2, :stopexec, :setip, :saveip
47
+ addop('cbw', [0x98]) { |o| o.props[:opsz] = 16 }
48
+ addop('cwde', [0x98]) { |o| o.props[:opsz] = 32 }
49
+ addop('cwd', [0x99]) { |o| o.props[:opsz] = 16 }
50
+ addop('cdq', [0x99]) { |o| o.props[:opsz] = 32 }
51
+ addop_macro1 'cmp', 7
52
+ addop_macrostr 'cmps', [0xA6], :stropz
53
+ addop 'dec', [0x48], :reg
54
+ addop 'dec', [0xFE], 1, {:w => [0, 0]}
55
+ addop 'div', [0xF6], 6, {:w => [0, 0]}
56
+ addop 'enter', [0xC8], nil, :u16, :u8
57
+ addop 'idiv', [0xF6], 7, {:w => [0, 0]}
58
+ addop 'imul', [0xF6], 5, {:w => [0, 0]} # implicit eax, but different semantic from imul eax, ebx (the implicit version updates edx:eax)
59
+ addop 'imul', [0x0F, 0xAF], :mrm
60
+ addop 'imul', [0x69], :mrm, {:s => [0, 1]}, :i
61
+ addop 'inc', [0x40], :reg
62
+ addop 'inc', [0xFE], 0, {:w => [0, 0]}
63
+ addop 'int', [0xCC], nil, :imm_val3, :stopexec
64
+ addop 'int', [0xCD], nil, :u8
65
+ addop_macrotttn 'j', [0x70], nil, :setip, :i8
66
+ addop_macrotttn('j', [0x70], nil, :setip, :i8) { |o| o.name << '.i8' }
67
+ addop_macrotttn 'j', [0x0F, 0x80], nil, :setip, :i
68
+ addop_macrotttn('j', [0x0F, 0x80], nil, :setip, :i) { |o| o.name << '.i' }
69
+ addop 'jmp', [0xE9], nil, {:s => [0, 1]}, :setip, :i, :stopexec
70
+ addop 'jmp', [0xFF], 4, :setip, :stopexec
71
+ addop 'lea', [0x8D], :mrmA
72
+ addop 'leave', [0xC9]
73
+ addop_macrostr 'lods', [0xAC], :strop
74
+ addop 'loop', [0xE2], nil, :setip, :i8
75
+ addop 'loopz', [0xE1], nil, :setip, :i8
76
+ addop 'loope', [0xE1], nil, :setip, :i8
77
+ addop 'loopnz',[0xE0], nil, :setip, :i8
78
+ addop 'loopne',[0xE0], nil, :setip, :i8
79
+ addop 'mov', [0xA0], nil, {:w => [0, 0], :d => [0, 1]}, :reg_eax, :mrm_imm
80
+ addop('mov', [0x88], :mrmw,{:d => [0, 1]}) { |o| o.args.reverse! }
81
+ addop 'mov', [0xB0], :reg, {:w => [0, 3]}, :i, :unsigned_imm
82
+ addop 'mov', [0xC6], 0, {:w => [0, 0]}, :i, :unsigned_imm
83
+ addop_macrostr 'movs', [0xA4], :strop
84
+ addop 'movsx', [0x0F, 0xBE], :mrmw
85
+ addop 'movzx', [0x0F, 0xB6], :mrmw
86
+ addop 'mul', [0xF6], 4, {:w => [0, 0]}
87
+ addop 'neg', [0xF6], 3, {:w => [0, 0]}
88
+ addop 'nop', [0x90]
89
+ addop 'not', [0xF6], 2, {:w => [0, 0]}
90
+ addop_macro1 'or', 1, :unsigned_imm
91
+ addop 'pop', [0x58], :reg
92
+ addop 'pop', [0x8F], 0
93
+ addop 'push', [0x50], :reg
94
+ addop 'push', [0xFF], 6
95
+ addop 'push', [0x68], nil, {:s => [0, 1]}, :i, :unsigned_imm
96
+ addop 'ret', [0xC3], nil, :stopexec, :setip
97
+ addop 'ret', [0xC2], nil, :stopexec, :u16, :setip
98
+ addop_macro3 'rol', 0
99
+ addop_macro3 'ror', 1
100
+ addop_macro3 'sar', 7
101
+ addop_macro1 'sbb', 3
102
+ addop_macrostr 'scas', [0xAE], :stropz
103
+ addop_macrotttn('set', [0x0F, 0x90], 0) { |o| o.props[:argsz] = 8 }
104
+ addop_macrotttn('set', [0x0F, 0x90], :mrm) { |o| o.props[:argsz] = 8 ; o.args.reverse! } # :reg field is unused
105
+ addop_macro3 'shl', 4
106
+ addop_macro3 'sal', 6
107
+ addop('shld', [0x0F, 0xA4], :mrm, :u8) { |o| o.args[0], o.args[1] = o.args[1], o.args[0] }
108
+ addop('shld', [0x0F, 0xA5], :mrm, :reg_cl) { |o| o.args[0], o.args[1] = o.args[1], o.args[0] }
109
+ addop_macro3 'shr', 5
110
+ addop('shrd', [0x0F, 0xAC], :mrm, :u8) { |o| o.args[0], o.args[1] = o.args[1], o.args[0] }
111
+ addop('shrd', [0x0F, 0xAD], :mrm, :reg_cl) { |o| o.args[0], o.args[1] = o.args[1], o.args[0] }
112
+ addop_macrostr 'stos', [0xAA], :strop
113
+ addop_macro1 'sub', 5
114
+ addop 'test', [0x84], :mrmw
115
+ addop 'test', [0xA8], nil, {:w => [0, 0]}, :reg_eax, :i, :unsigned_imm
116
+ addop 'test', [0xF6], 0, {:w => [0, 0]}, :i, :unsigned_imm
117
+ addop 'xchg', [0x90], :reg, :reg_eax
118
+ addop('xchg', [0x90], :reg, :reg_eax) { |o| o.args.reverse! } # xchg eax, ebx == xchg ebx, eax)
119
+ addop 'xchg', [0x86], :mrmw
120
+ addop('xchg', [0x86], :mrmw) { |o| o.args.reverse! }
121
+ addop_macro1 'xor', 6, :unsigned_imm
122
+ end
123
+
124
+ def init_386_only
125
+ init_cpu_constants
126
+
127
+ addop 'aaa', [0x37]
128
+ addop 'aad', [0xD5, 0x0A]
129
+ addop 'aam', [0xD4, 0x0A]
130
+ addop 'aas', [0x3F]
131
+ addop('arpl', [0x63], :mrm) { |o| o.props[:argsz] = 16 ; o.args.reverse! }
132
+ addop 'bound', [0x62], :mrmA
133
+ addop 'bsf', [0x0F, 0xBC], :mrm
134
+ addop 'bsr', [0x0F, 0xBD], :mrm
135
+ addop_macro2 'bt' , 0
136
+ addop_macro2 'btc', 3
137
+ addop_macro2 'btr', 2
138
+ addop_macro2 'bts', 1
139
+ addop 'call', [0x9A], nil, :stopexec, :setip, :farptr, :saveip
140
+ addop 'callf', [0x9A], nil, :stopexec, :setip, :farptr, :saveip
141
+ addop 'callf', [0xFF], 3, :stopexec, :setip, :saveip
142
+ addop 'clc', [0xF8]
143
+ addop 'cld', [0xFC]
144
+ addop 'cli', [0xFA]
145
+ addop 'clts', [0x0F, 0x06]
146
+ addop 'cmc', [0xF5]
147
+ addop('cmpxchg',[0x0F, 0xB0], :mrmw) { |o| o.args.reverse! }
148
+ addop 'cpuid', [0x0F, 0xA2]
149
+ addop 'daa', [0x27]
150
+ addop 'das', [0x2F]
151
+ addop 'hlt', [0xF4], nil, :stopexec
152
+ addop 'in', [0xE4], nil, {:w => [0, 0]}, :reg_eax, :u8
153
+ addop 'in', [0xE4], nil, {:w => [0, 0]}, :u8
154
+ addop 'in', [0xEC], nil, {:w => [0, 0]}, :reg_eax, :reg_dx
155
+ addop 'in', [0xEC], nil, {:w => [0, 0]}, :reg_eax
156
+ addop 'in', [0xEC], nil, {:w => [0, 0]}
157
+ addop_macrostr 'ins', [0x6C], :strop
158
+ addop 'into', [0xCE]
159
+ addop 'invd', [0x0F, 0x08]
160
+ addop 'invlpg', [0x0F, 0x01, 7<<3], :modrmA
161
+ addop('iretd', [0xCF], nil, :stopexec, :setip) { |o| o.props[:opsz] = 32 }
162
+ addop_macroret 'iret', [0xCF]
163
+ addop('jcxz', [0xE3], nil, :setip, :i8) { |o| o.props[:adsz] = 16 }
164
+ addop('jecxz', [0xE3], nil, :setip, :i8) { |o| o.props[:adsz] = 32 }
165
+ addop 'jmp', [0xEA], nil, :farptr, :setip, :stopexec
166
+ addop 'jmpf', [0xEA], nil, :farptr, :setip, :stopexec
167
+ addop 'jmpf', [0xFF], 5, :stopexec, :setip # reg ?
168
+ addop 'lahf', [0x9F]
169
+ addop 'lar', [0x0F, 0x02], :mrm
170
+ addop 'lds', [0xC5], :mrmA
171
+ addop 'les', [0xC4], :mrmA
172
+ addop 'lfs', [0x0F, 0xB4], :mrmA
173
+ addop 'lgs', [0x0F, 0xB5], :mrmA
174
+ addop 'lgdt', [0x0F, 0x01], 2, :modrmA
175
+ addop 'lidt', [0x0F, 0x01, 3<<3], :modrmA
176
+ addop 'lldt', [0x0F, 0x00], 2, :modrmA
177
+ addop 'lmsw', [0x0F, 0x01], 6
178
+ # prefix addop 'lock', [0xF0]
179
+ addop 'lsl', [0x0F, 0x03], :mrm
180
+ addop 'lss', [0x0F, 0xB2], :mrmA
181
+ addop 'ltr', [0x0F, 0x00], 3
182
+ addop 'mov', [0x0F, 0x20, 0xC0], :reg, {:d => [1, 1], :eeec => [2, 3]}, :eeec
183
+ addop 'mov', [0x0F, 0x21, 0xC0], :reg, {:d => [1, 1], :eeed => [2, 3]}, :eeed
184
+ addop 'mov', [0x0F, 0x24, 0xC0], :reg, {:d => [1, 1], :eeet => [2, 3]}, :eeet
185
+ addop 'mov', [0x8C], 0, {:d => [0, 1], :seg3 => [1, 3]}, :seg3
186
+ addop 'movbe', [0x0F, 0x38, 0xF0], :mrm, { :d => [2, 0] }
187
+ addop 'out', [0xE6], nil, {:w => [0, 0]}, :u8, :reg_eax
188
+ addop 'out', [0xE6], nil, {:w => [0, 0]}, :reg_eax, :u8
189
+ addop 'out', [0xE6], nil, {:w => [0, 0]}, :u8
190
+ addop 'out', [0xEE], nil, {:w => [0, 0]}, :reg_dx, :reg_eax
191
+ addop 'out', [0xEE], nil, {:w => [0, 0]}, :reg_eax, :reg_dx
192
+ addop 'out', [0xEE], nil, {:w => [0, 0]}, :reg_eax # implicit arguments
193
+ addop 'out', [0xEE], nil, {:w => [0, 0]}
194
+ addop_macrostr 'outs', [0x6E], :strop
195
+ addop 'pop', [0x07], nil, {:seg2A => [0, 3]}, :seg2A
196
+ addop 'pop', [0x0F, 0x81], nil, {:seg3A => [1, 3]}, :seg3A
197
+ addop('popa', [0x61]) { |o| o.props[:opsz] = 16 }
198
+ addop('popad', [0x61]) { |o| o.props[:opsz] = 32 }
199
+ addop('popf', [0x9D]) { |o| o.props[:opsz] = 16 }
200
+ addop('popfd', [0x9D]) { |o| o.props[:opsz] = 32 }
201
+ addop 'push', [0x06], nil, {:seg2 => [0, 3]}, :seg2
202
+ addop 'push', [0x0F, 0x80], nil, {:seg3A => [1, 3]}, :seg3A
203
+ addop('pusha', [0x60]) { |o| o.props[:opsz] = 16 }
204
+ addop('pushad',[0x60]) { |o| o.props[:opsz] = 32 }
205
+ addop('pushf', [0x9C]) { |o| o.props[:opsz] = 16 }
206
+ addop('pushfd',[0x9C]) { |o| o.props[:opsz] = 32 }
207
+ addop_macro3 'rcl', 2
208
+ addop_macro3 'rcr', 3
209
+ addop 'rdmsr', [0x0F, 0x32]
210
+ addop 'rdpmc', [0x0F, 0x33]
211
+ addop 'rdtsc', [0x0F, 0x31], nil, :random
212
+ addop_macroret 'retf', [0xCB]
213
+ addop_macroret 'retf', [0xCA], :u16
214
+ addop 'rsm', [0x0F, 0xAA], nil, :stopexec
215
+ addop 'sahf', [0x9E]
216
+ addop 'sgdt', [0x0F, 0x01, 0<<3], :modrmA
217
+ addop 'sidt', [0x0F, 0x01, 1<<3], :modrmA
218
+ addop 'sldt', [0x0F, 0x00], 0
219
+ addop 'smsw', [0x0F, 0x01], 4
220
+ addop 'stc', [0xF9]
221
+ addop 'std', [0xFD]
222
+ addop 'sti', [0xFB]
223
+ addop 'str', [0x0F, 0x00], 1
224
+ addop 'test', [0xF6], 1, {:w => [0, 0]}, :i, :unsigned_imm # undocumented alias to F6/0
225
+ addop 'ud2', [0x0F, 0x0B]
226
+ addop 'verr', [0x0F, 0x00], 4
227
+ addop 'verw', [0x0F, 0x00], 5
228
+ addop 'wait', [0x9B]
229
+ addop 'wbinvd',[0x0F, 0x09]
230
+ addop 'wrmsr', [0x0F, 0x30]
231
+ addop('xadd', [0x0F, 0xC0], :mrmw) { |o| o.args.reverse! }
232
+ addop 'xlat', [0xD7]
233
+
234
+ # pfx: addrsz = 0x67, lock = 0xF0, opsz = 0x66, repnz = 0xF2, rep/repz = 0xF3
235
+ # cs/nojmp = 0x2E, ds/jmp = 0x3E, es = 0x26, fs = 0x64, gs = 0x65, ss = 0x36
236
+
237
+ # undocumented opcodes
238
+ addop 'aam', [0xD4], nil, :u8
239
+ addop 'aad', [0xD5], nil, :u8
240
+ addop 'setalc',[0xD6]
241
+ addop 'salc', [0xD6]
242
+ addop 'icebp', [0xF1]
243
+ #addop 'loadall',[0x0F, 0x07] # conflict with syscall
244
+ addop 'ud0', [0x0F, 0xFF] # amd
245
+ addop 'ud2', [0x0F, 0xB9], :mrm
246
+ #addop 'umov', [0x0F, 0x10], :mrmw, {:d => [1, 1]} # conflicts with movups/movhlps
247
+ end
248
+
249
+ def init_387_only
250
+ init_cpu_constants
251
+
252
+ addop 'f2xm1', [0xD9, 0xF0]
253
+ addop 'fabs', [0xD9, 0xE1]
254
+ addop_macrofpu1 'fadd', 0
255
+ addop 'faddp', [0xDE, 0xC0], :regfp
256
+ addop 'faddp', [0xDE, 0xC1]
257
+ addop('fbld', [0xDF, 4<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 80 }
258
+ addop('fbstp', [0xDF, 6<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 80 }
259
+ addop 'fchs', [0xD9, 0xE0], nil, :regfp0
260
+ addop 'fnclex', [0xDB, 0xE2]
261
+ addop_macrofpu1 'fcom', 2
262
+ addop_macrofpu1 'fcomp', 3
263
+ addop 'fcompp',[0xDE, 0xD9]
264
+ addop 'fcomip',[0xDF, 0xF0], :regfp
265
+ addop 'fcos', [0xD9, 0xFF], nil, :regfp0
266
+ addop 'fdecstp', [0xD9, 0xF6]
267
+ addop_macrofpu1 'fdiv', 6
268
+ addop_macrofpu1 'fdivr', 7
269
+ addop 'fdivp', [0xDE, 0xF8], :regfp
270
+ addop 'fdivp', [0xDE, 0xF9]
271
+ addop 'fdivrp',[0xDE, 0xF0], :regfp
272
+ addop 'fdivrp',[0xDE, 0xF1]
273
+ addop 'ffree', [0xDD, 0xC0], nil, {:regfp => [1, 0]}, :regfp
274
+ addop_macrofpu2 'fiadd', 0
275
+ addop_macrofpu2 'fimul', 1
276
+ addop_macrofpu2 'ficom', 2
277
+ addop_macrofpu2 'ficomp',3
278
+ addop_macrofpu2 'fisub', 4
279
+ addop_macrofpu2 'fisubr',5
280
+ addop_macrofpu2 'fidiv', 6
281
+ addop_macrofpu2 'fidivr',7
282
+ addop 'fincstp', [0xD9, 0xF7]
283
+ addop 'fninit', [0xDB, 0xE3]
284
+ addop_macrofpu2 'fist', 2, 1
285
+ addop_macrofpu3 'fild', 0
286
+ addop_macrofpu3 'fistp',3
287
+ addop('fld', [0xD9, 0<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 32 }
288
+ addop('fld', [0xDD, 0<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 64 }
289
+ addop('fld', [0xDB, 5<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 80 }
290
+ addop 'fld', [0xD9, 0xC0], :regfp
291
+
292
+ addop('fldcw', [0xD9, 5<<3], :modrmA) { |o| o.props[:argsz] = 16 }
293
+ addop 'fldenv', [0xD9, 4<<3], :modrmA
294
+ addop 'fld1', [0xD9, 0xE8]
295
+ addop 'fldl2t', [0xD9, 0xE9]
296
+ addop 'fldl2e', [0xD9, 0xEA]
297
+ addop 'fldpi', [0xD9, 0xEB]
298
+ addop 'fldlg2', [0xD9, 0xEC]
299
+ addop 'fldln2', [0xD9, 0xED]
300
+ addop 'fldz', [0xD9, 0xEE]
301
+ addop_macrofpu1 'fmul', 1
302
+ addop 'fmulp', [0xDE, 0xC8], :regfp
303
+ addop 'fmulp', [0xDE, 0xC9]
304
+ addop 'fnop', [0xD9, 0xD0]
305
+ addop 'fpatan', [0xD9, 0xF3]
306
+ addop 'fprem', [0xD9, 0xF8]
307
+ addop 'fprem1', [0xD9, 0xF5]
308
+ addop 'fptan', [0xD9, 0xF2]
309
+ addop 'frndint',[0xD9, 0xFC]
310
+ addop 'frstor', [0xDD, 4<<3], :modrmA
311
+ addop 'fnsave', [0xDD, 6<<3], :modrmA
312
+ addop('fnstcw', [0xD9, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 }
313
+ addop 'fnstenv',[0xD9, 6<<3], :modrmA
314
+ addop 'fnstsw', [0xDF, 0xE0]
315
+ addop('fnstsw', [0xDD, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 }
316
+ addop 'fscale', [0xD9, 0xFD]
317
+ addop 'fsin', [0xD9, 0xFE]
318
+ addop 'fsincos',[0xD9, 0xFB]
319
+ addop 'fsqrt', [0xD9, 0xFA]
320
+ addop('fst', [0xD9, 2<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 32 }
321
+ addop('fst', [0xDD, 2<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 64 }
322
+ addop 'fst', [0xD9, 0xD0], :regfp
323
+ addop('fstp', [0xD9, 3<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 32 }
324
+ addop('fstp', [0xDD, 3<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 64 }
325
+ addop('fstp', [0xDB, 7<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 80 }
326
+ addop 'fstp', [0xDD, 0xD8], :regfp
327
+ addop_macrofpu1 'fsub', 4
328
+ addop 'fsubp', [0xDE, 0xE8], :regfp
329
+ addop 'fsubp', [0xDE, 0xE9]
330
+ addop_macrofpu1 'fsubp', 5
331
+ addop 'fsubrp', [0xDE, 0xE0], :regfp
332
+ addop 'fsubrp', [0xDE, 0xE1]
333
+ addop 'ftst', [0xD9, 0xE4]
334
+ addop 'fucom', [0xDD, 0xE0], :regfp
335
+ addop 'fucomp', [0xDD, 0xE8], :regfp
336
+ addop 'fucompp',[0xDA, 0xE9]
337
+ addop 'fucomi', [0xDB, 0xE8], :regfp
338
+ addop 'fxam', [0xD9, 0xE5]
339
+ addop 'fxch', [0xD9, 0xC8], :regfp
340
+ addop 'fxtract',[0xD9, 0xF4]
341
+ addop 'fyl2x', [0xD9, 0xF1]
342
+ addop 'fyl2xp1',[0xD9, 0xF9]
343
+ # fwait prefix
344
+ addop 'fclex', [0x9B, 0xDB, 0xE2]
345
+ addop 'finit', [0x9B, 0xDB, 0xE3]
346
+ addop 'fsave', [0x9B, 0xDD, 6<<3], :modrmA
347
+ addop('fstcw', [0x9B, 0xD9, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 }
348
+ addop 'fstenv', [0x9B, 0xD9, 6<<3], :modrmA
349
+ addop 'fstsw', [0x9B, 0xDF, 0xE0]
350
+ addop('fstsw', [0x9B, 0xDD, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 }
351
+ addop 'fwait', [0x9B]
352
+ end
353
+
354
+ def init_486_only
355
+ init_cpu_constants
356
+ end
357
+
358
+ def init_pentium_only
359
+ init_cpu_constants
360
+
361
+ addop('cmpxchg8b', [0x0F, 0xC7], 1) { |o| o.props[:opsz] = 32 ; o.props[:argsz] = 64 }
362
+ # lock cmpxchg8b eax
363
+ #addop 'f00fbug', [0xF0, 0x0F, 0xC7, 0xC8]
364
+
365
+ # mmx
366
+ addop 'emms', [0x0F, 0x77]
367
+ addop('movd', [0x0F, 0x6E], :mrmmmx, {:d => [1, 4]}) { |o| o.args = [:modrm, :regmmx] ; o.props[:opsz] = o.props[:argsz] = 32 }
368
+ addop('movq', [0x0F, 0x6F], :mrmmmx, {:d => [1, 4]}) { |o| o.props[:argsz] = 64 }
369
+ addop 'packssdw', [0x0F, 0x6B], :mrmmmx
370
+ addop 'packsswb', [0x0F, 0x63], :mrmmmx
371
+ addop 'packuswb', [0x0F, 0x67], :mrmmmx
372
+ addop_macrogg 0..2, 'padd', [0x0F, 0xFC], :mrmmmx
373
+ addop_macrogg 0..1, 'padds', [0x0F, 0xEC], :mrmmmx
374
+ addop_macrogg 0..1, 'paddus',[0x0F, 0xDC], :mrmmmx
375
+ addop 'pand', [0x0F, 0xDB], :mrmmmx
376
+ addop 'pandn', [0x0F, 0xDF], :mrmmmx
377
+ addop_macrogg 0..2, 'pcmpeq',[0x0F, 0x74], :mrmmmx
378
+ addop_macrogg 0..2, 'pcmpgt',[0x0F, 0x64], :mrmmmx
379
+ addop 'pmaddwd', [0x0F, 0xF5], :mrmmmx
380
+ addop 'pmulhuw', [0x0F, 0xE4], :mrmmmx
381
+ addop 'pmulhw',[0x0F, 0xE5], :mrmmmx
382
+ addop 'pmullw',[0x0F, 0xD5], :mrmmmx
383
+ addop 'por', [0x0F, 0xEB], :mrmmmx
384
+ [[1..3, 'psll', 3], [1..2, 'psra', 2], [1..3, 'psrl', 1]].each { |ggrng, name, val|
385
+ addop_macrogg ggrng, name, [0x0F, 0xC0 | (val << 4)], :mrmmmx
386
+ addop_macrogg ggrng, name, [0x0F, 0x70, 0xC0 | (val << 4)], nil, {:regmmx => [2, 0]}, :regmmx, :u8
387
+ }
388
+ addop_macrogg 0..2, 'psub', [0x0F, 0xF8], :mrmmmx
389
+ addop_macrogg 0..1, 'psubs', [0x0F, 0xE8], :mrmmmx
390
+ addop_macrogg 0..1, 'psubus',[0x0F, 0xD8], :mrmmmx
391
+ addop_macrogg 1..3, 'punpckh', [0x0F, 0x68], :mrmmmx
392
+ addop_macrogg 1..3, 'punpckl', [0x0F, 0x60], :mrmmmx
393
+ addop 'pxor', [0x0F, 0xEF], :mrmmmx
394
+ end
395
+
396
+ def init_p6_only
397
+ addop_macrotttn 'cmov', [0x0F, 0x40], :mrm
398
+
399
+ %w{b e be u}.each_with_index { |tt, i|
400
+ addop 'fcmov' + tt, [0xDA, 0xC0 | (i << 3)], :regfp
401
+ addop 'fcmovn'+ tt, [0xDB, 0xC0 | (i << 3)], :regfp
402
+ }
403
+ addop 'fcomi', [0xDB, 0xF0], :regfp
404
+ addop('fxrstor', [0x0F, 0xAE, 1<<3], :modrmA) { |o| o.props[:argsz] = 512*8 }
405
+ addop('fxsave', [0x0F, 0xAE, 0<<3], :modrmA) { |o| o.props[:argsz] = 512*8 }
406
+ addop 'sysenter',[0x0F, 0x34]
407
+ addop 'sysexit', [0x0F, 0x35]
408
+
409
+ addop 'syscall', [0x0F, 0x05] # AMD
410
+ addop_macroret 'sysret', [0x0F, 0x07] # AMD
411
+ end
412
+
413
+ def init_3dnow_only
414
+ init_cpu_constants
415
+
416
+ [['pavgusb', 0xBF], ['pfadd', 0x9E], ['pfsub', 0x9A],
417
+ ['pfsubr', 0xAA], ['pfacc', 0xAE], ['pfcmpge', 0x90],
418
+ ['pfcmpgt', 0xA0], ['fpcmpeq', 0xB0], ['pfmin', 0x94],
419
+ ['pfmax', 0xA4], ['pi2fd', 0x0D], ['pf2id', 0x1D],
420
+ ['pfrcp', 0x96], ['pfrsqrt', 0x97], ['pfmul', 0xB4],
421
+ ['pfrcpit1', 0xA6], ['pfrsqit1', 0xA7], ['pfrcpit2', 0xB6],
422
+ ['pmulhrw', 0xB7]].each { |str, bin|
423
+ addop str, [0x0F, 0x0F, bin], :mrmmmx
424
+ }
425
+ # 3dnow prefix fallback
426
+ addop '3dnow', [0x0F, 0x0F], :mrmmmx, :u8
427
+
428
+ addop 'femms', [0x0F, 0x0E]
429
+ addop 'prefetch', [0x0F, 0x0D, 0<<3], :modrmA
430
+ addop 'prefetchw', [0x0F, 0x0D, 1<<3], :modrmA
431
+ end
432
+
433
+ def init_sse_only
434
+ init_cpu_constants
435
+
436
+ addop_macrossps 'addps', [0x0F, 0x58], :mrmxmm
437
+ addop 'andnps', [0x0F, 0x55], :mrmxmm
438
+ addop 'andps', [0x0F, 0x54], :mrmxmm
439
+ addop_macrossps 'cmpps', [0x0F, 0xC2], :mrmxmm, :u8
440
+ addop 'comiss', [0x0F, 0x2F], :mrmxmm
441
+
442
+ addop('cvtpi2ps', [0x0F, 0x2A], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrmmmx }
443
+ addop('cvtps2pi', [0x0F, 0x2D], :mrmmmx) { |o| o.args[o.args.index(:modrmmmx)] = :modrmxmm }
444
+ addop('cvtsi2ss', [0x0F, 0x2A], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrm ; o.props[:needpfx] = 0xF3 }
445
+ addop('cvtss2si', [0x0F, 0x2D], :mrm) { |o| o.args[o.args.index(:modrm)] = :modrmxmm ; o.props[:needpfx] = 0xF3 }
446
+ addop('cvttps2pi',[0x0F, 0x2C], :mrmmmx) { |o| o.args[o.args.index(:modrmmmx)] = :modrmxmm }
447
+ addop('cvttss2si',[0x0F, 0x2C], :mrm) { |o| o.args[o.args.index(:modrm)] = :modrmxmm ; o.props[:needpfx] = 0xF3 }
448
+
449
+ addop_macrossps 'divps', [0x0F, 0x5E], :mrmxmm
450
+ addop 'ldmxcsr', [0x0F, 0xAE, 2<<3], :modrmA
451
+ addop_macrossps 'maxps', [0x0F, 0x5F], :mrmxmm
452
+ addop_macrossps 'minps', [0x0F, 0x5D], :mrmxmm
453
+ addop 'movaps', [0x0F, 0x28], :mrmxmm, {:d => [1, 0]}
454
+ addop 'movhlps', [0x0F, 0x12], :mrmxmm, :modrmR
455
+ addop 'movlps', [0x0F, 0x12], :mrmxmm, {:d => [1, 0]}, :modrmA
456
+ addop 'movlhps', [0x0F, 0x16], :mrmxmm, :modrmR
457
+ addop 'movhps', [0x0F, 0x16], :mrmxmm, {:d => [1, 0]}, :modrmA
458
+ addop 'movmskps',[0x0F, 0x50, 0xC0], nil, {:reg => [2, 3], :regxmm => [2, 0]}, :regxmm, :reg
459
+ addop('movss', [0x0F, 0x10], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0xF3 }
460
+ addop 'movups', [0x0F, 0x10], :mrmxmm, {:d => [1, 0]}
461
+ addop_macrossps 'mulps', [0x0F, 0x59], :mrmxmm
462
+ addop 'orps', [0x0F, 0x56], :mrmxmm
463
+ addop_macrossps 'rcpps', [0x0F, 0x53], :mrmxmm
464
+ addop_macrossps 'rsqrtps',[0x0F, 0x52], :mrmxmm
465
+ addop 'shufps', [0x0F, 0xC6], :mrmxmm, :u8
466
+ addop_macrossps 'sqrtps', [0x0F, 0x51], :mrmxmm
467
+ addop 'stmxcsr', [0x0F, 0xAE, 3<<3], :modrmA
468
+ addop_macrossps 'subps', [0x0F, 0x5C], :mrmxmm
469
+ addop 'ucomiss', [0x0F, 0x2E], :mrmxmm
470
+ addop 'unpckhps',[0x0F, 0x15], :mrmxmm
471
+ addop 'unpcklps',[0x0F, 0x14], :mrmxmm
472
+ addop 'xorps', [0x0F, 0x57], :mrmxmm
473
+
474
+ # integer instrs, mmx only
475
+ addop 'pavgb', [0x0F, 0xE0], :mrmmmx
476
+ addop 'pavgw', [0x0F, 0xE3], :mrmmmx
477
+ addop 'pextrw', [0x0F, 0xC5, 0xC0], nil, {:reg => [2, 3], :regmmx => [2, 0]}, :reg, :regmmx, :u8
478
+ addop 'pinsrw', [0x0F, 0xC4, 0x00], nil, {:modrm => [2, 0], :regmmx => [2, 3]}, :modrm, :regmmx, :u8
479
+ addop 'pmaxsw', [0x0F, 0xEE], :mrmmmx
480
+ addop 'pmaxub', [0x0F, 0xDE], :mrmmmx
481
+ addop 'pminsw', [0x0F, 0xEA], :mrmmmx
482
+ addop 'pminub', [0x0F, 0xDA], :mrmmmx
483
+ addop 'pmovmskb',[0x0F, 0xD7, 0xC0], nil, {:reg => [2, 3], :regmmx => [2, 0]}, :reg, :regmmx
484
+ addop 'psadbw', [0x0F, 0xF6], :mrmmmx
485
+ addop 'pshufw', [0x0F, 0x70], :mrmmmx, :u8
486
+
487
+ addop 'maskmovq',[0x0F, 0xF7], :mrmmmx, :modrmR
488
+ addop('movntq', [0x0F, 0xE7], :mrmmmx) { |o| o.args.reverse! }
489
+ addop('movntps', [0x0F, 0x2B], :mrmxmm) { |o| o.args.reverse! }
490
+ addop 'prefetcht0', [0x0F, 0x18, 1<<3], :modrmA
491
+ addop 'prefetcht1', [0x0F, 0x18, 2<<3], :modrmA
492
+ addop 'prefetcht2', [0x0F, 0x18, 3<<3], :modrmA
493
+ addop 'prefetchnta',[0x0F, 0x18, 0<<3], :modrmA
494
+ addop 'sfence', [0x0F, 0xAE, 0xF8]
495
+
496
+ # the whole row of prefetch is actually nops
497
+ addop 'nop', [0x0F, 0x1C], :mrmw, :d => [1, 1] # incl. official version = 0f1f mrm
498
+ addop 'nop_8', [0x0F, 0x18], :mrmw, :d => [1, 1]
499
+ addop 'nop_d', [0x0F, 0x0D], :mrm
500
+ addop 'nop', [0x0F, 0x1C], 0 # official asm syntax is 'nop [eax]'
501
+ end
502
+
503
+ def init_sse2_only
504
+ init_cpu_constants
505
+
506
+ @opcode_list.each { |o| o.props[:xmmx] = true if o.fields[:regmmx] and o.name !~ /^(?:mov(?:nt)?q|pshufw|cvt.*)$/ }
507
+
508
+ # mirror of the init_sse part
509
+ addop_macrosdpd 'addpd', [0x0F, 0x58], :mrmxmm
510
+ addop('andnpd', [0x0F, 0x55], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
511
+ addop('andpd', [0x0F, 0x54], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
512
+ addop_macrosdpd 'cmppd', [0x0F, 0xC2], :mrmxmm, :u8
513
+ addop('comisd', [0x0F, 0x2F], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
514
+
515
+ addop('cvtpi2pd', [0x0F, 0x2A], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrmmmx ; o.props[:needpfx] = 0x66 }
516
+ addop('cvtpd2pi', [0x0F, 0x2D], :mrmmmx) { |o| o.args[o.args.index(:modrmmmx)] = :modrmxmm ; o.props[:needpfx] = 0x66 }
517
+ addop('cvtsi2sd', [0x0F, 0x2A], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrm ; o.props[:needpfx] = 0xF2 }
518
+ addop('cvtsd2si', [0x0F, 0x2D], :mrm ) { |o| o.args[o.args.index(:modrm )] = :modrmxmm ; o.props[:needpfx] = 0xF2 }
519
+ addop('cvttpd2pi',[0x0F, 0x2C], :mrmmmx) { |o| o.args[o.args.index(:modrmmmx)] = :modrmxmm ; o.props[:needpfx] = 0x66 }
520
+ addop('cvttsd2si',[0x0F, 0x2C], :mrm ) { |o| o.args[o.args.index(:modrm )] = :modrmxmm ; o.props[:needpfx] = 0xF2 }
521
+
522
+ addop('cvtpd2ps', [0x0F, 0x5A], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
523
+ addop('cvtps2pd', [0x0F, 0x5A], :mrmxmm)
524
+ addop('cvtsd2ss', [0x0F, 0x5A], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 }
525
+ addop('cvtss2sd', [0x0F, 0x5A], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 }
526
+
527
+ addop('cvtpd2dq', [0x0F, 0xE6], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 }
528
+ addop('cvttpd2dq',[0x0F, 0xE6], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
529
+ addop('cvtdq2pd', [0x0F, 0xE6], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 }
530
+ addop('cvtps2dq', [0x0F, 0x5B], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
531
+ addop('cvttps2dq',[0x0F, 0x5B], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 }
532
+ addop('cvtdq2ps', [0x0F, 0x5B], :mrmxmm)
533
+
534
+ addop_macrosdpd 'divpd', [0x0F, 0x5E], :mrmxmm
535
+ addop_macrosdpd 'maxpd', [0x0F, 0x5F], :mrmxmm
536
+ addop_macrosdpd 'minpd', [0x0F, 0x5D], :mrmxmm
537
+ addop('movapd', [0x0F, 0x28], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0x66 }
538
+
539
+ addop('movlpd', [0x0F, 0x12], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0x66 }
540
+ addop('movhpd', [0x0F, 0x16], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0x66 }
541
+
542
+ addop('movmskpd',[0x0F, 0x50, 0xC0], nil, {:reg => [2, 3], :regxmm => [2, 0]}, :regxmm, :reg) { |o| o.props[:needpfx] = 0x66 }
543
+ addop('movsd', [0x0F, 0x10], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0xF2 }
544
+ addop('movupd', [0x0F, 0x10], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0x66 }
545
+ addop_macrosdpd 'mulpd', [0x0F, 0x59], :mrmxmm
546
+ addop('orpd', [0x0F, 0x56], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
547
+ addop('shufpd', [0x0F, 0xC6], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
548
+ addop_macrosdpd 'sqrtpd', [0x0F, 0x51], :mrmxmm
549
+ addop_macrosdpd 'subpd', [0x0F, 0x5C], :mrmxmm
550
+ addop('ucomisd', [0x0F, 0x2E], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
551
+ addop('unpckhpd',[0x0F, 0x15], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
552
+ addop('unpcklpd',[0x0F, 0x14], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
553
+ addop('xorpd', [0x0F, 0x57], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
554
+
555
+ addop('movdqa', [0x0F, 0x6F], :mrmxmm, {:d => [1, 4]}) { |o| o.props[:needpfx] = 0x66 }
556
+ addop('movdqu', [0x0F, 0x6F], :mrmxmm, {:d => [1, 4]}) { |o| o.props[:needpfx] = 0xF3 }
557
+ addop('movq2dq', [0x0F, 0xD6], :mrmxmm, :modrmR) { |o| o.args[o.args.index(:modrmxmm)] = :modrmmmx ; o.props[:needpfx] = 0xF3 }
558
+ addop('movdq2q', [0x0F, 0xD6], :mrmmmx, :modrmR) { |o| o.args[o.args.index(:modrmmmx)] = :modrmxmm ; o.props[:needpfx] = 0xF2 }
559
+ addop('movq', [0x0F, 0x7E], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 ; o.props[:argsz] = 128 }
560
+ addop('movq', [0x0F, 0xD6], :mrmxmm) { |o| o.args.reverse! ; o.props[:needpfx] = 0x66 ; o.props[:argsz] = 128 }
561
+
562
+ addop 'paddq', [0x0F, 0xD4], :mrmmmx, :xmmx
563
+ addop 'pmuludq', [0x0F, 0xF4], :mrmmmx, :xmmx
564
+ addop('pshuflw', [0x0F, 0x70], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0xF2 }
565
+ addop('pshufhw', [0x0F, 0x70], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0xF3 }
566
+ addop('pshufd', [0x0F, 0x70], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
567
+ addop('pslldq', [0x0F, 0x73, 0xF8], nil, {:regxmm => [2, 0]}, :regxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
568
+ addop('psrldq', [0x0F, 0x73, 0xD8], nil, {:regxmm => [2, 0]}, :regxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
569
+ addop 'psubq', [0x0F, 0xFB], :mrmmmx, :xmmx
570
+ addop('punpckhqdq', [0x0F, 0x6D], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
571
+ addop('punpcklqdq', [0x0F, 0x6C], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
572
+
573
+ addop('clflush', [0x0F, 0xAE, 7<<3], :modrmA) { |o| o.props[:argsz] = 8 }
574
+ addop('maskmovdqu', [0x0F, 0xF7], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
575
+ addop('movntpd', [0x0F, 0x2B], :mrmxmm) { |o| o.args.reverse! ; o.props[:needpfx] = 0x66 }
576
+ addop('movntdq', [0x0F, 0xE7], :mrmxmm) { |o| o.args.reverse! ; o.props[:needpfx] = 0x66 }
577
+ addop('movnti', [0x0F, 0xC3], :mrm) { |o| o.args.reverse! }
578
+ addop('pause', [0x90]) { |o| o.props[:needpfx] = 0xF3 }
579
+ addop 'lfence', [0x0F, 0xAE, 0xE8]
580
+ addop 'mfence', [0x0F, 0xAE, 0xF0]
581
+ end
582
+
583
+ def init_sse3_only
584
+ init_cpu_constants
585
+
586
+ addop('addsubpd', [0x0F, 0xD0], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
587
+ addop('addsubps', [0x0F, 0xD0], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 }
588
+ addop('haddpd', [0x0F, 0x7C], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
589
+ addop('haddps', [0x0F, 0x7C], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 }
590
+ addop('hsubpd', [0x0F, 0x7D], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
591
+ addop('hsubps', [0x0F, 0x7D], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 }
592
+
593
+ addop 'monitor', [0x0F, 0x01, 0xC8]
594
+ addop 'mwait', [0x0F, 0x01, 0xC9]
595
+
596
+ addop('fisttp', [0xDF, 1<<3], :modrmA) { |o| o.props[:argsz] = 16 }
597
+ addop('fisttp', [0xDB, 1<<3], :modrmA) { |o| o.props[:argsz] = 32 }
598
+ addop('fisttp', [0xDD, 1<<3], :modrmA) { |o| o.props[:argsz] = 64 }
599
+ addop('lddqu', [0x0F, 0xF0], :mrmxmm, :modrmA) { |o| o.args[o.args.index(:modrmxmm)] = :modrm ; o.props[:needpfx] = 0xF2 }
600
+ addop('movddup', [0x0F, 0x12], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 }
601
+ addop('movshdup', [0x0F, 0x16], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 }
602
+ addop('movsldup', [0x0F, 0x12], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 }
603
+ end
604
+
605
+ def init_ssse3_only
606
+ init_cpu_constants
607
+
608
+ addop_macrogg 0..2, 'pabs', [0x0F, 0x38, 0x1C], :mrmmmx, :xmmx
609
+ addop 'palignr', [0x0F, 0x3A, 0x0F], :mrmmmx, :u8, :xmmx
610
+ addop 'phaddd', [0x0F, 0x38, 0x02], :mrmmmx, :xmmx
611
+ addop 'phaddsw', [0x0F, 0x38, 0x03], :mrmmmx, :xmmx
612
+ addop 'phaddw', [0x0F, 0x38, 0x01], :mrmmmx, :xmmx
613
+ addop 'phsubd', [0x0F, 0x38, 0x06], :mrmmmx, :xmmx
614
+ addop 'phsubsw', [0x0F, 0x38, 0x07], :mrmmmx, :xmmx
615
+ addop 'phsubw', [0x0F, 0x38, 0x05], :mrmmmx, :xmmx
616
+ addop 'pmaddubsw',[0x0F, 0x38, 0x04], :mrmmmx, :xmmx
617
+ addop 'pmulhrsw', [0x0F, 0x38, 0x0B], :mrmmmx, :xmmx
618
+ addop 'pshufb', [0x0F, 0x38, 0x00], :mrmmmx, :xmmx
619
+ addop_macrogg 0..2, 'psignb', [0x0F, 0x38, 0x80], :mrmmmx, :xmmx
620
+ end
621
+
622
+ def init_aesni_only
623
+ init_cpu_constants
624
+
625
+ addop('aesdec', [0x0F, 0x38, 0xDE], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
626
+ addop('aesdeclast',[0x0F, 0x38, 0xDF], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
627
+ addop('aesenc', [0x0F, 0x38, 0xDC], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
628
+ addop('aesenclast',[0x0F, 0x38, 0xDD], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
629
+ addop('aesimc', [0x0F, 0x38, 0xDB], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
630
+ addop('aeskeygenassist', [0x0F, 0x3A, 0xDF], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
631
+
632
+ addop('pclmulqdq', [0x0F, 0x3A, 0x44], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
633
+ end
634
+
635
+ def init_vmx_only
636
+ init_cpu_constants
637
+
638
+ addop 'vmcall', [0x0F, 0x01, 0xC1]
639
+ addop 'vmlaunch', [0x0F, 0x01, 0xC2]
640
+ addop 'vmresume', [0x0F, 0x01, 0xC3]
641
+ addop 'vmxoff', [0x0F, 0x01, 0xC4]
642
+ addop 'vmread', [0x0F, 0x78], :mrm
643
+ addop 'vmwrite', [0x0F, 0x79], :mrm
644
+ addop('vmclear', [0x0F, 0xC7, 6<<3], :modrmA) { |o| o.props[:argsz] = 64 ; o.props[:needpfx] = 0x66 }
645
+ addop('vmxon', [0x0F, 0xC7, 6<<3], :modrmA) { |o| o.props[:argsz] = 64 ; o.props[:needpfx] = 0xF3 }
646
+ addop('vmptrld', [0x0F, 0xC7, 6<<3], :modrmA) { |o| o.props[:argsz] = 64 }
647
+ addop('vmptrrst', [0x0F, 0xC7, 7<<3], :modrmA) { |o| o.props[:argsz] = 64 }
648
+ addop('invept', [0x0F, 0x38, 0x80], :mrmA) { |o| o.props[:needpfx] = 0x66 }
649
+ addop('invvpid', [0x0F, 0x38, 0x81], :mrmA) { |o| o.props[:needpfx] = 0x66 }
650
+
651
+ addop 'getsec', [0x0F, 0x37]
652
+
653
+ addop 'xgetbv', [0x0F, 0x01, 0xD0]
654
+ addop 'xsetbv', [0x0F, 0x01, 0xD1]
655
+ addop 'rdtscp', [0x0F, 0x01, 0xF9]
656
+ addop 'xrstor', [0x0F, 0xAE, 5<<3], :modrmA
657
+ addop 'xsave', [0x0F, 0xAE, 4<<3], :modrmA
658
+ end
659
+
660
+ def init_sse41_only
661
+ init_cpu_constants
662
+
663
+ addop('blendpd', [0x0F, 0x3A, 0x0D], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
664
+ addop('blendps', [0x0F, 0x3A, 0x0C], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
665
+ addop('blendvpd', [0x0F, 0x38, 0x15], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
666
+ addop('blendvps', [0x0F, 0x38, 0x14], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
667
+ addop('dppd', [0x0F, 0x3A, 0x41], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
668
+ addop('dpps', [0x0F, 0x3A, 0x40], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
669
+ addop('extractps',[0x0F, 0x3A, 0x17], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
670
+ addop('insertps', [0x0F, 0x3A, 0x21], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
671
+ addop('movntdqa', [0x0F, 0x38, 0x2A], :mrmxmm, :modrmA) { |o| o.props[:needpfx] = 0x66 }
672
+ addop('mpsadbw', [0x0F, 0x3A, 0x42], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
673
+ addop('packusdw', [0x0F, 0x38, 0x2B], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
674
+ addop('pblendvb', [0x0F, 0x38, 0x10], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
675
+ addop('pblendw', [0x0F, 0x3A, 0x1E], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
676
+ addop('pcmpeqq', [0x0F, 0x38, 0x29], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
677
+ addop('pextrb', [0x0F, 0x3A, 0x14], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:argsz] = 8 }
678
+ addop('pextrw', [0x0F, 0x3A, 0x15], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:argsz] = 16 }
679
+ addop('pextrd', [0x0F, 0x3A, 0x16], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:argsz] = 32 }
680
+ addop('pinsrb', [0x0F, 0x3A, 0x20], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:argsz] = 8 }
681
+ addop('pinsrw', [0x0F, 0x3A, 0x21], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:argsz] = 16 }
682
+ addop('pinsrd', [0x0F, 0x3A, 0x22], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66; o.args[o.args.index(:modrmxmm)] = :modrm; o.props[:argsz] = 32 }
683
+ addop('phminposuw', [0x0F, 0x38, 0x41], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
684
+ addop('pminsb', [0x0F, 0x38, 0x38], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
685
+ addop('pminsd', [0x0F, 0x38, 0x39], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
686
+ addop('pminuw', [0x0F, 0x38, 0x3A], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
687
+ addop('pminud', [0x0F, 0x38, 0x3B], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
688
+ addop('pmaxsb', [0x0F, 0x38, 0x3C], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
689
+ addop('pmaxsd', [0x0F, 0x38, 0x3D], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
690
+ addop('pmaxuw', [0x0F, 0x38, 0x3E], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
691
+ addop('pmaxud', [0x0F, 0x38, 0x3F], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
692
+
693
+ addop('pmovsxbw', [0x0F, 0x38, 0x20], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
694
+ addop('pmovsxbd', [0x0F, 0x38, 0x21], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
695
+ addop('pmovsxbq', [0x0F, 0x38, 0x22], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
696
+ addop('pmovsxwd', [0x0F, 0x38, 0x23], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
697
+ addop('pmovsxwq', [0x0F, 0x38, 0x24], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
698
+ addop('pmovsxdq', [0x0F, 0x38, 0x25], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
699
+ addop('pmovzxbw', [0x0F, 0x38, 0x30], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
700
+ addop('pmovzxbd', [0x0F, 0x38, 0x31], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
701
+ addop('pmovzxbq', [0x0F, 0x38, 0x32], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
702
+ addop('pmovzxwd', [0x0F, 0x38, 0x33], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
703
+ addop('pmovzxwq', [0x0F, 0x38, 0x34], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
704
+ addop('pmovzxdq', [0x0F, 0x38, 0x35], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
705
+
706
+ addop('pmuldq', [0x0F, 0x38, 0x28], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
707
+ addop('pmulld', [0x0F, 0x38, 0x40], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
708
+ addop('ptest', [0x0F, 0x38, 0x17], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
709
+ addop('roundps', [0x0F, 0x3A, 0x08], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
710
+ addop('roundpd', [0x0F, 0x3A, 0x09], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
711
+ addop('roundss', [0x0F, 0x3A, 0x0A], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
712
+ addop('roundsd', [0x0F, 0x3A, 0x0B], :mrmxmm, :u8) { |o| o.props[:needpfx] = 0x66 }
713
+ end
714
+
715
+ def init_sse42_only
716
+ init_cpu_constants
717
+
718
+ addop('crc32', [0x0F, 0x38, 0xF0], :mrmw) { |o| o.props[:needpfx] = 0xF2 }
719
+ addop('pcmpestrm', [0x0F, 0x3A, 0x60], :mrmxmm, :i8) { |o| o.props[:needpfx] = 0x66 }
720
+ addop('pcmpestri', [0x0F, 0x3A, 0x61], :mrmxmm, :i8) { |o| o.props[:needpfx] = 0x66 }
721
+ addop('pcmpistrm', [0x0F, 0x3A, 0x62], :mrmxmm, :i8) { |o| o.props[:needpfx] = 0x66 }
722
+ addop('pcmpistri', [0x0F, 0x3A, 0x63], :mrmxmm, :i8) { |o| o.props[:needpfx] = 0x66 }
723
+ addop('pcmpgtq', [0x0F, 0x38, 0x37], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
724
+ addop('popcnt', [0x0F, 0xB8], :mrm) { |o| o.props[:needpfx] = 0xF3 }
725
+ end
726
+
727
+ def init_avx_only
728
+ init_cpu_constants
729
+
730
+ add128 = {}
731
+ add256 = {}
732
+ %w[movss movsd movlhps movhpd movhlps
733
+ cvtsi2ss cvtsi2sd sqrtss sqrtsd rsqrtss rcpss
734
+ addss addsd mulss mulsd cvtss2sd cvtsd2ss subss subsd
735
+ minss minsd divss divsd maxss maxsd
736
+ punpcklb punpcklw punpckld packsswb pcmpgtb pcmpgtw pcmpgtd packuswb
737
+ punpckhb punpckhw punpckhd packssdw punpcklq punpckhq
738
+ pcmpeqb pcmpeqw pcmpeqd ldmxcsr stmxcsr
739
+ cmpss cmpsd paddq pmullw psubusb psubusw pminub
740
+ pand paddusb paddusw pmaxub pandn pavgb pavgw
741
+ pmulhuw pmulhw psubsb psubsw pminsw por paddsb paddsw pmaxsw pxor
742
+ pmuludq pmaddwd psadbw
743
+ psubb psubw psubd psubq paddb paddw paddd
744
+ phaddw phaddsw phaddd phsubw phsubsw phsubd
745
+ pmaddubsw palignr pshufb pmulhrsw psignb psignw psignd
746
+ dppd insertps mpsadbw packusdw pblendw pcmpeqq
747
+ pinsrb pinsrw pinsrd pinsrq
748
+ pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw
749
+ pmuldq pmulld roundsd roundss pcmpgtq
750
+ aesdec aesdeclast aesenc aesenclast
751
+ pclmulqdq punpcklbw punpcklwd punpckldq punpckhbw punpckhwd
752
+ punpckhdq punpcklqdq punpckhqdq].each { |n| add128[n] = true }
753
+
754
+ %w[movups movupd movddup movsldup
755
+ unpcklps unpcklpd unpckhps unpckhpd
756
+ movaps movshdup movapd movntps movntpd movmskps movmskpd
757
+ sqrtps sqrtpd rsqrtps rcpps andps andpd andnps andnpd
758
+ orps orpd xorps xorpd addps addpd mulps mulpd
759
+ cvtps2pd cvtpd2ps cvtdq2ps cvtps2dq cvttps2dq
760
+ subps subpd minps minpd divps divpd maxps maxpd
761
+ movdqa movdqu haddpd haddps hsubpd hsubps
762
+ cmpps cmppd shufps shufpd addsubpd addsubps
763
+ cvtpd2dq cvttpd2dq cvtdq2pd movntdq lddqu
764
+ blendps blendpd blendvps blendvpd dpps ptest
765
+ roundpd roundps].each { |n| add128[n] = add256[n] = true }
766
+
767
+ varg = Hash.new(1)
768
+ %w[pabsb pabsw pabsd pmovmskb pshufd pshufhw pshuflw movntdqa
769
+ pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq
770
+ pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq
771
+ aesimc aeskeygenassist lddqu maskmovdqu movapd movaps
772
+ pcmpestri pcmpestrm pcmpistri pcmpistrm phminposuw
773
+ cvtpd2dq cvttpd2dq cvtdq2pd cvtps2pd cvtpd2ps cvtdq2ps cvtps2dq
774
+ cvttps2dq movd movq movddup movdqa movdqu movmskps movmskpd
775
+ movntdq movntps movntpd movshdup movsldup movups movupd
776
+ pextrb pextrw pextrd pextrq ptest rcpps roundps roundpd
777
+ extractps sqrtps sqrtpd comiss comisd ucomiss ucomisd
778
+ cvttss2si cvttsd2si cvtss2si cvtsd2si
779
+ ].each { |n| add128[n] = true ; varg[n] = nil }
780
+
781
+ cvtarg128 = { :regmmx => :regxmm, :modrmmmx => :modrmxmm }
782
+ cvtarg256 = { :regmmx => :regymm, :modrmmmx => :modrmymm,
783
+ :regxmm => :regymm, :modrmxmm => :modrmymm }
784
+
785
+ # autopromote old sseX opcodes
786
+ @opcode_list.each { |o|
787
+ next if o.bin[0] != 0x0F or not add128[o.name] # rep cmpsd / movsd
788
+
789
+ mm = (o.bin[1] == 0x38 ? 0x0F38 : o.bin[1] == 0x3A ? 0x0F3A : 0x0F)
790
+ pp = o.props[:needpfx]
791
+ pp = 0x66 if o.props[:xmmx]
792
+ fpxlen = (mm == 0x0F ? 1 : 2)
793
+
794
+ addop_vex('v' + o.name, [varg[o.name], 128, pp, mm], o.bin[fpxlen], nil, *o.args.map { |oa| cvtarg128[oa] || oa }) { |oo|
795
+ oo.bin += [o.bin[fpxlen+1]] if o.bin[fpxlen+1]
796
+ dbinlen = o.bin.length - oo.bin.length
797
+ o.fields.each { |k, v| oo.fields[cvtarg128[k] || k] = [v[0]-dbinlen, v[1]] }
798
+ o.props.each { |k, v| oo.props[k] = v if k != :xmmx and k != :needpfx }
799
+ }
800
+
801
+ next if not add256[o.name]
802
+ addop_vex('v' + o.name, [varg[o.name], 256, pp, mm], o.bin[fpxlen], nil, *o.args.map { |oa| cvtarg256[oa] || oa }) { |oo|
803
+ oo.bin += [o.bin[fpxlen+1]] if o.bin[fpxlen+1]
804
+ dbinlen = o.bin.length - oo.bin.length
805
+ o.fields.each { |k, v| oo.fields[cvtarg256[k] || k] = [v[0]-dbinlen, v[1]] }
806
+ o.props.each { |k, v| oo.props[k] = v if k != :xmmx and k != :needpfx }
807
+ }
808
+ }
809
+
810
+ # sse promotion, special cases
811
+ addop_vex 'vpblendvb', [1, 128, 0x66, 0x0F3A, 0], 0x4C, :mrmxmm, :i4xmm
812
+ addop_vex 'vpsllw', [1, 128, 0x66, 0x0F], 0xF1, :mrmxmm
813
+ addop_vex('vpsllw', [0, 128, 0x66, 0x0F], 0x71, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm }
814
+ addop_vex 'vpslld', [1, 128, 0x66, 0x0F], 0xF2, :mrmxmm
815
+ addop_vex('vpslld', [0, 128, 0x66, 0x0F], 0x72, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm }
816
+ addop_vex 'vpsllq', [1, 128, 0x66, 0x0F], 0xF3, :mrmxmm
817
+ addop_vex('vpsllq', [0, 128, 0x66, 0x0F], 0x73, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm }
818
+ addop_vex('vpslldq',[0, 128, 0x66, 0x0F], 0x73, 7, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm }
819
+ addop_vex 'vpsraw', [1, 128, 0x66, 0x0F], 0xE1, :mrmxmm
820
+ addop_vex('vpsraw', [0, 128, 0x66, 0x0F], 0x71, 4, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm }
821
+ addop_vex 'vpsrad', [1, 128, 0x66, 0x0F], 0xE2, :mrmxmm
822
+ addop_vex('vpsrad', [0, 128, 0x66, 0x0F], 0x72, 4, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm }
823
+ addop_vex 'vpsrlw', [1, 128, 0x66, 0x0F], 0xD1, :mrmxmm
824
+ addop_vex('vpsrlw', [0, 128, 0x66, 0x0F], 0x71, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm }
825
+ addop_vex 'vpsrld', [1, 128, 0x66, 0x0F], 0xD2, :mrmxmm
826
+ addop_vex('vpsrld', [0, 128, 0x66, 0x0F], 0x72, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm }
827
+ addop_vex 'vpsrlq', [1, 128, 0x66, 0x0F], 0xD3, :mrmxmm
828
+ addop_vex('vpsrlq', [0, 128, 0x66, 0x0F], 0x73, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm }
829
+ addop_vex('vpsrldq',[0, 128, 0x66, 0x0F], 0x73, 3, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmxmm }
830
+
831
+ # dst==mem => no vreg
832
+ addop_vex 'vmovhps', [1, 128, nil, 0x0F], 0x16, :mrmxmm, :modrmA
833
+ addop_vex('vmovhps', [nil, 128, nil, 0x0F], 0x17, :mrmxmm, :modrmA) { |o| o.args.reverse! }
834
+ addop_vex 'vmovlpd', [1, 128, 0x66, 0x0F], 0x12, :mrmxmm, :modrmA
835
+ addop_vex('vmovlpd', [nil, 128, 0x66, 0x0F], 0x13, :mrmxmm, :modrmA) { |o| o.args.reverse! }
836
+ addop_vex 'vmovlps', [1, 128, nil, 0x0F], 0x12, :mrmxmm, :modrmA
837
+ addop_vex('vmovlps', [nil, 128, nil, 0x0F], 0x13, :mrmxmm, :modrmA) { |o| o.args.reverse! }
838
+
839
+ addop_vex 'vbroadcastss', [nil, 128, 0x66, 0x0F38, 0], 0x18, :mrmxmm, :modrmA
840
+ addop_vex 'vbroadcastss', [nil, 256, 0x66, 0x0F38, 0], 0x18, :mrmymm, :modrmA
841
+ addop_vex 'vbroadcastsd', [nil, 256, 0x66, 0x0F38, 0], 0x19, :mrmymm, :modrmA
842
+ addop_vex 'vbroadcastf128', [nil, 256, 0x66, 0x0F38, 0], 0x1A, :mrmymm, :modrmA
843
+
844
+ # general-purpose register operations
845
+ addop_vex 'andn', [1, :vexvreg, 128, nil, 0x0F38], 0xF2, :mrm
846
+ addop_vex 'bextr', [2, :vexvreg, 128, nil, 0x0F38], 0xF7, :mrm
847
+ addop_vex 'blsi', [0, :vexvreg, 128, nil, 0x0F38], 0xF3, 3
848
+ addop_vex 'blsmsk', [0, :vexvreg, 128, nil, 0x0F38], 0xF3, 2
849
+ addop_vex 'blsr', [0, :vexvreg, 128, nil, 0x0F38], 0xF3, 1
850
+ addop_vex 'bzhi', [2, :vexvreg, 128, nil, 0x0F38], 0xF5, :mrm
851
+ addop('lzcnt', [0x0F, 0xBD], :mrm) { |o| o.props[:needpfx] = 0xF3 }
852
+ addop_vex 'mulx', [1, :vexvreg, 128, 0xF2, 0x0F38], 0xF6, :mrm
853
+ addop_vex 'pdep', [1, :vexvreg, 128, 0xF2, 0x0F38], 0xF5, :mrm
854
+ addop_vex 'pext', [1, :vexvreg, 128, 0xF3, 0x0F38], 0xF5, :mrm
855
+ addop_vex 'rorx', [nil, 128, 0xF2, 0x0F3A], 0xF0, :mrm, :u8
856
+ addop_vex 'sarx', [2, :vexvreg, 128, 0xF3, 0x0F38], 0xF7, :mrm
857
+ addop_vex 'shrx', [2, :vexvreg, 128, 0xF2, 0x0F38], 0xF7, :mrm
858
+ addop_vex 'shlx', [2, :vexvreg, 128, 0x66, 0x0F38], 0xF7, :mrm
859
+ addop('tzcnt', [0x0F, 0xBC], :mrm) { |o| o.props[:needpfx] = 0xF3 }
860
+ addop('invpcid', [0x0F, 0x38, 0x82], :mrm) { |o| o.props[:needpfx] = 0x66 }
861
+ addop 'rdrand', [0x0F, 0xC7], 6, :modrmR
862
+ addop 'rdseed', [0x0F, 0xC7], 7, :modrmR
863
+ addop('adcx', [0x0F, 0x38, 0xF6], :mrm) { |o| o.props[:needpfx] = 0x66 }
864
+ addop('adox', [0x0F, 0x38, 0xF6], :mrm) { |o| o.props[:needpfx] = 0xF3 }
865
+
866
+ # fp16
867
+ addop_vex 'vcvtph2ps', [nil, 128, 0x66, 0x0F38, 0], 0x13, :mrmxmm
868
+ addop_vex 'vcvtph2ps', [nil, 256, 0x66, 0x0F38, 0], 0x13, :mrmymm
869
+ addop_vex('vcvtps2ph', [nil, 128, 0x66, 0x0F3A, 0], 0x1D, :mrmxmm, :u8) { |o| o.args.reverse! }
870
+ addop_vex('vcvtps2ph', [nil, 256, 0x66, 0x0F3A, 0], 0x1D, :mrmymm, :u8) { |o| o.args.reverse! }
871
+
872
+ # TSE
873
+ addop 'xabort', [0xC6, 0xF8], nil, :i8 # may :stopexec
874
+ addop 'xbegin', [0xC7, 0xF8], nil, :i # may :setip: xabortreturns to $_(xbegin) + off
875
+ addop 'xend', [0x0F, 0x01, 0xD5]
876
+ addop 'xtest', [0x0F, 0x01, 0xD6]
877
+
878
+ # SMAP
879
+ addop 'clac', [0x0F, 0x01, 0xCA]
880
+ addop 'stac', [0x0F, 0x01, 0xCB]
881
+ end
882
+
883
+ def init_avx2_only
884
+ init_cpu_constants
885
+
886
+ add256 = {}
887
+ %w[packsswb pcmpgtb pcmpgtw pcmpgtd packuswb packssdw
888
+ pcmpeqb pcmpeqw pcmpeqd paddq pmullw psubusb psubusw
889
+ pminub pand paddusb paddusw pmaxub pandn pavgb pavgw
890
+ pmulhuw pmulhw psubsb psubsw pminsw por paddsb paddsw
891
+ pmaxsw pxor pmuludq pmaddwd psadbw
892
+ psubb psubw psubd psubq paddb paddw paddd
893
+ phaddw phaddsw phaddd phsubw phsubsw phsubd
894
+ pmaddubsw palignr pshufb pmulhrsw psignb psignw psignd
895
+ mpsadbw packusdw pblendw pcmpeqq
896
+ pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw
897
+ pmuldq pmulld pcmpgtq punpcklbw punpcklwd punpckldq
898
+ punpckhbw punpckhwd punpckhdq punpcklqdq punpckhqdq
899
+ ].each { |n| add256[n] = true }
900
+
901
+ varg = Hash.new(1)
902
+ %w[pabsb pabsw pabsd pmovmskb pshufd pshufhw pshuflw movntdqa
903
+ pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq
904
+ pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq
905
+ maskmovdqu].each { |n| add256[n] = true ; varg[n] = nil }
906
+
907
+ cvtarg256 = { :regmmx => :regymm, :modrmmmx => :modrmymm,
908
+ :regxmm => :regymm, :modrmxmm => :modrmymm }
909
+
910
+ # autopromote old sseX opcodes
911
+ @opcode_list.each { |o|
912
+ next if o.bin[0] != 0x0F or not add256[o.name]
913
+
914
+ mm = (o.bin[1] == 0x38 ? 0x0F38 : o.bin[1] == 0x3A ? 0x0F3A : 0x0F)
915
+ pp = o.props[:needpfx]
916
+ pp = 0x66 if o.props[:xmmx]
917
+ fpxlen = (mm == 0x0F ? 1 : 2)
918
+
919
+ addop_vex('v' + o.name, [varg[o.name], 256, pp, mm], o.bin[fpxlen], nil, *o.args.map { |oa| cvtarg256[oa] || oa }) { |oo|
920
+ oo.bin += [o.bin[fpxlen+1]] if o.bin[fpxlen+1]
921
+ dbinlen = o.bin.length - oo.bin.length
922
+ o.fields.each { |k, v| oo.fields[cvtarg256[k] || k] = [v[0]-dbinlen, v[1]] }
923
+ o.props.each { |k, v| oo.props[k] = v if k != :xmmx and k != :needpfx }
924
+ }
925
+ }
926
+
927
+ # promote special cases
928
+ addop_vex 'vpblendvb', [1, 256, 0x66, 0x0F3A, 0], 0x4C, :mrmymm, :i4ymm
929
+ addop_vex 'vpsllw', [1, 256, 0x66, 0x0F], 0xF1, :mrmymm
930
+ addop_vex('vpsllw', [0, 256, 0x66, 0x0F], 0x71, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm }
931
+ addop_vex 'vpslld', [1, 256, 0x66, 0x0F], 0xF2, :mrmymm
932
+ addop_vex('vpslld', [0, 256, 0x66, 0x0F], 0x72, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm }
933
+ addop_vex 'vpsllq', [1, 256, 0x66, 0x0F], 0xF3, :mrmymm
934
+ addop_vex('vpsllq', [0, 256, 0x66, 0x0F], 0x73, 6, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm }
935
+ addop_vex('vpslldq',[0, 256, 0x66, 0x0F], 0x73, 7, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm }
936
+ addop_vex 'vpsraw', [1, 256, 0x66, 0x0F], 0xE1, :mrmymm
937
+ addop_vex('vpsraw', [0, 256, 0x66, 0x0F], 0x71, 4, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm }
938
+ addop_vex 'vpsrad', [1, 256, 0x66, 0x0F], 0xE2, :mrmymm
939
+ addop_vex('vpsrad', [0, 256, 0x66, 0x0F], 0x72, 4, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm }
940
+ addop_vex 'vpsrlw', [1, 256, 0x66, 0x0F], 0xD1, :mrmymm
941
+ addop_vex('vpsrlw', [0, 256, 0x66, 0x0F], 0x71, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm }
942
+ addop_vex 'vpsrld', [1, 256, 0x66, 0x0F], 0xD2, :mrmymm
943
+ addop_vex('vpsrld', [0, 256, 0x66, 0x0F], 0x72, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm }
944
+ addop_vex 'vpsrlq', [1, 256, 0x66, 0x0F], 0xD3, :mrmymm
945
+ addop_vex('vpsrlq', [0, 256, 0x66, 0x0F], 0x73, 2, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm }
946
+ addop_vex('vpsrldq',[0, 256, 0x66, 0x0F], 0x73, 3, :u8, :modrmR) { |o| o.args[o.args.index(:modrm)] = :modrmymm }
947
+
948
+ addop_vex 'vbroadcastss', [nil, 128, 0x66, 0x0F38, 0], 0x18, :mrmxmm, :modrmR
949
+ addop_vex 'vbroadcastss', [nil, 256, 0x66, 0x0F38, 0], 0x18, :mrmymm, :modrmR
950
+ addop_vex 'vbroadcastsd', [nil, 256, 0x66, 0x0F38, 0], 0x19, :mrmymm, :modrmR
951
+ addop_vex 'vbroadcasti128', [nil, 256, 0x66, 0x0F38, 0], 0x5A, :mrmymm, :modrmA
952
+ addop_vex 'vpblendd', [1, 128, 0x66, 0x0F3A, 0], 0x02, :mrmxmm, :u8
953
+ addop_vex 'vpblendd', [1, 256, 0x66, 0x0F3A, 0], 0x02, :mrmymm, :u8
954
+ addop_vex 'vpbroadcastb', [nil, 128, 0x66, 0x0F38, 0], 0x78, :mrmxmm
955
+ addop_vex 'vpbroadcastb', [nil, 256, 0x66, 0x0F38, 0], 0x78, :mrmymm
956
+ addop_vex 'vpbroadcastw', [nil, 128, 0x66, 0x0F38, 0], 0x79, :mrmxmm
957
+ addop_vex 'vpbroadcastw', [nil, 256, 0x66, 0x0F38, 0], 0x79, :mrmymm
958
+ addop_vex 'vpbroadcastd', [nil, 128, 0x66, 0x0F38, 0], 0x58, :mrmxmm
959
+ addop_vex 'vpbroadcastd', [nil, 256, 0x66, 0x0F38, 0], 0x58, :mrmymm
960
+ addop_vex 'vpbroadcastq', [nil, 128, 0x66, 0x0F38, 0], 0x59, :mrmxmm
961
+ addop_vex 'vpbroadcastq', [nil, 256, 0x66, 0x0F38, 0], 0x59, :mrmymm
962
+ addop_vex 'vpermd', [1, 256, 0x66, 0x0F38, 0], 0x36, :mrmymm
963
+ addop_vex 'vpermpd', [nil, 256, 0x66, 0x0F3A, 1], 0x01, :mrmymm, :u8
964
+ addop_vex 'vpermps', [1, 256, 0x66, 0x0F38, 0], 0x16, :mrmymm, :u8
965
+ addop_vex 'vpermq', [nil, 256, 0x66, 0x0F3A, 1], 0x00, :mrmymm, :u8
966
+ addop_vex 'vperm2i128', [1, 256, 0x66, 0x0F3A, 0], 0x46, :mrmymm, :u8
967
+ addop_vex 'vextracti128', [nil, 256, 0x66, 0x0F3A, 0], 0x39, :mrmymm, :u8
968
+ addop_vex 'vinserti128', [1, 256, 0x66, 0x0F3A, 0], 0x38, :mrmymm, :u8
969
+ addop_vex 'vpmaskmovd', [1, 128, 0x66, 0x0F38, 0], 0x8C, :mrmxmm, :modrmA
970
+ addop_vex 'vpmaskmovd', [1, 256, 0x66, 0x0F38, 0], 0x8C, :mrmymm, :modrmA
971
+ addop_vex 'vpmaskmovq', [1, 128, 0x66, 0x0F38, 1], 0x8C, :mrmxmm, :modrmA
972
+ addop_vex 'vpmaskmovq', [1, 256, 0x66, 0x0F38, 1], 0x8C, :mrmymm, :modrmA
973
+ addop_vex('vpmaskmovd', [1, 128, 0x66, 0x0F38, 0], 0x8E, :mrmxmm, :modrmA) { |o| o.args.reverse! }
974
+ addop_vex('vpmaskmovd', [1, 256, 0x66, 0x0F38, 0], 0x8E, :mrmymm, :modrmA) { |o| o.args.reverse! }
975
+ addop_vex('vpmaskmovq', [1, 128, 0x66, 0x0F38, 1], 0x8E, :mrmxmm, :modrmA) { |o| o.args.reverse! }
976
+ addop_vex('vpmaskmovq', [1, 256, 0x66, 0x0F38, 1], 0x8E, :mrmymm, :modrmA) { |o| o.args.reverse! }
977
+ addop_vex 'vpsllvd', [1, 128, 0x66, 0x0F38, 0], 0x47, :mrmxmm
978
+ addop_vex 'vpsllvq', [1, 128, 0x66, 0x0F38, 1], 0x47, :mrmxmm
979
+ addop_vex 'vpsllvd', [1, 256, 0x66, 0x0F38, 0], 0x47, :mrmymm
980
+ addop_vex 'vpsllvq', [1, 256, 0x66, 0x0F38, 1], 0x47, :mrmymm
981
+ addop_vex 'vpsravd', [1, 128, 0x66, 0x0F38, 0], 0x46, :mrmxmm
982
+ addop_vex 'vpsravd', [1, 256, 0x66, 0x0F38, 0], 0x46, :mrmymm
983
+ addop_vex 'vpsrlvd', [1, 128, 0x66, 0x0F38, 0], 0x45, :mrmxmm
984
+ addop_vex 'vpsrlvq', [1, 128, 0x66, 0x0F38, 1], 0x45, :mrmxmm
985
+ addop_vex 'vpsrlvd', [1, 256, 0x66, 0x0F38, 0], 0x45, :mrmymm
986
+ addop_vex 'vpsrlvq', [1, 256, 0x66, 0x0F38, 1], 0x45, :mrmymm
987
+
988
+ addop_vex('vpgatherdd', [2, 128, 0x66, 0x0F38, 0], 0x90, :mrmxmm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 128 }
989
+ addop_vex('vpgatherdd', [2, 256, 0x66, 0x0F38, 0], 0x90, :mrmymm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 256 }
990
+ addop_vex('vpgatherdq', [2, 128, 0x66, 0x0F38, 1], 0x90, :mrmxmm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 128 }
991
+ addop_vex('vpgatherdq', [2, 256, 0x66, 0x0F38, 1], 0x90, :mrmymm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 256 }
992
+ addop_vex('vpgatherqd', [2, 128, 0x66, 0x0F38, 0], 0x91, :mrmxmm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 128 }
993
+ addop_vex('vpgatherqd', [2, 256, 0x66, 0x0F38, 0], 0x91, :mrmymm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 256 }
994
+ addop_vex('vpgatherqq', [2, 128, 0x66, 0x0F38, 1], 0x91, :mrmxmm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 128 }
995
+ addop_vex('vpgatherqq', [2, 256, 0x66, 0x0F38, 1], 0x91, :mrmymm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 256 }
996
+ addop_vex('vgatherdps', [2, 128, 0x66, 0x0F38, 0], 0x92, :mrmxmm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 128 }
997
+ addop_vex('vgatherdps', [2, 256, 0x66, 0x0F38, 0], 0x92, :mrmymm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 256 }
998
+ addop_vex('vgatherdpd', [2, 128, 0x66, 0x0F38, 1], 0x92, :mrmxmm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 128 }
999
+ addop_vex('vgatherdpd', [2, 256, 0x66, 0x0F38, 1], 0x92, :mrmymm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 256 }
1000
+ addop_vex('vgatherqps', [2, 128, 0x66, 0x0F38, 0], 0x93, :mrmxmm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 128 }
1001
+ addop_vex('vgatherqps', [2, 256, 0x66, 0x0F38, 0], 0x93, :mrmymm) { |o| o.props[:argsz] = 32 ; o.props[:mrmvex] = 256 }
1002
+ addop_vex('vgatherqpd', [2, 128, 0x66, 0x0F38, 1], 0x93, :mrmxmm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 128 }
1003
+ addop_vex('vgatherqpd', [2, 256, 0x66, 0x0F38, 1], 0x93, :mrmymm) { |o| o.props[:argsz] = 64 ; o.props[:mrmvex] = 256 }
1004
+ end
1005
+
1006
+ def init_fma_only
1007
+ init_cpu_constants
1008
+
1009
+ [['vfmaddsub', 'p', 0x86],
1010
+ ['vfmsubadd', 'p', 0x87],
1011
+ ['vfmadd', 'p', 0x88],
1012
+ ['vfmadd', 's', 0x89],
1013
+ ['vfmsub', 'p', 0x8A],
1014
+ ['vfmsub', 's', 0x8B],
1015
+ ['vfnmadd', 'p', 0x8C],
1016
+ ['vfnmadd', 's', 0x8D],
1017
+ ['vfnmsub', 'p', 0x8E],
1018
+ ['vfnmsub', 's', 0x8F]].each { |n1, n2, bin|
1019
+ addop_vex n1 + '132' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x10, :mrmxmm
1020
+ addop_vex n1 + '132' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x10, :mrmymm
1021
+ addop_vex n1 + '132' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x10, :mrmxmm
1022
+ addop_vex n1 + '132' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x10, :mrmymm
1023
+ addop_vex n1 + '213' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x20, :mrmxmm
1024
+ addop_vex n1 + '213' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x20, :mrmymm
1025
+ addop_vex n1 + '213' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x20, :mrmxmm
1026
+ addop_vex n1 + '213' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x20, :mrmymm
1027
+ addop_vex n1 + '231' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x30, :mrmxmm
1028
+ addop_vex n1 + '231' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x30, :mrmymm
1029
+ addop_vex n1 + '231' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x30, :mrmxmm
1030
+ addop_vex n1 + '231' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x30, :mrmymm
1031
+
1032
+ # pseudo-opcodes aliases (swap arg0/arg1)
1033
+ addop_vex(n1 + '312' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x10, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1034
+ addop_vex(n1 + '312' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x10, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1035
+ addop_vex(n1 + '312' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x10, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1036
+ addop_vex(n1 + '312' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x10, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1037
+ addop_vex(n1 + '123' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x20, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1038
+ addop_vex(n1 + '123' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x20, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1039
+ addop_vex(n1 + '123' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x20, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1040
+ addop_vex(n1 + '123' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x20, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1041
+ addop_vex(n1 + '321' + n2 + 's', [1, 128, 0x66, 0x0F38, 0], bin | 0x30, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1042
+ addop_vex(n1 + '321' + n2 + 's', [1, 256, 0x66, 0x0F38, 0], bin | 0x30, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1043
+ addop_vex(n1 + '321' + n2 + 'd', [1, 128, 0x66, 0x0F38, 1], bin | 0x30, :mrmxmm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1044
+ addop_vex(n1 + '321' + n2 + 'd', [1, 256, 0x66, 0x0F38, 1], bin | 0x30, :mrmymm) { |o| o.args[0, 2] = o.args[0, 2].reverse }
1045
+ }
1046
+ end
1047
+
1048
+ #
1049
+ # CPU family dependencies
1050
+ #
1051
+
1052
+ def init_386_common
1053
+ init_386_common_only
1054
+ end
1055
+
1056
+ def init_386
1057
+ init_386_common
1058
+ init_386_only
1059
+ end
1060
+
1061
+ def init_387
1062
+ init_387_only
1063
+ end
1064
+
1065
+ def init_486
1066
+ init_386
1067
+ init_387
1068
+ init_486_only
1069
+ end
1070
+
1071
+ def init_pentium
1072
+ init_486
1073
+ init_pentium_only
1074
+ end
1075
+
1076
+ def init_3dnow
1077
+ init_pentium
1078
+ init_3dnow_only
1079
+ end
1080
+
1081
+ def init_p6
1082
+ init_pentium
1083
+ init_p6_only
1084
+ end
1085
+
1086
+ def init_sse
1087
+ init_p6
1088
+ init_sse_only
1089
+ end
1090
+
1091
+ def init_sse2
1092
+ init_sse
1093
+ init_sse2_only
1094
+ end
1095
+
1096
+ def init_sse3
1097
+ init_sse2
1098
+ init_sse3_only
1099
+ end
1100
+
1101
+ def init_ssse3
1102
+ init_sse3
1103
+ init_ssse3_only
1104
+ end
1105
+
1106
+ def init_sse41
1107
+ init_ssse3
1108
+ init_sse41_only
1109
+ end
1110
+
1111
+ def init_sse42
1112
+ init_sse41
1113
+ init_sse42_only
1114
+ end
1115
+
1116
+ def init_avx
1117
+ init_sse42
1118
+ init_avx_only
1119
+ end
1120
+
1121
+ def init_avx2
1122
+ init_avx
1123
+ init_fma_only
1124
+ init_avx2_only
1125
+ end
1126
+
1127
+ def init_all
1128
+ init_avx2
1129
+ init_3dnow_only
1130
+ init_vmx_only
1131
+ init_aesni_only
1132
+ end
1133
+
1134
+ alias init_latest init_all
1135
+
1136
+
1137
+ #
1138
+ # addop_* macros
1139
+ #
1140
+
1141
+ def addop_macro1(name, num, *props)
1142
+ addop name, [(num << 3) | 4], nil, {:w => [0, 0]}, :reg_eax, :i, *props
1143
+ addop(name, [num << 3], :mrmw, {:d => [0, 1]}) { |o| o.args.reverse! }
1144
+ addop name, [0x80], num, {:w => [0, 0], :s => [0, 1]}, :i, *props
1145
+ end
1146
+ def addop_macro2(name, num)
1147
+ addop name, [0x0F, 0xBA], (4 | num), :u8
1148
+ addop(name, [0x0F, 0xA3 | (num << 3)], :mrm) { |op| op.args.reverse! }
1149
+ end
1150
+ def addop_macro3(name, num)
1151
+ addop name, [0xD0], num, {:w => [0, 0]}, :imm_val1
1152
+ addop name, [0xD2], num, {:w => [0, 0]}, :reg_cl
1153
+ addop name, [0xC0], num, {:w => [0, 0]}, :u8
1154
+ end
1155
+
1156
+ def addop_macrotttn(name, bin, hint, *props, &blk)
1157
+ [%w{o}, %w{no}, %w{b nae c}, %w{nb ae nc},
1158
+ %w{z e}, %w{nz ne}, %w{be na}, %w{nbe a},
1159
+ %w{s}, %w{ns}, %w{p pe}, %w{np po},
1160
+ %w{l nge}, %w{nl ge}, %w{le ng}, %w{nle g}].each_with_index { |e, i|
1161
+ b = bin.dup
1162
+ if b[0] == 0x0F
1163
+ b[1] |= i
1164
+ else
1165
+ b[0] |= i
1166
+ end
1167
+
1168
+ e.each { |k| addop(name + k, b.dup, hint, *props, &blk) }
1169
+ }
1170
+ end
1171
+
1172
+ def addop_macrostr(name, bin, type)
1173
+ # addop(name, bin.dup, {:w => [0, 0]}) { |o| o.props[type] = true } # TODO allow segment override
1174
+ addop(name+'b', bin) { |o| o.props[:opsz] = 16 ; o.props[type] = true }
1175
+ addop(name+'b', bin) { |o| o.props[:opsz] = 32 ; o.props[type] = true }
1176
+ bin = bin.dup
1177
+ bin[0] |= 1
1178
+ addop(name+'w', bin) { |o| o.props[:opsz] = 16 ; o.props[type] = true }
1179
+ addop(name+'d', bin) { |o| o.props[:opsz] = 32 ; o.props[type] = true }
1180
+ end
1181
+
1182
+ def addop_macrofpu1(name, n)
1183
+ addop(name, [0xD8, n<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 32 }
1184
+ addop(name, [0xDC, n<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 64 }
1185
+ addop(name, [0xD8, 0xC0|(n<<3)], :regfp, {:d => [0, 2]}) { |o| o.args.reverse! }
1186
+ end
1187
+ def addop_macrofpu2(name, n, n2=0)
1188
+ addop(name, [0xDE|n2, n<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 16 }
1189
+ addop(name, [0xDA|n2, n<<3], :modrmA, :regfp0) { |o| o.props[:argsz] = 32 }
1190
+ end
1191
+ def addop_macrofpu3(name, n)
1192
+ addop_macrofpu2 name, n, 1
1193
+ addop(name, [0xDF, 0x28|(n<<3)], :modrmA, :regfp0) { |o| o.props[:argsz] = 64 }
1194
+ end
1195
+
1196
+ def addop_macrogg(ggrng, name, bin, *args, &blk)
1197
+ ggoff = 1
1198
+ ggoff = 2 if bin[1] == 0x38 or bin[1] == 0x3A
1199
+ ggrng.each { |gg|
1200
+ bindup = bin.dup
1201
+ bindup[ggoff] |= gg
1202
+ sfx = %w(b w d q)[gg]
1203
+ addop name+sfx, bindup, *args, &blk
1204
+ }
1205
+ end
1206
+
1207
+ def addop_macrossps(name, bin, hint, *a)
1208
+ addop name, bin.dup, hint, *a
1209
+ addop(name.sub(/ps$/, 'ss'), bin.dup, hint, *a) { |o| o.props[:needpfx] = 0xF3 }
1210
+ end
1211
+
1212
+ def addop_macrosdpd(name, bin, hint, *a)
1213
+ addop(name, bin.dup, hint, *a) { |o| o.props[:needpfx] = 0x66 }
1214
+ addop(name.sub(/pd$/, 'sd'), bin.dup, hint, *a) { |o| o.props[:needpfx] = 0xF2 }
1215
+ end
1216
+
1217
+ # special ret (iret/retf), that still default to 32b mode in x64
1218
+ def addop_macroret(name, bin, *args)
1219
+ addop(name + '.i32', bin.dup, nil, :stopexec, :setip, *args) { |o| o.props[:opsz] = 32 }
1220
+ addop(name + '.i16', bin.dup, nil, :stopexec, :setip, *args) { |o| o.props[:opsz] = 16 } if name != 'sysret'
1221
+ addop(name, bin.dup, nil, :stopexec, :setip, *args) { |o| o.props[:opsz] = @size }
1222
+ end
1223
+
1224
+ # add an AVX instruction needing a VEX prefix (c4h/c5h)
1225
+ # the prefix is hardcoded
1226
+ def addop_vex(name, vexspec, bin, *args)
1227
+ argnr = vexspec.shift
1228
+ argt = vexspec.shift if argnr and vexspec.first.kind_of?(::Symbol)
1229
+ l = vexspec.shift
1230
+ pfx = vexspec.shift
1231
+ of = vexspec.shift
1232
+ w = vexspec.shift
1233
+ argt ||= (l == 128 ? :vexvxmm : :vexvymm)
1234
+
1235
+ lpp = ((l >> 8) << 2) | [nil, 0x66, 0xF3, 0xF2].index(pfx)
1236
+ mmmmm = [nil, 0x0F, 0x0F38, 0x0F3A].index(of)
1237
+
1238
+ c4bin = [0xC4, mmmmm, lpp, bin]
1239
+ c4bin[1] |= 1 << 7 if @size != 64
1240
+ c4bin[1] |= 1 << 6 if @size != 64
1241
+ c4bin[2] |= 1 << 7 if w == 1
1242
+ c4bin[2] |= 0xF << 3 if not argnr
1243
+
1244
+ addop(name, c4bin, *args) { |o|
1245
+ o.args.insert(argnr, argt) if argnr
1246
+
1247
+ o.fields[:vex_r] = [1, 7] if @size == 64
1248
+ o.fields[:vex_x] = [1, 6] if @size == 64
1249
+ o.fields[:vex_b] = [1, 5]
1250
+ o.fields[:vex_w] = [2, 7] if not w
1251
+ o.fields[:vex_vvvv] = [2, 3] if argnr
1252
+
1253
+ yield o if block_given?
1254
+ }
1255
+
1256
+ return if w == 1 or mmmmm != 1
1257
+
1258
+ c5bin = [0xC5, lpp, bin]
1259
+ c5bin[1] |= 1 << 7 if @size != 64
1260
+ c5bin[1] |= 0xF << 3 if not argnr
1261
+
1262
+ addop(name, c5bin, *args) { |o|
1263
+ o.args.insert(argnr, argt) if argnr
1264
+
1265
+ o.fields[:vex_r] = [1, 7] if @size == 64
1266
+ o.fields[:vex_vvvv] = [1, 3] if argnr
1267
+
1268
+ yield o if block_given?
1269
+ }
1270
+ end
1271
+
1272
+ # helper function: creates a new Opcode based on the arguments, eventually
1273
+ # yields it for further customisation, and append it to the instruction set
1274
+ # is responsible of the creation of disambiguating opcodes if necessary (:s flag hardcoding)
1275
+ def addop(name, bin, hint=nil, *argprops)
1276
+ fields = (argprops.first.kind_of?(Hash) ? argprops.shift : {})
1277
+ op = Opcode.new name, bin
1278
+ op.fields.replace fields
1279
+
1280
+ case hint
1281
+ when nil
1282
+
1283
+ when :mrm, :mrmw, :mrmA
1284
+ op.fields[:reg] = [bin.length, 3]
1285
+ op.fields[:modrm] = [bin.length, 0]
1286
+ op.fields[:w] = [bin.length - 1, 0] if hint == :mrmw
1287
+ argprops.unshift :reg, :modrm
1288
+ argprops << :modrmA if hint == :mrmA
1289
+ op.bin << 0
1290
+ when :reg
1291
+ op.fields[:reg] = [bin.length-1, 0]
1292
+ argprops.unshift :reg
1293
+ when :regfp
1294
+ op.fields[:regfp] = [bin.length-1, 0]
1295
+ argprops.unshift :regfp, :regfp0
1296
+ when :modrmA
1297
+ op.fields[:modrm] = [bin.length-1, 0]
1298
+ argprops << :modrm << :modrmA
1299
+
1300
+ when Integer # mod/m, reg == opcode extension = hint
1301
+ op.fields[:modrm] = [bin.length, 0]
1302
+ op.bin << (hint << 3)
1303
+ argprops.unshift :modrm
1304
+
1305
+ when :mrmmmx
1306
+ op.fields[:regmmx] = [bin.length, 3]
1307
+ op.fields[:modrm] = [bin.length, 0]
1308
+ bin << 0
1309
+ argprops.unshift :regmmx, :modrmmmx
1310
+ when :mrmxmm
1311
+ op.fields[:regxmm] = [bin.length, 3]
1312
+ op.fields[:modrm] = [bin.length, 0]
1313
+ bin << 0
1314
+ argprops.unshift :regxmm, :modrmxmm
1315
+ when :mrmymm
1316
+ op.fields[:regymm] = [bin.length, 3]
1317
+ op.fields[:modrm] = [bin.length, 0]
1318
+ bin << 0
1319
+ argprops.unshift :regymm, :modrmymm
1320
+ else
1321
+ raise SyntaxError, "invalid hint #{hint.inspect} for #{name}"
1322
+ end
1323
+
1324
+ argprops.each { |a|
1325
+ op.props[a] = true if @valid_props[a]
1326
+ op.args << a if @valid_args[a]
1327
+ }
1328
+
1329
+ yield op if block_given?
1330
+
1331
+ if $DEBUG
1332
+ argprops -= @valid_props.keys + @valid_args.keys
1333
+ raise "Invalid opcode definition: #{name}: unknown #{argprops.inspect}" unless argprops.empty?
1334
+
1335
+ argprops = (op.props.keys - @valid_props.keys) + (op.args - @valid_args.keys) + (op.fields.keys - @fields_mask.keys)
1336
+ raise "Invalid opcode customisation: #{name}: #{argprops.inspect}" unless argprops.empty?
1337
+ end
1338
+
1339
+ addop_post(op)
1340
+ end
1341
+
1342
+ # this recursive method is in charge of Opcode duplication (eg to hardcode some flag)
1343
+ def addop_post(op)
1344
+ if df = op.fields.delete(:d)
1345
+ # hardcode the bit
1346
+ dop = op.dup
1347
+ addop_post dop
1348
+
1349
+ op.bin[df[0]] |= 1 << df[1]
1350
+ op.args.reverse!
1351
+ addop_post op
1352
+
1353
+ return
1354
+ elsif wf = op.fields.delete(:w)
1355
+ # hardcode the bit
1356
+ dop = op.dup
1357
+ dop.props[:argsz] = 8
1358
+ # 64-bit w=0 s=1 => UD
1359
+ dop.fields.delete(:s) if @size == 64
1360
+ addop_post dop
1361
+
1362
+ op.bin[wf[0]] |= 1 << wf[1]
1363
+ addop_post op
1364
+
1365
+ return
1366
+ elsif sf = op.fields.delete(:s)
1367
+ # add explicit choice versions, with lower precedence (so that disassembling will return the general version)
1368
+ # eg "jmp", "jmp.i8", "jmp.i"
1369
+ # also hardcode the bit
1370
+ op32 = op
1371
+ addop_post op32
1372
+
1373
+ op8 = op.dup
1374
+ op8.bin[sf[0]] |= 1 << sf[1]
1375
+ op8.args.map! { |arg| arg == :i ? :i8 : arg }
1376
+ addop_post op8
1377
+
1378
+ op32 = op32.dup
1379
+ op32.name << '.i'
1380
+ addop_post op32
1381
+
1382
+ op8 = op8.dup
1383
+ op8.name << '.i8'
1384
+ addop_post op8
1385
+
1386
+ return
1387
+ elsif op.args.first == :regfp0
1388
+ dop = op.dup
1389
+ dop.args.delete :regfp0
1390
+ addop_post dop
1391
+ end
1392
+
1393
+ if op.props[:needpfx]
1394
+ @opcode_list.unshift op
1395
+ else
1396
+ @opcode_list << op
1397
+ end
1398
+
1399
+ if (op.args == [:i] or op.args == [:farptr] or op.name == 'ret') and op.name !~ /\.i/
1400
+ # define opsz-override version for ambiguous opcodes
1401
+ op16 = op.dup
1402
+ op16.name << '.i16'
1403
+ op16.props[:opsz] = 16
1404
+ @opcode_list << op16
1405
+ op32 = op.dup
1406
+ op32.name << '.i32'
1407
+ op32.props[:opsz] = 32
1408
+ @opcode_list << op32
1409
+ elsif op.props[:strop] or op.props[:stropz] or op.args.include? :mrm_imm or
1410
+ op.args.include? :modrm or op.name =~ /loop|xlat/
1411
+ # define adsz-override version for ambiguous opcodes (TODO allow movsd edi / movsd di syntax)
1412
+ # XXX loop pfx 67 = eip+cx, 66 = ip+ecx
1413
+ op16 = op.dup
1414
+ op16.name << '.a16'
1415
+ op16.props[:adsz] = 16
1416
+ @opcode_list << op16
1417
+ op32 = op.dup
1418
+ op32.name << '.a32'
1419
+ op32.props[:adsz] = 32
1420
+ @opcode_list << op32
1421
+ end
1422
+ end
1423
+ end
1424
+ end