metasm 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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