metasm 1.0.0

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 (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. metadata +255 -0
@@ -0,0 +1,872 @@
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/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, :seg2 => 3, :seg3 => 7,
15
+ :regfp => 7, :regmmx => 7, :regxmm => 7
16
+ @fields_mask[:seg2A] = @fields_mask[:seg2]
17
+ @fields_mask[:seg3A] = @fields_mask[:seg3]
18
+ @fields_mask[:modrmA] = @fields_mask[:modrm]
19
+
20
+ @valid_args.concat [:i, :i8, :u8, :u16, :reg, :seg2, :seg2A,
21
+ :seg3, :seg3A, :eeec, :eeed, :modrm, :modrmA, :mrm_imm,
22
+ :farptr, :imm_val1, :imm_val3, :reg_cl, :reg_eax,
23
+ :reg_dx, :regfp, :regfp0, :modrmmmx, :regmmx,
24
+ :modrmxmm, :regxmm] - @valid_args
25
+
26
+ @valid_props.concat [:strop, :stropz, :opsz, :argsz, :setip,
27
+ :stopexec, :saveip, :unsigned_imm, :random, :needpfx,
28
+ :xmmx] - @valid_props
29
+ end
30
+
31
+ # only most common instructions from the 386 instruction set
32
+ # inexhaustive list :
33
+ # no aaa, arpl, mov crX, call/jmp/ret far, in/out, bts, xchg...
34
+ def init_386_common_only
35
+ init_cpu_constants
36
+
37
+ addop_macro1 'adc', 2
38
+ addop_macro1 'add', 0
39
+ addop_macro1 'and', 4, :u
40
+ addop 'bswap', [0x0F, 0xC8], :reg
41
+ addop 'call', [0xE8], nil, {}, :stopexec, :setip, :i, :saveip
42
+ addop 'call', [0xFF], 2, {}, :stopexec, :setip, :saveip
43
+ addop('cbw', [0x98]) { |o| o.props[:opsz] = 16 }
44
+ addop('cwde', [0x98]) { |o| o.props[:opsz] = 32 }
45
+ addop('cdqe', [0x98]) { |o| o.props[:opsz] = 64 }
46
+ addop('cwd', [0x99]) { |o| o.props[:opsz] = 16 }
47
+ addop('cdq', [0x99]) { |o| o.props[:opsz] = 32 }
48
+ addop('cqo', [0x99]) { |o| o.props[:opsz] = 64 }
49
+ addop_macro1 'cmp', 7
50
+ addop_macrostr 'cmps', [0xA6], :stropz
51
+ addop 'dec', [0x48], :reg
52
+ addop 'dec', [0xFE], 1, {:w => [0, 0]}
53
+ addop 'div', [0xF6], 6, {:w => [0, 0]}
54
+ addop 'enter', [0xC8], nil, {}, :u16, :u8
55
+ addop 'idiv', [0xF6], 7, {:w => [0, 0]}
56
+ addop 'imul', [0xF6], 5, {:w => [0, 0]}, :reg_eax
57
+ addop 'imul', [0x0F, 0xAF], :mrm
58
+ addop 'imul', [0x69], :mrm, {:s => [0, 1]}, :i
59
+ addop 'inc', [0x40], :reg
60
+ addop 'inc', [0xFE], 0, {:w => [0, 0]}
61
+ addop 'int', [0xCC], nil, {}, :imm_val3, :stopexec
62
+ addop 'int', [0xCD], nil, {}, :u8
63
+ addop_macrotttn 'j', [0x70], nil, {}, :setip, :i8
64
+ addop_macrotttn 'j', [0x0F, 0x80], nil, {}, :setip, :i
65
+ addop 'jmp', [0xE9], nil, {:s => [0, 1]}, :setip, :i, :stopexec
66
+ addop 'jmp', [0xFF], 4, {}, :setip, :stopexec
67
+ addop 'lea', [0x8D], :mrmA
68
+ addop 'leave', [0xC9]
69
+ addop_macrostr 'lods', [0xAC], :strop
70
+ addop 'loop', [0xE2], nil, {}, :setip, :i8
71
+ addop 'loopz', [0xE1], nil, {}, :setip, :i8
72
+ addop 'loope', [0xE1], nil, {}, :setip, :i8
73
+ addop 'loopnz',[0xE0], nil, {}, :setip, :i8
74
+ addop 'loopne',[0xE0], nil, {}, :setip, :i8
75
+ addop 'mov', [0xA0], nil, {:w => [0, 0], :d => [0, 1]}, :mrm_imm, :reg_eax
76
+ addop 'mov', [0x88], :mrmw,{:d => [0, 1]}
77
+ addop 'mov', [0xB0], :reg, {:w => [0, 3]}, :u
78
+ addop 'mov', [0xC6], 0, {:w => [0, 0]}, :u
79
+ addop_macrostr 'movs', [0xA4], :strop
80
+ addop 'movsx', [0x0F, 0xBE], :mrmw
81
+ addop 'movzx', [0x0F, 0xB6], :mrmw
82
+ addop 'mul', [0xF6], 4, {:w => [0, 0]}
83
+ addop 'neg', [0xF6], 3, {:w => [0, 0]}
84
+ addop 'nop', [0x90]
85
+ addop 'not', [0xF6], 2, {:w => [0, 0]}
86
+ addop_macro1 'or', 1, :u
87
+ addop 'pop', [0x58], :reg
88
+ addop 'pop', [0x8F], 0
89
+ addop 'push', [0x50], :reg
90
+ addop 'push', [0xFF], 6
91
+ addop 'push', [0x68], nil, {:s => [0, 1]}, :u
92
+ addop 'ret', [0xC3], nil, {}, :stopexec, :setip
93
+ addop 'ret', [0xC2], nil, {}, :stopexec, :u16, :setip
94
+ addop_macro3 'rol', 0
95
+ addop_macro3 'ror', 1
96
+ addop_macro3 'sar', 7
97
+ addop_macro1 'sbb', 3
98
+ addop_macrostr 'scas', [0xAE], :stropz
99
+ addop_macrotttn('set', [0x0F, 0x90], 0) { |o| o.props[:argsz] = 8 }
100
+ addop_macrotttn('set', [0x0F, 0x90], :mrm) { |o| o.props[:argsz] = 8 ; o.args.reverse! } # :reg field is unused
101
+ addop_macro3 'shl', 4
102
+ addop_macro3 'sal', 6
103
+ addop 'shld', [0x0F, 0xA4], :mrm, {}, :u8
104
+ addop 'shld', [0x0F, 0xA5], :mrm, {}, :reg_cl
105
+ addop_macro3 'shr', 5
106
+ addop 'shrd', [0x0F, 0xAC], :mrm, {}, :u8
107
+ addop 'shrd', [0x0F, 0xAD], :mrm, {}, :reg_cl
108
+ addop_macrostr 'stos', [0xAA], :strop
109
+ addop_macro1 'sub', 5
110
+ addop 'test', [0x84], :mrmw
111
+ addop 'test', [0xA8], nil, {:w => [0, 0]}, :reg_eax, :u
112
+ addop 'test', [0xF6], 0, {:w => [0, 0]}, :u
113
+ addop 'xchg', [0x90], :reg, {}, :reg_eax
114
+ addop('xchg', [0x90], :reg, {}, :reg_eax) { |o| o.args.reverse! } # xchg eax, ebx == xchg ebx, eax)
115
+ addop 'xchg', [0x86], :mrmw
116
+ addop('xchg', [0x86], :mrmw) { |o| o.args.reverse! }
117
+ addop_macro1 'xor', 6, :u
118
+ end
119
+
120
+ def init_386_only
121
+ init_cpu_constants
122
+
123
+ addop 'aaa', [0x37]
124
+ addop 'aad', [0xD5, 0x0A]
125
+ addop 'aam', [0xD4, 0x0A]
126
+ addop 'aas', [0x3F]
127
+ addop('arpl', [0x63], :mrm) { |o| o.props[:argsz] = 16 ; o.args.reverse! }
128
+ addop 'bound', [0x62], :mrmA
129
+ addop 'bsf', [0x0F, 0xBC], :mrm
130
+ addop 'bsr', [0x0F, 0xBD], :mrm
131
+ addop_macro2 'bt' , 0
132
+ addop_macro2 'btc', 3
133
+ addop_macro2 'btr', 2
134
+ addop_macro2 'bts', 1
135
+ addop 'call', [0x9A], nil, {}, :stopexec, :setip, :farptr, :saveip
136
+ addop 'callf', [0x9A], nil, {}, :stopexec, :setip, :farptr, :saveip
137
+ addop 'callf', [0xFF], 3, {}, :stopexec, :setip, :saveip
138
+ addop 'clc', [0xF8]
139
+ addop 'cld', [0xFC]
140
+ addop 'cli', [0xFA]
141
+ addop 'clts', [0x0F, 0x06]
142
+ addop 'cmc', [0xF5]
143
+ addop('cmpxchg',[0x0F, 0xB0], :mrmw) { |o| o.args.reverse! }
144
+ addop 'cpuid', [0x0F, 0xA2]
145
+ addop 'daa', [0x27]
146
+ addop 'das', [0x2F]
147
+ addop 'hlt', [0xF4], nil, {}, :stopexec
148
+ addop 'in', [0xE4], nil, {:w => [0, 0]}, :reg_eax, :u8
149
+ addop 'in', [0xE4], nil, {:w => [0, 0]}, :u8
150
+ addop 'in', [0xEC], nil, {:w => [0, 0]}, :reg_eax, :reg_dx
151
+ addop 'in', [0xEC], nil, {:w => [0, 0]}, :reg_eax
152
+ addop 'in', [0xEC], nil, {:w => [0, 0]}
153
+ addop_macrostr 'ins', [0x6C], :strop
154
+ addop 'into', [0xCE]
155
+ addop 'invd', [0x0F, 0x08]
156
+ addop 'invlpg',[0x0F, 0x01, 7<<3], :modrmA
157
+ addop 'iret', [0xCF], nil, {}, :stopexec, :setip
158
+ addop 'iretd', [0xCF], nil, {}, :stopexec, :setip
159
+ addop('jcxz', [0xE3], nil, {}, :setip, :i8) { |o| o.props[:opsz] = 16 }
160
+ addop('jecxz', [0xE3], nil, {}, :setip, :i8) { |o| o.props[:opsz] = 32 }
161
+ addop 'jmp', [0xEA], nil, {}, :farptr, :setip, :stopexec
162
+ addop 'jmpf', [0xEA], nil, {}, :farptr, :setip, :stopexec
163
+ addop 'jmpf', [0xFF], 5, {}, :stopexec, :setip # reg ?
164
+ addop 'lahf', [0x9F]
165
+ addop 'lar', [0x0F, 0x02], :mrm
166
+ addop 'lds', [0xC5], :mrmA
167
+ addop 'les', [0xC4], :mrmA
168
+ addop 'lfs', [0x0F, 0xB4], :mrmA
169
+ addop 'lgs', [0x0F, 0xB5], :mrmA
170
+ addop 'lgdt', [0x0F, 0x01], 2
171
+ addop 'lidt', [0x0F, 0x01, 3<<3], :modrmA
172
+ addop 'lldt', [0x0F, 0x00], 2
173
+ addop 'lmsw', [0x0F, 0x01], 6
174
+ # prefix addop 'lock', [0xF0]
175
+ addop 'lsl', [0x0F, 0x03], :mrm
176
+ addop 'lss', [0x0F, 0xB2], :mrmA
177
+ addop 'ltr', [0x0F, 0x00], 3
178
+ addop('mov', [0x0F, 0x20, 0xC0], :reg, {:d => [1, 1], :eeec => [2, 3]}, :eeec) { |op| op.args.reverse! }
179
+ addop('mov', [0x0F, 0x21, 0xC0], :reg, {:d => [1, 1], :eeed => [2, 3]}, :eeed) { |op| op.args.reverse! }
180
+ addop('mov', [0x8C], 0, {:d => [0, 1], :seg3 => [1, 3]}, :seg3) { |op| op.args.reverse! }
181
+ addop 'out', [0xE6], nil, {:w => [0, 0]}, :u8, :reg_eax
182
+ addop 'out', [0xE6], nil, {:w => [0, 0]}, :reg_eax, :u8
183
+ addop 'out', [0xE6], nil, {:w => [0, 0]}, :u8
184
+ addop 'out', [0xEE], nil, {:w => [0, 0]}, :reg_dx, :reg_eax
185
+ addop 'out', [0xEE], nil, {:w => [0, 0]}, :reg_eax, :reg_dx
186
+ addop 'out', [0xEE], nil, {:w => [0, 0]}, :reg_eax # implicit arguments
187
+ addop 'out', [0xEE], nil, {:w => [0, 0]}
188
+ addop_macrostr 'outs', [0x6E], :strop
189
+ addop 'pop', [0x07], nil, {:seg2A => [0, 3]}, :seg2A
190
+ addop 'pop', [0x0F, 0x81], nil, {:seg3A => [1, 3]}, :seg3A
191
+ addop('popa', [0x61]) { |o| o.props[:opsz] = 16 }
192
+ addop('popad', [0x61]) { |o| o.props[:opsz] = 32 }
193
+ addop('popf', [0x9D]) { |o| o.props[:opsz] = 16 }
194
+ addop('popfd', [0x9D]) { |o| o.props[:opsz] = 32 }
195
+ addop 'push', [0x06], nil, {:seg2 => [0, 3]}, :seg2
196
+ addop 'push', [0x0F, 0x80], nil, {:seg3A => [1, 3]}, :seg3A
197
+ addop('pusha', [0x60]) { |o| o.props[:opsz] = 16 }
198
+ addop('pushad',[0x60]) { |o| o.props[:opsz] = 32 }
199
+ addop('pushf', [0x9C]) { |o| o.props[:opsz] = 16 }
200
+ addop('pushfd',[0x9C]) { |o| o.props[:opsz] = 32 }
201
+ addop_macro3 'rcl', 2
202
+ addop_macro3 'rcr', 3
203
+ addop 'rdmsr', [0x0F, 0x32]
204
+ addop 'rdpmc', [0x0F, 0x33]
205
+ addop 'rdtsc', [0x0F, 0x31], nil, {}, :random
206
+ addop 'retf', [0xCB], nil, {}, :stopexec, :setip
207
+ addop 'retf', [0xCA], nil, {}, :stopexec, :u16, :setip
208
+ addop 'rsm', [0x0F, 0xAA], nil, {}, :stopexec
209
+ addop 'sahf', [0x9E]
210
+ addop 'sgdt', [0x0F, 0x01, 0<<3], :modrmA
211
+ addop 'sidt', [0x0F, 0x01, 1<<3], :modrmA
212
+ addop 'sldt', [0x0F, 0x00], 0
213
+ addop 'smsw', [0x0F, 0x01], 4
214
+ addop 'stc', [0xF9]
215
+ addop 'std', [0xFD]
216
+ addop 'sti', [0xFB]
217
+ addop 'str', [0x0F, 0x00], 1
218
+ addop 'ud2', [0x0F, 0x0B]
219
+ addop 'verr', [0x0F, 0x00], 4
220
+ addop 'verw', [0x0F, 0x00], 5
221
+ addop 'wait', [0x9B]
222
+ addop 'wbinvd',[0x0F, 0x09]
223
+ addop 'wrmsr', [0x0F, 0x30]
224
+ addop('xadd', [0x0F, 0xC0], :mrmw) { |o| o.args.reverse! }
225
+ addop 'xlat', [0xD7]
226
+
227
+ # pfx: addrsz = 0x67, lock = 0xf0, opsz = 0x66, repnz = 0xf2, rep/repz = 0xf3
228
+ # cs/nojmp = 0x2E, ds/jmp = 0x3E, es = 0x26, fs = 0x64, gs = 0x65, ss = 0x36
229
+ # undocumented opcodes
230
+ # TODO put these in the right place (486/P6/...)
231
+ addop 'aam', [0xD4], nil, {}, :u8
232
+ addop 'aad', [0xD5], nil, {}, :u8
233
+ addop 'setalc', [0xD6]
234
+ addop 'salc', [0xD6]
235
+ addop 'icebp', [0xF1]
236
+ #addop 'loadall',[0x0F, 0x07] # conflict with syscall
237
+ addop 'ud2', [0x0F, 0xB9]
238
+ addop 'umov', [0x0F, 0x10], :mrmw,{:d => [1, 1]}
239
+ end
240
+
241
+ def init_387_only
242
+ init_cpu_constants
243
+
244
+ addop 'f2xm1', [0xD9, 0xF0]
245
+ addop 'fabs', [0xD9, 0xE1]
246
+ addop_macrofpu1 'fadd', 0
247
+ addop 'faddp', [0xDE, 0xC0], :regfp
248
+ addop 'faddp', [0xDE, 0xC1]
249
+ addop('fbld', [0xDF, 4<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 80 }
250
+ addop('fbstp', [0xDF, 6<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 80 }
251
+ addop 'fchs', [0xD9, 0xE0], nil, {}, :regfp0
252
+ addop 'fnclex', [0xDB, 0xE2]
253
+ addop_macrofpu1 'fcom', 2
254
+ addop_macrofpu1 'fcomp', 3
255
+ addop 'fcompp',[0xDE, 0xD9]
256
+ addop 'fcomip',[0xDF, 0xF0], :regfp
257
+ addop 'fcos', [0xD9, 0xFF], nil, {}, :regfp0
258
+ addop 'fdecstp', [0xD9, 0xF6]
259
+ addop_macrofpu1 'fdiv', 6
260
+ addop_macrofpu1 'fdivr', 7
261
+ addop 'fdivp', [0xDE, 0xF8], :regfp
262
+ addop 'fdivp', [0xDE, 0xF9]
263
+ addop 'fdivrp',[0xDE, 0xF0], :regfp
264
+ addop 'fdivrp',[0xDE, 0xF1]
265
+ addop 'ffree', [0xDD, 0xC0], nil, {:regfp => [1, 0]}, :regfp
266
+ addop_macrofpu2 'fiadd', 0
267
+ addop_macrofpu2 'fimul', 1
268
+ addop_macrofpu2 'ficom', 2
269
+ addop_macrofpu2 'ficomp',3
270
+ addop_macrofpu2 'fisub', 4
271
+ addop_macrofpu2 'fisubr',5
272
+ addop_macrofpu2 'fidiv', 6
273
+ addop_macrofpu2 'fidivr',7
274
+ addop 'fincstp', [0xD9, 0xF7]
275
+ addop 'fninit', [0xDB, 0xE3]
276
+ addop_macrofpu2 'fist', 2, 1
277
+ addop_macrofpu3 'fild', 0
278
+ addop_macrofpu3 'fistp',3
279
+ addop('fld', [0xD9, 0<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 32 }
280
+ addop('fld', [0xDD, 0<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 64 }
281
+ addop('fld', [0xDB, 5<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 80 }
282
+ addop 'fld', [0xD9, 0xC0], :regfp
283
+
284
+ addop('fldcw', [0xD9, 5<<3], :modrmA) { |o| o.props[:argsz] = 16 }
285
+ addop 'fldenv', [0xD9, 4<<3], :modrmA
286
+ addop 'fld1', [0xD9, 0xE8]
287
+ addop 'fldl2t', [0xD9, 0xE9]
288
+ addop 'fldl2e', [0xD9, 0xEA]
289
+ addop 'fldpi', [0xD9, 0xEB]
290
+ addop 'fldlg2', [0xD9, 0xEC]
291
+ addop 'fldln2', [0xD9, 0xED]
292
+ addop 'fldz', [0xD9, 0xEE]
293
+ addop_macrofpu1 'fmul', 1
294
+ addop 'fmulp', [0xDE, 0xC8], :regfp
295
+ addop 'fmulp', [0xDE, 0xC9]
296
+ addop 'fnop', [0xD9, 0xD0]
297
+ addop 'fpatan', [0xD9, 0xF3]
298
+ addop 'fprem', [0xD9, 0xF8]
299
+ addop 'fprem1', [0xD9, 0xF5]
300
+ addop 'fptan', [0xD9, 0xF2]
301
+ addop 'frndint',[0xD9, 0xFC]
302
+ addop 'frstor', [0xDD, 4<<3], :modrmA
303
+ addop 'fnsave', [0xDD, 6<<3], :modrmA
304
+ addop('fnstcw', [0xD9, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 }
305
+ addop 'fnstenv',[0xD9, 6<<3], :modrmA
306
+ addop 'fnstsw', [0xDF, 0xE0]
307
+ addop('fnstsw', [0xDD, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 }
308
+ addop 'fscale', [0xD9, 0xFD]
309
+ addop 'fsin', [0xD9, 0xFE]
310
+ addop 'fsincos',[0xD9, 0xFB]
311
+ addop 'fsqrt', [0xD9, 0xFA]
312
+ addop('fst', [0xD9, 2<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 32 }
313
+ addop('fst', [0xDD, 2<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 64 }
314
+ addop 'fst', [0xD9, 0xD0], :regfp
315
+ addop('fstp', [0xD9, 3<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 32 }
316
+ addop('fstp', [0xDD, 3<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 64 }
317
+ addop('fstp', [0xDB, 7<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 80 }
318
+ addop 'fstp', [0xDD, 0xD8], :regfp
319
+ addop_macrofpu1 'fsub', 4
320
+ addop 'fsubp', [0xDE, 0xE8], :regfp
321
+ addop 'fsubp', [0xDE, 0xE9]
322
+ addop_macrofpu1 'fsubp', 5
323
+ addop 'fsubrp', [0xDE, 0xE0], :regfp
324
+ addop 'fsubrp', [0xDE, 0xE1]
325
+ addop 'ftst', [0xD9, 0xE4]
326
+ addop 'fucom', [0xDD, 0xE0], :regfp
327
+ addop 'fucomp', [0xDD, 0xE8], :regfp
328
+ addop 'fucompp',[0xDA, 0xE9]
329
+ addop 'fucomi', [0xDB, 0xE8], :regfp
330
+ addop 'fxam', [0xD9, 0xE5]
331
+ addop 'fxch', [0xD9, 0xC8], :regfp
332
+ addop 'fxtract',[0xD9, 0xF4]
333
+ addop 'fyl2x', [0xD9, 0xF1]
334
+ addop 'fyl2xp1',[0xD9, 0xF9]
335
+ # fwait prefix
336
+ addop 'fclex', [0x9B, 0xDB, 0xE2]
337
+ addop 'finit', [0x9B, 0xDB, 0xE3]
338
+ addop 'fsave', [0x9B, 0xDD, 6<<3], :modrmA
339
+ addop('fstcw', [0x9B, 0xD9, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 }
340
+ addop 'fstenv', [0x9B, 0xD9, 6<<3], :modrmA
341
+ addop 'fstsw', [0x9B, 0xDF, 0xE0]
342
+ addop('fstsw', [0x9B, 0xDD, 7<<3], :modrmA) { |o| o.props[:argsz] = 16 }
343
+ addop 'fwait', [0x9B]
344
+ end
345
+
346
+ def init_486_only
347
+ init_cpu_constants
348
+ # TODO add new segments (fs/gs) ?
349
+ end
350
+
351
+ def init_pentium_only
352
+ init_cpu_constants
353
+
354
+ addop 'cmpxchg8b', [0x0F, 0xC7], 1
355
+ # lock cmpxchg8b eax
356
+ #addop 'f00fbug', [0xF0, 0x0F, 0xC7, 0xC8]
357
+
358
+ # mmx
359
+ addop 'emms', [0x0F, 0x77]
360
+ addop('movd', [0x0F, 0x6E], :mrmmmx, {:d => [1, 4]}) { |o| o.args[o.args.index(:modrmmmx)] = :modrm ; o.args.reverse! }
361
+ addop('movq', [0x0F, 0x6F], :mrmmmx, {:d => [1, 4]}) { |o| o.args.reverse! }
362
+ addop 'packssdw', [0x0F, 0x6B], :mrmmmx
363
+ addop 'packsswb', [0x0F, 0x63], :mrmmmx
364
+ addop 'packuswb', [0x0F, 0x67], :mrmmmx
365
+ addop_macrogg 0..2, 'padd', [0x0F, 0xFC], :mrmmmx
366
+ addop_macrogg 0..1, 'padds', [0x0F, 0xEC], :mrmmmx
367
+ addop_macrogg 0..1, 'paddus',[0x0F, 0xDC], :mrmmmx
368
+ addop 'pand', [0x0F, 0xDB], :mrmmmx
369
+ addop 'pandn', [0x0F, 0xDF], :mrmmmx
370
+ addop_macrogg 0..2, 'pcmpeq',[0x0F, 0x74], :mrmmmx
371
+ addop_macrogg 0..2, 'pcmpgt',[0x0F, 0x64], :mrmmmx
372
+ addop 'pmaddwd', [0x0F, 0xF5], :mrmmmx
373
+ addop 'pmulhuw', [0x0F, 0xE4], :mrmmmx
374
+ addop 'pmulhw',[0x0F, 0xE5], :mrmmmx
375
+ addop 'pmullw',[0x0F, 0xD5], :mrmmmx
376
+ addop 'por', [0x0F, 0xEB], :mrmmmx
377
+ addop_macrommx 1..3, 'psll', 3
378
+ addop_macrommx 1..2, 'psra', 2
379
+ addop_macrommx 1..3, 'psrl', 1
380
+ addop_macrogg 0..2, 'psub', [0x0F, 0xF8], :mrmmmx
381
+ addop_macrogg 0..1, 'psubs', [0x0F, 0xE8], :mrmmmx
382
+ addop_macrogg 0..1, 'psubus',[0x0F, 0xD8], :mrmmmx
383
+ addop_macrogg 1..3, 'punchkh', [0x0F, 0x68], :mrmmmx
384
+ addop_macrogg 1..3, 'punpckl', [0x0F, 0x60], :mrmmmx
385
+ addop 'pxor', [0x0F, 0xEF], :mrmmmx
386
+ end
387
+
388
+ def init_p6_only
389
+ addop_macrotttn 'cmov', [0x0F, 0x40], :mrm
390
+
391
+ %w{b e be u}.each_with_index { |tt, i|
392
+ addop 'fcmov' + tt, [0xDA, 0xC0 | (i << 3)], :regfp
393
+ addop 'fcmovn'+ tt, [0xDB, 0xC0 | (i << 3)], :regfp
394
+ }
395
+ addop 'fcomi', [0xDB, 0xF0], :regfp
396
+ addop('fxrstor', [0x0F, 0xAE, 1<<3], :modrmA) { |o| o.props[:argsz] = 512*8 }
397
+ addop('fxsave', [0x0F, 0xAE, 0<<3], :modrmA) { |o| o.props[:argsz] = 512*8 }
398
+ addop 'sysenter',[0x0F, 0x34]
399
+ addop 'sysexit', [0x0F, 0x35]
400
+
401
+ addop 'syscall', [0x0F, 0x05] # AMD
402
+ addop 'sysret', [0x0F, 0x07] # AMD
403
+ end
404
+
405
+ def init_3dnow_only
406
+ init_cpu_constants
407
+
408
+ [['pavgusb', 0xBF], ['pfadd', 0x9E], ['pfsub', 0x9A],
409
+ ['pfsubr', 0xAA], ['pfacc', 0xAE], ['pfcmpge', 0x90],
410
+ ['pfcmpgt', 0xA0], ['fpcmpeq', 0xB0], ['pfmin', 0x94],
411
+ ['pfmax', 0xA4], ['pi2fd', 0x0D], ['pf2id', 0x1D],
412
+ ['pfrcp', 0x96], ['pfrsqrt', 0x97], ['pfmul', 0xB4],
413
+ ['pfrcpit1', 0xA6], ['pfrsqit1', 0xA7], ['pfrcpit2', 0xB6],
414
+ ['pmulhrw', 0xB7]].each { |str, bin|
415
+ addop str, [0x0F, 0x0F, bin], :mrmmmx
416
+ }
417
+ # 3dnow prefix fallback
418
+ addop '3dnow', [0x0F, 0x0F], :mrmmmx, {}, :u8
419
+
420
+ addop 'femms', [0x0F, 0x0E]
421
+ addop 'prefetch', [0x0F, 0x0D, 0<<3], :modrmA
422
+ addop 'prefetchw', [0x0F, 0x0D, 1<<3], :modrmA
423
+ end
424
+
425
+ def init_sse_only
426
+ init_cpu_constants
427
+
428
+ addop_macrossps 'addps', [0x0F, 0xA8], :mrmxmm
429
+ addop 'andnps', [0x0F, 0xAA], :mrmxmm
430
+ addop 'andps', [0x0F, 0xA4], :mrmxmm
431
+ addop_macrossps 'cmpps', [0x0F, 0xC2], :mrmxmm
432
+ addop 'comiss', [0x0F, 0x2F], :mrmxmm
433
+
434
+ [['pi2ps', 0x2A], ['ps2pi', 0x2D], ['tps2pi', 0x2C]].each { |str, bin|
435
+ addop('cvt' << str, [0x0F, bin], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrmmmx }
436
+ addop('cvt' << str.tr('p', 's'), [0x0F, bin], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrm ; o.props[:needpfx] = 0xF3 }
437
+ }
438
+
439
+ addop_macrossps 'divps', [0x0F, 0x5E], :mrmxmm
440
+ addop 'ldmxcsr', [0x0F, 0xAE, 2<<3], :modrmA
441
+ addop_macrossps 'maxps', [0x0F, 0x5F], :mrmxmm
442
+ addop_macrossps 'minps', [0x0F, 0x5D], :mrmxmm
443
+ addop('movaps', [0x0F, 0x28], :mrmxmm, {:d => [1, 0]}) { |o| o.args.reverse! }
444
+ addop('movd', [0x0F, 0x6E], :mrmxmm, {:d => [1, 4]}) { |o| o.args[o.args.index(:modrmxmm)] = :modrm ; o.args.reverse! ; o.props[:needpfx] = 0x66 }
445
+ addop('movdqa', [0x0F, 0x6F], :mrmxmm, {:d => [1, 4]}) { |o| o.args.reverse! ; o.props[:needpfx] = 0x66 }
446
+
447
+ # movhlps(reg, reg){nomem} == movlps(reg, mrm){no restriction}...
448
+ addop 'movhlps', [0x0F, 0x12], :mrmxmm, {:d => [1, 0]}
449
+ addop 'movlps', [0x0F, 0x12], :mrmxmm, {:d => [1, 0]}
450
+ addop 'movlhps', [0x0F, 0x16], :mrmxmm, {:d => [1, 0]}
451
+ addop 'movhps', [0x0F, 0x16], :mrmxmm, {:d => [1, 0]}
452
+
453
+ addop 'movmskps',[0x0F, 0x50, 0xC0], nil, {:reg => [2, 3], :regxmm => [2, 0]}, :regxmm, :reg
454
+ addop('movss', [0x0F, 0x10], :mrmxmm, {:d => [1, 0]}) { |o| o.props[:needpfx] = 0xF3 }
455
+ addop 'movups', [0x0F, 0x10], :mrmxmm, {:d => [1, 0]}
456
+ addop_macrossps 'mulps', [0x0F, 0x59], :mrmxmm
457
+ addop 'orps', [0x0F, 0x56], :mrmxmm
458
+ addop_macrossps 'rcpps', [0x0F, 0x53], :mrmxmm
459
+ addop_macrossps 'rsqrtps',[0x0F, 0x52], :mrmxmm
460
+ addop 'shufps', [0x0F, 0xC6], :mrmxmm, {}, :u8
461
+ addop_macrossps 'sqrtps', [0x0F, 0x51], :mrmxmm
462
+ addop 'stmxcsr', [0x0F, 0xAE, 3<<3], :modrmA
463
+ addop_macrossps 'subps', [0x0F, 0x5C], :mrmxmm
464
+ addop 'ucomiss', [0x0F, 0x2E], :mrmxmm
465
+ addop 'unpckhps',[0x0F, 0x15], :mrmxmm
466
+ addop 'unpcklps',[0x0F, 0x14], :mrmxmm
467
+ addop 'xorps', [0x0F, 0x57], :mrmxmm
468
+
469
+ # start of integer instruction (accept opsz override prefix to access xmm)
470
+ addop('pavgb', [0x0F, 0xE0], :mrmmmx) { |o| o.props[:xmmx] = true }
471
+ addop('pavgw', [0x0F, 0xE3], :mrmmmx) { |o| o.props[:xmmx] = true }
472
+ # TODO addop('pextrw', [0x0F, 0xC5], :mrmmmx) { |o| o.fields[:reg] = o.fields.delete(:regmmx) } { |o| o.props[:xmmx] = true ; o.args << :u8 }
473
+ # addop('pinsrw', [0x0F, 0xC4], :mrmmmx) { |o| o.fields[:reg] = o.fields.delete(:regmmx) } { |o| o.props[:xmmx] = true ; o.args << :u8 }
474
+ addop('pmaxsw', [0x0F, 0xEE], :mrmmmx) { |o| o.props[:xmmx] = true }
475
+ addop('pmaxub', [0x0F, 0xDE], :mrmmmx) { |o| o.props[:xmmx] = true }
476
+ addop('pminsw', [0x0F, 0xEA], :mrmmmx) { |o| o.props[:xmmx] = true }
477
+ addop('pminub', [0x0F, 0xDA], :mrmmmx) { |o| o.props[:xmmx] = true }
478
+ # addop('pmovmskb',[0x0F, 0xD4], :mrmmmx) { |o| o.fields[:reg] = o.fields.delete(:regmmx) } ) { |o| o.props[:xmmx] = true } # no mem ref in the mrm
479
+ addop('pmulhuw', [0x0F, 0xE4], :mrmmmx) { |o| o.props[:xmmx] = true }
480
+ addop('psadbw', [0x0F, 0xF6], :mrmmmx) { |o| o.props[:xmmx] = true }
481
+ addop('pshufw', [0x0F, 0x70], :mrmmmx) { |o| o.props[:xmmx] = true ; o.args << :u8 }
482
+ addop('maskmovq',[0x0F, 0xF7], :mrmmmx) { |o| o.props[:xmmx] = true } # nomem
483
+ addop('movntq', [0x0F, 0xE7], :mrmmmx) { |o| o.props[:xmmx] = true }
484
+ addop 'movntps', [0x0F, 0x2B], :mrmxmm
485
+ addop 'prefetcht0', [0x0F, 0x18, 1<<3], :modrmA
486
+ addop 'prefetcht1', [0x0F, 0x18, 2<<3], :modrmA
487
+ addop 'prefetcht2', [0x0F, 0x18, 3<<3], :modrmA
488
+ addop 'prefetchnta',[0x0F, 0x18, 0<<3], :modrmA
489
+ addop 'sfence', [0x0F, 0xAE, 0xF8]
490
+ end
491
+
492
+ # XXX must be done after init_sse (patches :regmmx opcodes)
493
+ # TODO complete the list
494
+ def init_sse2_only
495
+ init_cpu_constants
496
+
497
+ @opcode_list.each { |o| o.props[:xmmx] = true if o.args.include? :regmmx and o.args.include? :modrmmmx }
498
+
499
+ # TODO <..blabla...integer...blabla..>
500
+
501
+ # nomem
502
+ addop('clflush', [0x0F, 0xAE, 7<<3], :modrmA) { |o| o.props[:argsz] = 8 }
503
+ addop('maskmovdqu', [0x0F, 0xF7], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
504
+ addop('movntpd', [0x0F, 0x2B], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
505
+ addop('movntdq', [0x0F, 0xE7], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
506
+ addop 'movnti', [0x0F, 0xC3], :mrm
507
+ addop('pause', [0x90]) { |o| o.props[:needpfx] = 0xF3 }
508
+ addop 'lfence', [0x0F, 0xAE, 0xE8]
509
+ addop 'mfence', [0x0F, 0xAE, 0xF0]
510
+ end
511
+
512
+ def init_sse3_only
513
+ init_cpu_constants
514
+
515
+ addop('addsubpd', [0x0F, 0xD0], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
516
+ addop('addsubps', [0x0F, 0xD0], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 }
517
+ addop('haddpd', [0x0F, 0x7C], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
518
+ addop('haddps', [0x0F, 0x7C], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 }
519
+ addop('hsubpd', [0x0F, 0x7D], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
520
+ addop('hsubps', [0x0F, 0x7D], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 }
521
+
522
+ addop 'monitor', [0x0F, 0x01, 0xC8]
523
+ addop 'mwait', [0x0F, 0x01, 0xC9]
524
+
525
+ addop('fisttp', [0xDF, 1<<3], :modrmA) { |o| o.props[:argsz] = 16 }
526
+ addop('fisttp', [0xDB, 1<<3], :modrmA) { |o| o.props[:argsz] = 32 }
527
+ addop('fisttp', [0xDD, 1<<3], :modrmA) { |o| o.props[:argsz] = 64 }
528
+ addop('lddqu', [0x0F, 0xF0], :mrmxmm) { |o| o.args[o.args.index(:modrmxmm)] = :modrmA ; o.props[:needpfx] = 0xF2 }
529
+ addop('movddup', [0x0F, 0x12], :mrmxmm) { |o| o.props[:needpfx] = 0xF2 }
530
+ addop('movshdup', [0x0F, 0x16], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 }
531
+ addop('movsldup', [0x0F, 0x12], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 }
532
+ end
533
+
534
+ def init_vmx_only
535
+ init_cpu_constants
536
+
537
+ addop 'vmcall', [0x0F, 0x01, 0xC1]
538
+ addop 'vmlaunch', [0x0F, 0x01, 0xC2]
539
+ addop 'vmresume', [0x0F, 0x01, 0xC3]
540
+ addop 'vmxoff', [0x0F, 0x01, 0xC4]
541
+ addop 'vmread', [0x0F, 0x78], :mrm
542
+ addop 'vmwrite', [0x0F, 0x79], :mrm
543
+ addop('vmclear', [0x0F, 0xC7, 6<<3], :modrmA) { |o| o.props[:argsz] = 64 ; o.props[:needpfx] = 0x66 }
544
+ addop('vmxon', [0x0F, 0xC7, 6<<3], :modrmA) { |o| o.props[:argsz] = 64 ; o.props[:needpfx] = 0xF3 }
545
+ addop('vmptrld', [0x0F, 0xC7, 6<<3], :modrmA) { |o| o.props[:argsz] = 64 }
546
+ addop('vmptrrst', [0x0F, 0xC7, 7<<3], :modrmA) { |o| o.props[:argsz] = 64 }
547
+ addop('invept', [0x0F, 0x38, 0x80], :mrmA) { |o| o.props[:needpfx] = 0x66 }
548
+ addop('invvpid', [0x0F, 0x38, 0x81], :mrmA) { |o| o.props[:needpfx] = 0x66 }
549
+
550
+ addop 'getsec', [0x0F, 0x37]
551
+
552
+ addop('movbe', [0x0F, 0x38, 0xF0], :mrm, { :d => [2, 0] }) { |o| o.args.reverse! }
553
+ addop 'xgetbv', [0x0F, 0x01, 0xD0]
554
+ addop 'xsetbv', [0x0F, 0x01, 0xD1]
555
+ addop 'rdtscp', [0x0F, 0x01, 0xF9]
556
+ addop 'xrstor', [0x0F, 0xAE, 5<<3], :modrmA
557
+ addop 'xsave', [0x0F, 0xAE, 4<<3], :modrmA
558
+ addop 'nop', [0x0F, 0x1F], 0 # which family does this belong to ?
559
+ end
560
+
561
+ def init_sse42_only
562
+ init_cpu_constants
563
+
564
+ addop('crc32', [0x0F, 0x38, 0xF0], :mrmw) { |o| o.props[:needpfx] = 0xF2 }
565
+ addop('pcmpestrm', [0x0F, 0x3A, 0x60], :mrmxmm, {}, :i8) { |o| o.props[:needpfx] = 0x66 }
566
+ addop('pcmpestri', [0x0F, 0x3A, 0x61], :mrmxmm, {}, :i8) { |o| o.props[:needpfx] = 0x66 }
567
+ addop('pcmpistrm', [0x0F, 0x3A, 0x62], :mrmxmm, {}, :i8) { |o| o.props[:needpfx] = 0x66 }
568
+ addop('pcmpistri', [0x0F, 0x3A, 0x63], :mrmxmm, {}, :i8) { |o| o.props[:needpfx] = 0x66 }
569
+ addop('pcmpgtq', [0x0F, 0x38, 0x37], :mrmxmm) { |o| o.props[:needpfx] = 0x66 }
570
+ addop('popcnt', [0x0F, 0xB8], :mrmxmm) { |o| o.props[:needpfx] = 0xF3 }
571
+ end
572
+
573
+
574
+ #
575
+ # CPU family dependencies
576
+ #
577
+
578
+ def init_386_common
579
+ init_386_common_only
580
+ end
581
+
582
+ def init_386
583
+ init_386_common
584
+ init_386_only
585
+ end
586
+
587
+ def init_387
588
+ init_387_only
589
+ end
590
+
591
+ def init_486
592
+ init_386
593
+ init_387
594
+ init_486_only
595
+ end
596
+
597
+ def init_pentium
598
+ init_486
599
+ init_pentium_only
600
+ end
601
+
602
+ def init_3dnow
603
+ init_pentium
604
+ init_3dnow_only
605
+ end
606
+
607
+ def init_p6
608
+ init_pentium
609
+ init_p6_only
610
+ end
611
+
612
+ def init_sse
613
+ init_p6
614
+ init_sse_only
615
+ end
616
+
617
+ def init_sse2
618
+ init_sse
619
+ init_sse2_only
620
+ end
621
+
622
+ def init_sse3
623
+ init_sse2
624
+ init_sse3_only
625
+ end
626
+
627
+ def init_vmx
628
+ init_sse3
629
+ init_vmx_only
630
+ end
631
+
632
+ def init_all
633
+ init_vmx
634
+ init_sse42_only
635
+ init_3dnow_only
636
+ end
637
+
638
+ alias init_latest init_all
639
+
640
+
641
+ #
642
+ # addop_* macros
643
+ #
644
+
645
+ def addop_macro1(name, num, immtype=:i)
646
+ addop name, [(num << 3) | 4], nil, {:w => [0, 0]}, :reg_eax, immtype
647
+ addop name, [num << 3], :mrmw, {:d => [0, 1]}
648
+ addop name, [0x80], num, {:w => [0, 0], :s => [0, 1]}, immtype
649
+ end
650
+ def addop_macro2(name, num)
651
+ addop name, [0x0F, 0xBA], (4 | num), {}, :u8
652
+ addop(name, [0x0F, 0xA3 | (num << 3)], :mrm) { |op| op.args.reverse! }
653
+ end
654
+ def addop_macro3(name, num)
655
+ addop name, [0xD0], num, {:w => [0, 0]}, :imm_val1
656
+ addop name, [0xD2], num, {:w => [0, 0]}, :reg_cl
657
+ addop name, [0xC0], num, {:w => [0, 0]}, :u8
658
+ end
659
+
660
+ def addop_macrotttn(name, bin, hint, fields = {}, *props, &blk)
661
+ [%w{o}, %w{no}, %w{b nae c}, %w{nb ae nc},
662
+ %w{z e}, %w{nz ne}, %w{be na}, %w{nbe a},
663
+ %w{s}, %w{ns}, %w{p pe}, %w{np po},
664
+ %w{l nge}, %w{nl ge}, %w{le ng}, %w{nle g}].each_with_index { |e, i|
665
+ b = bin.dup
666
+ if b[0] == 0x0F
667
+ b[1] |= i
668
+ else
669
+ b[0] |= i
670
+ end
671
+
672
+ e.each { |k| addop(name + k, b.dup, hint, fields.dup, *props, &blk) }
673
+ }
674
+ end
675
+
676
+ def addop_macrostr(name, bin, type)
677
+ # addop(name, bin.dup, {:w => [0, 0]}) { |o| o.props[type] = true } # TODO allow segment override
678
+ addop(name+'b', bin) { |o| o.props[:opsz] = 16 ; o.props[type] = true }
679
+ addop(name+'b', bin) { |o| o.props[:opsz] = 32 ; o.props[type] = true }
680
+ bin = bin.dup
681
+ bin[0] |= 1
682
+ addop(name+'w', bin) { |o| o.props[:opsz] = 16 ; o.props[type] = true }
683
+ addop(name+'d', bin) { |o| o.props[:opsz] = 32 ; o.props[type] = true }
684
+ end
685
+
686
+ def addop_macrofpu1(name, n)
687
+ addop(name, [0xD8, n<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 32 }
688
+ addop(name, [0xDC, n<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 64 }
689
+ addop name, [0xD8, 0xC0|(n<<3)], :regfp, {:d => [0, 2]}
690
+ end
691
+ def addop_macrofpu2(name, n, n2=0)
692
+ addop(name, [0xDE|n2, n<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 16 }
693
+ addop(name, [0xDA|n2, n<<3], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 32 }
694
+ end
695
+ def addop_macrofpu3(name, n)
696
+ addop_macrofpu2 name, n, 1
697
+ addop(name, [0xDF, 0x28|(n<<3)], :modrmA, {}, :regfp0) { |o| o.props[:argsz] = 64 }
698
+ end
699
+
700
+ def addop_macrogg(ggrng, name, bin, *args, &blk)
701
+ ggrng.each { |gg|
702
+ bindup = bin.dup
703
+ bindup[1] |= gg
704
+ sfx = %w(b w d q)[gg]
705
+ addop name+sfx, bindup, *args, &blk
706
+ }
707
+ end
708
+
709
+ def addop_macrommx(ggrng, name, val)
710
+ addop_macrogg ggrng, name, [0x0F, 0xC0 | (val << 4)], :mrmmmx
711
+ addop_macrogg ggrng, name, [0x0F, 0x70, 0xC0 | (val << 4)], nil, {:regmmx => [2, 0]}, :u8
712
+ end
713
+
714
+ def addop_macrossps(name, bin, hint)
715
+ # don't allow fields argument, as this will be modified by addop (.dup it if needed)
716
+ addop name, bin, hint
717
+ addop(name.tr('p', 's'), bin, hint) { |o| o.props[:needpfx] = 0xF3 }
718
+ end
719
+
720
+ # helper function: creates a new Opcode based on the arguments, eventually
721
+ # yields it for further customisation, and append it to the instruction set
722
+ # is responsible of the creation of disambiguating opcodes if necessary (:s flag hardcoding)
723
+ def addop(name, bin, hint=nil, fields={}, *argprops)
724
+ op = Opcode.new name, bin
725
+ op.fields.replace fields
726
+
727
+ case hint
728
+ when nil
729
+
730
+ when :mrm, :mrmw, :mrmA
731
+ h = (hint == :mrmA ? :modrmA : :modrm)
732
+ op.fields[:reg] = [bin.length, 3]
733
+ op.fields[h] = [bin.length, 0]
734
+ op.fields[:w] = [bin.length - 1, 0] if hint == :mrmw
735
+ argprops.unshift :reg, h
736
+ op.bin << 0
737
+ when :reg
738
+ op.fields[:reg] = [bin.length-1, 0]
739
+ argprops.unshift :reg
740
+ when :regfp
741
+ op.fields[:regfp] = [bin.length-1, 0]
742
+ argprops.unshift :regfp, :regfp0
743
+ when :modrmA
744
+ op.fields[:modrmA] = [bin.length-1, 0]
745
+ argprops << :modrmA
746
+
747
+ when Integer # mod/m, reg == opcode extension = hint
748
+ op.fields[:modrm] = [bin.length, 0]
749
+ op.bin << (hint << 3)
750
+ argprops.unshift :modrm
751
+
752
+ when :mrmmmx
753
+ op.fields[:regmmx] = [bin.length, 3]
754
+ op.fields[:modrm] = [bin.length, 0]
755
+ bin << 0
756
+ argprops.unshift :regmmx, :modrmmmx
757
+ when :mrmxmm
758
+ op.fields[:regxmm] = [bin.length, 3]
759
+ op.fields[:modrm] = [bin.length, 0]
760
+ bin << 0
761
+ argprops.unshift :regxmm, :modrmxmm
762
+ else
763
+ raise SyntaxError, "invalid hint #{hint.inspect} for #{name}"
764
+ end
765
+
766
+ if argprops.index(:u)
767
+ argprops << :unsigned_imm
768
+ argprops[argprops.index(:u)] = :i
769
+ end
770
+
771
+ (argprops & @valid_props).each { |p| op.props[p] = true }
772
+ argprops -= @valid_props
773
+
774
+ op.args.concat(argprops & @valid_args)
775
+ argprops -= @valid_args
776
+
777
+ raise "Invalid opcode definition: #{name}: unknown #{argprops.inspect}" unless argprops.empty?
778
+
779
+ yield op if block_given?
780
+
781
+ argprops = (op.props.keys - @valid_props) + (op.args - @valid_args) + (op.fields.keys - @fields_mask.keys)
782
+ raise "Invalid opcode customisation: #{name}: #{argprops.inspect}" unless argprops.empty?
783
+
784
+ addop_post(op)
785
+ end
786
+
787
+ # this recursive method is in charge of Opcode duplication (eg to hardcode some flag)
788
+ def addop_post(op)
789
+ dupe = lambda { |o|
790
+ dop = Opcode.new o.name.dup
791
+ dop.bin, dop.fields, dop.props, dop.args = o.bin.dup, o.fields.dup, o.props.dup, o.args.dup
792
+ dop
793
+ }
794
+ if df = op.fields.delete(:d)
795
+ # hardcode the bit
796
+ dop = dupe[op]
797
+ dop.args.reverse!
798
+ addop_post dop
799
+
800
+ op.bin[df[0]] |= 1 << df[1]
801
+ addop_post op
802
+
803
+ return
804
+ elsif wf = op.fields.delete(:w)
805
+ # hardcode the bit
806
+ dop = dupe[op]
807
+ dop.props[:argsz] = 8
808
+ addop_post dop
809
+
810
+ op.bin[wf[0]] |= 1 << wf[1]
811
+ addop_post op
812
+
813
+ return
814
+ elsif sf = op.fields.delete(:s)
815
+ # add explicit choice versions, with lower precedence (so that disassembling will return the general version)
816
+ # eg "jmp", "jmp.i8", "jmp.i"
817
+ # also hardcode the bit
818
+ op32 = op
819
+ addop_post op32
820
+
821
+ op8 = dupe[op]
822
+ op8.bin[sf[0]] |= 1 << sf[1]
823
+ op8.args.map! { |arg| arg == :i ? :i8 : arg }
824
+ addop_post op8
825
+
826
+ op32 = dupe[op32]
827
+ op32.name << '.i'
828
+ addop_post op32
829
+
830
+ op8 = dupe[op8]
831
+ op8.name << '.i8'
832
+ addop_post op8
833
+
834
+ return
835
+ elsif op.args.first == :regfp0
836
+ dop = dupe[op]
837
+ dop.args.delete :regfp0
838
+ addop_post dop
839
+ end
840
+
841
+ if op.props[:needpfx] and @opcode_list.find { |oo| oo.name == op.name and not oo.props[:needpfx] }
842
+ @opcode_list.unshift op
843
+ else
844
+ @opcode_list << op
845
+ end
846
+
847
+ if op.args == [:i] or op.args == [:farptr] or op.name[0, 3] == 'ret'
848
+ # define opsz-override version for ambiguous opcodes
849
+ op16 = dupe[op]
850
+ op16.name << '.i16'
851
+ op16.props[:opsz] = 16
852
+ @opcode_list << op16
853
+ op32 = dupe[op]
854
+ op32.name << '.i32'
855
+ op32.props[:opsz] = 32
856
+ @opcode_list << op32
857
+ elsif op.props[:strop] or op.props[:stropz] or op.args.include? :mrm_imm or
858
+ op.args.include? :modrm or op.args.include? :modrmA or op.name =~ /loop|xlat/
859
+ # define adsz-override version for ambiguous opcodes (TODO allow movsd edi / movsd di syntax)
860
+ # XXX loop pfx 67 = eip+cx, 66 = ip+ecx
861
+ op16 = dupe[op]
862
+ op16.name << '.a16'
863
+ op16.props[:adsz] = 16
864
+ @opcode_list << op16
865
+ op32 = dupe[op]
866
+ op32.name << '.a32'
867
+ op32.props[:adsz] = 32
868
+ @opcode_list << op32
869
+ end
870
+ end
871
+ end
872
+ end