evoasm 0.0.2.pre7 → 0.1.0.pre2

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 (168) hide show
  1. checksums.yaml +4 -4
  2. data/.gdbinit +41 -0
  3. data/.gitignore +1 -2
  4. data/.gitmodules +3 -0
  5. data/.rubocop.yml +8 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.md +660 -0
  8. data/Makefile +1 -1
  9. data/README.md +17 -9
  10. data/Rakefile +39 -107
  11. data/bin/gdb +1 -1
  12. data/bin/gdb_loop +4 -0
  13. data/docs/FindingInstructions.md +17 -0
  14. data/docs/JIT.md +14 -0
  15. data/docs/SymbolicRegression.md +102 -0
  16. data/docs/Visualization.md +29 -0
  17. data/docs/examples/bit_insts.rb +44 -0
  18. data/docs/examples/jit.rb +26 -0
  19. data/docs/examples/loss.gif +0 -0
  20. data/docs/examples/program.png +0 -0
  21. data/docs/examples/sym_reg.rb +64 -0
  22. data/docs/examples/vis.rb +38 -0
  23. data/evoasm.gemspec +21 -15
  24. data/ext/evoasm_ext/Rakefile +3 -0
  25. data/ext/evoasm_ext/compile.rake +35 -0
  26. data/ext/evoasm_ext/libevoasm/src/evoasm-alloc.c +226 -0
  27. data/ext/evoasm_ext/libevoasm/src/evoasm-alloc.h +84 -0
  28. data/ext/evoasm_ext/libevoasm/src/evoasm-arch.c +52 -0
  29. data/ext/evoasm_ext/libevoasm/src/evoasm-arch.h +101 -0
  30. data/ext/evoasm_ext/libevoasm/src/evoasm-bitmap.h +158 -0
  31. data/ext/evoasm_ext/libevoasm/src/evoasm-buf.c +204 -0
  32. data/ext/evoasm_ext/libevoasm/src/evoasm-buf.h +109 -0
  33. data/ext/evoasm_ext/libevoasm/src/evoasm-domain.c +124 -0
  34. data/ext/evoasm_ext/libevoasm/src/evoasm-domain.h +279 -0
  35. data/ext/evoasm_ext/libevoasm/src/evoasm-error.c +65 -0
  36. data/ext/evoasm_ext/libevoasm/src/evoasm-error.h +108 -0
  37. data/ext/evoasm_ext/{evoasm-log.c → libevoasm/src/evoasm-log.c} +36 -18
  38. data/ext/evoasm_ext/libevoasm/src/evoasm-log.h +93 -0
  39. data/ext/evoasm_ext/libevoasm/src/evoasm-param.c +22 -0
  40. data/ext/evoasm_ext/libevoasm/src/evoasm-param.h +33 -0
  41. data/ext/evoasm_ext/libevoasm/src/evoasm-pop-params.c +192 -0
  42. data/ext/evoasm_ext/libevoasm/src/evoasm-pop-params.h +60 -0
  43. data/ext/evoasm_ext/libevoasm/src/evoasm-pop.c +1323 -0
  44. data/ext/evoasm_ext/libevoasm/src/evoasm-pop.h +107 -0
  45. data/ext/evoasm_ext/libevoasm/src/evoasm-program-io.c +116 -0
  46. data/ext/evoasm_ext/libevoasm/src/evoasm-program-io.h +60 -0
  47. data/ext/evoasm_ext/libevoasm/src/evoasm-program.c +1827 -0
  48. data/ext/evoasm_ext/libevoasm/src/evoasm-program.h +167 -0
  49. data/ext/evoasm_ext/libevoasm/src/evoasm-rand.c +65 -0
  50. data/ext/evoasm_ext/libevoasm/src/evoasm-rand.h +76 -0
  51. data/ext/evoasm_ext/libevoasm/src/evoasm-signal.c +106 -0
  52. data/ext/evoasm_ext/libevoasm/src/evoasm-signal.h +58 -0
  53. data/ext/evoasm_ext/libevoasm/src/evoasm-util.h +112 -0
  54. data/ext/evoasm_ext/libevoasm/src/evoasm-x64.c +925 -0
  55. data/ext/evoasm_ext/libevoasm/src/evoasm-x64.h +277 -0
  56. data/ext/evoasm_ext/libevoasm/src/evoasm.c +28 -0
  57. data/ext/evoasm_ext/libevoasm/src/evoasm.h +35 -0
  58. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-enums.h +2077 -0
  59. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-insts.c +191203 -0
  60. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-insts.h +1713 -0
  61. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-misc.c +348 -0
  62. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-misc.h +93 -0
  63. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-params.c +51 -0
  64. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-params.h +509 -0
  65. data/lib/evoasm.rb +28 -11
  66. data/lib/evoasm/buffer.rb +105 -0
  67. data/lib/evoasm/capstone.rb +100 -0
  68. data/lib/evoasm/domain.rb +116 -0
  69. data/lib/evoasm/error.rb +37 -16
  70. data/lib/evoasm/exception_error.rb +19 -0
  71. data/lib/evoasm/ffi_ext.rb +53 -0
  72. data/lib/evoasm/libevoasm.rb +286 -0
  73. data/lib/evoasm/libevoasm/x64_enums.rb +1967 -0
  74. data/lib/evoasm/parameter.rb +20 -0
  75. data/lib/evoasm/population.rb +145 -0
  76. data/lib/evoasm/population/parameters.rb +227 -0
  77. data/lib/evoasm/population/plotter.rb +89 -0
  78. data/lib/evoasm/prng.rb +64 -0
  79. data/lib/evoasm/program.rb +195 -12
  80. data/lib/evoasm/program/io.rb +144 -0
  81. data/lib/evoasm/test.rb +8 -0
  82. data/lib/evoasm/version.rb +1 -1
  83. data/lib/evoasm/x64.rb +115 -0
  84. data/lib/evoasm/x64/cpu_state.rb +95 -0
  85. data/lib/evoasm/x64/instruction.rb +109 -0
  86. data/lib/evoasm/x64/operand.rb +156 -0
  87. data/lib/evoasm/x64/parameters.rb +211 -0
  88. data/test/helpers/population_helper.rb +128 -0
  89. data/test/helpers/test_helper.rb +1 -0
  90. data/test/helpers/x64_helper.rb +24 -0
  91. data/test/integration/bitwise_reverse_test.rb +41 -0
  92. data/test/integration/gcd_test.rb +52 -0
  93. data/test/integration/popcnt_test.rb +46 -0
  94. data/test/integration/sym_reg_test.rb +68 -0
  95. data/test/unit/evoasm/buffer_test.rb +48 -0
  96. data/test/unit/evoasm/capstone_test.rb +18 -0
  97. data/test/unit/evoasm/domain_test.rb +55 -0
  98. data/test/unit/evoasm/population/parameters_test.rb +106 -0
  99. data/test/unit/evoasm/population_test.rb +96 -0
  100. data/test/unit/evoasm/prng_test.rb +47 -0
  101. data/test/unit/evoasm/x64/cpu_state_test.rb +73 -0
  102. data/test/unit/evoasm/x64/encoding_test.rb +320 -0
  103. data/test/unit/evoasm/x64/instruction_access_test.rb +177 -0
  104. data/test/unit/evoasm/x64/instruction_encoding_test.rb +780 -0
  105. data/test/unit/evoasm/x64/instruction_test.rb +62 -0
  106. data/test/unit/evoasm/x64/parameters_test.rb +65 -0
  107. data/test/unit/evoasm/x64_test.rb +52 -0
  108. metadata +195 -89
  109. data/Gemfile.rake +0 -8
  110. data/Gemfile.rake.lock +0 -51
  111. data/LICENSE.txt +0 -373
  112. data/data/tables/README.md +0 -19
  113. data/data/tables/x64.csv +0 -1684
  114. data/data/templates/evoasm-x64.c.erb +0 -319
  115. data/data/templates/evoasm-x64.h.erb +0 -126
  116. data/examples/abs.yml +0 -20
  117. data/examples/popcnt.yml +0 -17
  118. data/examples/sym_reg.yml +0 -26
  119. data/exe/evoasm-search +0 -13
  120. data/ext/evoasm_ext/evoasm-alloc.c +0 -145
  121. data/ext/evoasm_ext/evoasm-alloc.h +0 -59
  122. data/ext/evoasm_ext/evoasm-arch.c +0 -44
  123. data/ext/evoasm_ext/evoasm-arch.h +0 -161
  124. data/ext/evoasm_ext/evoasm-bitmap.h +0 -114
  125. data/ext/evoasm_ext/evoasm-buf.c +0 -130
  126. data/ext/evoasm_ext/evoasm-buf.h +0 -47
  127. data/ext/evoasm_ext/evoasm-error.c +0 -31
  128. data/ext/evoasm_ext/evoasm-error.h +0 -75
  129. data/ext/evoasm_ext/evoasm-free-list.c.tmpl +0 -121
  130. data/ext/evoasm_ext/evoasm-free-list.h.tmpl +0 -86
  131. data/ext/evoasm_ext/evoasm-log.h +0 -69
  132. data/ext/evoasm_ext/evoasm-misc.c +0 -23
  133. data/ext/evoasm_ext/evoasm-misc.h +0 -282
  134. data/ext/evoasm_ext/evoasm-param.h +0 -37
  135. data/ext/evoasm_ext/evoasm-search.c +0 -2145
  136. data/ext/evoasm_ext/evoasm-search.h +0 -214
  137. data/ext/evoasm_ext/evoasm-util.h +0 -40
  138. data/ext/evoasm_ext/evoasm-x64.c +0 -275624
  139. data/ext/evoasm_ext/evoasm-x64.h +0 -5436
  140. data/ext/evoasm_ext/evoasm.c +0 -7
  141. data/ext/evoasm_ext/evoasm.h +0 -23
  142. data/ext/evoasm_ext/evoasm_ext.c +0 -1757
  143. data/ext/evoasm_ext/extconf.rb +0 -31
  144. data/lib/evoasm/cli.rb +0 -6
  145. data/lib/evoasm/cli/search.rb +0 -127
  146. data/lib/evoasm/core_ext.rb +0 -1
  147. data/lib/evoasm/core_ext/array.rb +0 -9
  148. data/lib/evoasm/core_ext/integer.rb +0 -10
  149. data/lib/evoasm/core_ext/kwstruct.rb +0 -13
  150. data/lib/evoasm/core_ext/range.rb +0 -5
  151. data/lib/evoasm/examples.rb +0 -27
  152. data/lib/evoasm/gen.rb +0 -8
  153. data/lib/evoasm/gen/enum.rb +0 -169
  154. data/lib/evoasm/gen/name_util.rb +0 -80
  155. data/lib/evoasm/gen/state.rb +0 -176
  156. data/lib/evoasm/gen/state_dsl.rb +0 -152
  157. data/lib/evoasm/gen/strio.rb +0 -27
  158. data/lib/evoasm/gen/translator.rb +0 -1102
  159. data/lib/evoasm/gen/version.rb +0 -5
  160. data/lib/evoasm/gen/x64.rb +0 -237
  161. data/lib/evoasm/gen/x64/funcs.rb +0 -495
  162. data/lib/evoasm/gen/x64/inst.rb +0 -781
  163. data/lib/evoasm/search.rb +0 -40
  164. data/lib/evoasm/tasks/gen_task.rb +0 -86
  165. data/lib/evoasm/tasks/template_task.rb +0 -52
  166. data/test/test_helper.rb +0 -1
  167. data/test/x64/test_helper.rb +0 -19
  168. data/test/x64/x64_test.rb +0 -87
@@ -0,0 +1,64 @@
1
+ module Evoasm
2
+ # A fast pseudo-random number generator.
3
+ class PRNG < FFI::AutoPointer
4
+
5
+ # Number of seed elements required
6
+ SEED_SIZE = 16
7
+
8
+ # Default seed values
9
+ DEFAULT_SEED = (1..SEED_SIZE).to_a
10
+
11
+ # @!visibility private
12
+ def self.release(ptr)
13
+ Libevoasm.prng_free ptr
14
+ end
15
+
16
+ # Gives the default {PRNG}, seeded with {DEFAULT_SEED}
17
+ # @return [PRNG] default {PRNG} instance
18
+ def self.default
19
+ @default_prng ||= new(DEFAULT_SEED)
20
+ end
21
+
22
+ # @param seed [Array<Integer>] the seed, must have exactly {SEED_SIZE} elements
23
+ # @return [PRNG] new {PRNG} instance
24
+ def initialize(seed = DEFAULT_SEED)
25
+ if seed.size != SEED_SIZE
26
+ raise ArgumentError, "seed must be have exactly #{SEED_SIZE} elements"
27
+ end
28
+
29
+ ptr = Libevoasm.prng_alloc
30
+
31
+ seed_ptr = FFI::MemoryPointer.new :uint64, SEED_SIZE
32
+ seed_ptr.write_array_of_uint64 seed
33
+
34
+ Libevoasm.prng_init ptr, seed_ptr
35
+ super(ptr)
36
+ end
37
+
38
+ # @return [Integer] a random number in the range (0..2**64 - 2)
39
+ def rand64
40
+ Libevoasm.prng_rand64 self
41
+ end
42
+
43
+ # @return [Integer] a random number in the range (0..2**32 - 2)
44
+ def rand32
45
+ Libevoasm.prng_rand32 self
46
+ end
47
+
48
+ # @return [Integer] a random number in the range (0..2**16 - 2)
49
+ def rand16
50
+ Libevoasm.prng_rand16 self
51
+ end
52
+
53
+ # @return [Integer] a random number in the range (0..2**8 - 2)
54
+ def rand8
55
+ Libevoasm.prng_rand8 self
56
+ end
57
+
58
+ # Gives a random number in the range (+min+..+max+ - 1)
59
+ # @return [Integer] random number
60
+ def rand_between(min, max)
61
+ Libevoasm.prng_rand_between self, min, max
62
+ end
63
+ end
64
+ end
@@ -1,23 +1,206 @@
1
- require 'evoasm/search'
1
+ require 'ffi'
2
2
 
3
3
  module Evoasm
4
- class Program
5
- include Search::Util
6
4
 
7
- def run(*input_example)
8
- run_all(input_example).first
5
+ # Represents a program comprising one ore multiple kernels
6
+ class Program < FFI::AutoPointer
7
+
8
+ require_relative 'program/io.rb'
9
+
10
+
11
+ # @!visibility private
12
+ def self.release(ptr)
13
+ Libevoasm.program_destroy(ptr)
14
+ Libevoasm.program_free(ptr)
15
+ end
16
+
17
+ def initialize
18
+ ptr = Libevoasm.program_alloc
19
+ super ptr
20
+ end
21
+
22
+ # Runs the program with the given input
23
+ # @param input_tuple [Array] an input tuple
24
+ # @return [Array] the output tuple corresponding to the given input
25
+ def run(*input_tuple)
26
+ run_all(input_tuple).first
9
27
  end
10
28
 
29
+ # Like {#run}, but runs multiple input tuples at once
30
+ # @param input_examples [Array] an array of input tuples
31
+ # @return [Array] an array of output tuples
11
32
  def run_all(*input_examples)
12
- input_examples, input_arity = flatten_examples input_examples
13
- p input_examples, input_arity
14
- a = __run__ input_examples, input_arity
15
- p a
16
- a
33
+ input = Program::Input.new(input_examples)
34
+
35
+ output_ptr = Libevoasm.program_run self, input
36
+
37
+ if output_ptr.null?
38
+ raise Error.last
39
+ end
40
+
41
+ Program::Output.new(output_ptr).to_a
42
+ end
43
+
44
+ # Gives the size of the program as the number of kernels
45
+ # @return [Integer] size
46
+ def size
47
+ Libevoasm.program_get_size self
48
+ end
49
+
50
+ # Eliminates intron instructions (instructions without effect)
51
+ # @return [Program] a new program with introns eliminated
52
+ def eliminate_introns
53
+ program = Program.new
54
+ unless Libevoasm.program_eliminate_introns self, program
55
+ raise Libevoasm::Error.last
56
+ end
57
+
58
+ program
59
+ end
60
+
61
+ # Gives the disassembly for the specified kernel
62
+ # @param kernel_index [Integer] index of kernel to disassemble
63
+ # @return [String] disassembly
64
+ def disassemble_kernel(kernel_index)
65
+ code_ptr_ptr = FFI::MemoryPointer.new :pointer
66
+ code_len = Libevoasm.program_get_kernel_code self, kernel_index, code_ptr_ptr
67
+ code_ptr = code_ptr_ptr.read_pointer
68
+ code = code_ptr.read_string(code_len)
69
+
70
+ X64.disassemble code, code_ptr.address
71
+ end
72
+
73
+ # Gives the disassembly for all kernels in the program
74
+ # @return [Array<String>] array of disassembly
75
+ def disassemble_kernels
76
+ Array.new(size) do |kernel_index|
77
+ disassemble_kernel kernel_index
78
+ end
79
+ end
80
+
81
+ private def io_registers(input, kernel_index)
82
+ reg_enum_type = Libevoasm.enum_type(:x64_reg_id)
83
+ reg_enum_type.to_h.each_with_object([]) do |(k, v), acc|
84
+ unless k == :none
85
+ io =
86
+ if input
87
+ Libevoasm.program_is_input_reg(self, kernel_index, v)
88
+ else
89
+ Libevoasm.program_is_output_reg(self, kernel_index, v)
90
+ end
91
+
92
+ acc << k if io
93
+ end
94
+ end
17
95
  end
18
96
 
19
- def disassemble(*args)
20
- buffer.disassemble(*args)
97
+ # Gives the input registers of the specified kernel
98
+ # @param kernel_index [Integer]
99
+ # @return [Array<Symbol>] input registers
100
+ def input_registers(kernel_index = 0)
101
+ io_registers true, kernel_index
102
+ end
103
+
104
+ # Gives the output registers of the specified kernel
105
+ # @param kernel_index [Integer]
106
+ # @return [Array<Symbol>] output registers
107
+ def output_registers(kernel_index = size - 1)
108
+ io_registers false, kernel_index
109
+ end
110
+
111
+ private def format_disassembly(disasm)
112
+ disasm.map do |line|
113
+ "0x#{line[0].to_s 16}:\t#{line[1]}\t#{line[2]}"
114
+ end.join("\n")
115
+ end
116
+
117
+ # Disassembles the whole program
118
+ # @param frame [Bool] whether to include the stack frame and
119
+ # @param format [Bool] whether to format the assembly
120
+ # @return [String, Array<String>] the formatted assembly as string
121
+ # if format is set, an array of address, opcode, operands triples otherwise.
122
+ def disassemble(frame = false, format: false)
123
+ code_ptr_ptr = FFI::MemoryPointer.new :pointer
124
+ code_len = Libevoasm.program_get_code self, frame, code_ptr_ptr
125
+ code_ptr = code_ptr_ptr.read_pointer
126
+ code = code_ptr.read_string(code_len)
127
+
128
+ disasm = X64.disassemble code, code_ptr.address
129
+
130
+ if format
131
+ format_disassembly disasm
132
+ else
133
+ disasm
134
+ end
135
+ end
136
+
137
+ # Visualizes the program and its kernels using Graphviz
138
+ # @return [GV::Graph]
139
+ def to_gv
140
+ require 'gv'
141
+
142
+ graph = GV::Graph.open 'g'
143
+
144
+ disasms = disassemble_kernels
145
+ addrs = disasms.map do |disasm|
146
+ disasm.first&.first
147
+ end
148
+
149
+ size.times do |kernel_index|
150
+ label = '<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">'
151
+
152
+ label << '<TR>'
153
+ label << %Q{<TD COLSPAN="3"><B>Kernel #{kernel_index}</B></TD>}
154
+ label << '</TR>'
155
+
156
+ disasm = disasms[kernel_index]
157
+ addr = addrs[kernel_index]
158
+ jmp_addrs = []
159
+
160
+ disasm.each do |line|
161
+ op_str = line[2]
162
+
163
+ label << '<TR>'
164
+ label << %Q{<TD ALIGN="LEFT">0x#{line[0].to_s 16}</TD>}
165
+ label << %Q{<TD ALIGN="LEFT">#{line[1]}</TD>}
166
+
167
+ if op_str =~ /0x(\h+)/
168
+ jmp_addr = Integer($1, 16)
169
+ jmp_addrs << jmp_addr
170
+ port = jmp_addr
171
+ else
172
+ port = ''
173
+ end
174
+ label << %Q{<TD ALIGN="LEFT" PORT="#{port}">#{op_str}</TD>}
175
+ label << '</TR>'
176
+ end
177
+ label << '</TABLE>'
178
+
179
+ node = graph.node addr.to_s,
180
+ shape: :none,
181
+ label: graph.html(label)
182
+
183
+ succs = [kernel_index + 1, kernel_index + Libevoasm.program_get_jmp_off(self, kernel_index)].select do |succ|
184
+ succ < size
185
+ end
186
+
187
+ succs.each do |succ|
188
+ succ_addr = addrs[succ]
189
+ tail_port =
190
+ if jmp_addrs.include? succ_addr
191
+ # Remove, in case we have the same
192
+ # successor multiple times
193
+ # only one of which goes through the jump
194
+ jmp_addrs.delete succ_addr
195
+ succ_addr.to_s
196
+ else
197
+ 's'
198
+ end
199
+ graph.edge 'e', node, graph.node(succ_addr.to_s), tailport: tail_port, headport: 'n'
200
+ end
201
+ end
202
+
203
+ graph
21
204
  end
22
205
  end
23
206
  end
@@ -0,0 +1,144 @@
1
+ require 'evoasm/program'
2
+
3
+ module Evoasm
4
+ class Program
5
+ # Represents one or multiple input/output tuples.
6
+ class IO < FFI::AutoPointer
7
+
8
+ # Maximum arity for tuples
9
+ MAX_ARITY = 8
10
+
11
+ include Enumerable
12
+
13
+ # @!visibility private
14
+ def self.release(ptr)
15
+ Libevoasm.program_io_free(ptr)
16
+ end
17
+
18
+ # @param tuples [Array] array of input or output tuples
19
+ def initialize(tuples)
20
+ if tuples.is_a?(FFI::Pointer)
21
+ super(tuples)
22
+ else
23
+ tuples = tuples
24
+ arity = determine_arity tuples
25
+
26
+ if arity > MAX_ARITY
27
+ raise ArgumentError, "maximum arity exceeded (#{arity} > #{MAX_ARITY})"
28
+ end
29
+
30
+ flat_tuples = tuples.flatten
31
+
32
+ ptr = Libevoasm.program_io_alloc flat_tuples.size
33
+ load_tuples ptr, flat_tuples, arity
34
+
35
+ super(ptr)
36
+ end
37
+ end
38
+
39
+ # @return [Integer] arity of tuples
40
+ def arity
41
+ Libevoasm.program_io_get_arity self
42
+ end
43
+
44
+ # @yield [Array] tuple
45
+ def each
46
+ return enum_for(:each) unless block_given?
47
+ size.times do |tuple_index|
48
+ yield self[tuple_index]
49
+ end
50
+ end
51
+
52
+ # Converts to array of tuples
53
+ def to_a
54
+ Array.new(size) do |tuple_index|
55
+ self[tuple_index]
56
+ end
57
+ end
58
+
59
+ # @return [Integer] the number of input/output values
60
+ def length
61
+ Libevoasm.program_io_get_len self
62
+ end
63
+
64
+ # @return [Integer] the number of input/output pairs
65
+ def size
66
+ length / arity
67
+ end
68
+
69
+ # @param tuple_index [Integer]
70
+ # @return [Array] returns the tuple at tuple_index
71
+ def [](tuple_index)
72
+ absolute_index = arity * tuple_index
73
+ if arity > 1
74
+ Array.new(arity) do |value_index|
75
+ value_at(absolute_index + value_index)
76
+ end
77
+ else
78
+ value_at(absolute_index)
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def value_at(index)
85
+ type = Libevoasm.program_io_get_type self, index
86
+ case type
87
+ when :i64
88
+ Libevoasm.program_io_get_value_i64 self, index
89
+ when :f64
90
+ Libevoasm.program_io_get_value_f64 self, index
91
+ else
92
+ raise "unknown value type #{type}"
93
+ end
94
+ end
95
+
96
+ def load_tuples(ptr, flat_tuples, arity)
97
+ var_args = flat_tuples.flat_map do |tuple_value|
98
+ tuple_type, c_type = value_types tuple_value
99
+ [:io_val_type, tuple_type, c_type, tuple_value]
100
+ end
101
+
102
+ success = Libevoasm.program_io_init ptr, arity, *var_args
103
+
104
+ unless success
105
+ Libevoasm.program_io_unref ptr
106
+ raise Error.last
107
+ end
108
+ end
109
+
110
+ def value_types(value)
111
+ case value
112
+ when Float
113
+ [:f64, :double]
114
+ when Integer
115
+ [:i64, :int64]
116
+ else
117
+ raise ArgumentError,
118
+ "invalid tuple value '#{value}' of type '#{value.class}'"
119
+ end
120
+ end
121
+
122
+ def determine_arity(tuples)
123
+ arity = nil
124
+ tuples.each do |tuple|
125
+ tuple_arity = Array(tuple).size
126
+ if arity && arity != tuple_arity
127
+ raise ArgumentError,
128
+ "invalid arity for tuple '#{tuple}' (#{tuple_arity} for #{arity})"
129
+ end
130
+ arity = tuple_arity
131
+ end
132
+ arity || 0
133
+ end
134
+ end
135
+
136
+ # Represents a program's input
137
+ class Input < IO
138
+ end
139
+
140
+ # Represents a program's output
141
+ class Output < IO
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,8 @@
1
+ require 'evoasm'
2
+ require 'minitest/reporters'
3
+ require 'minitest/autorun'
4
+
5
+ $LOAD_PATH << File.join(Evoasm.test_dir, 'helpers')
6
+ $LOAD_PATH << File.join(Evoasm.test_dir, 'unit')
7
+
8
+ Minitest::Reporters.use!
@@ -1,3 +1,3 @@
1
1
  module Evoasm
2
- VERSION = "0.0.2.pre7"
2
+ VERSION = "0.1.0.pre2"
3
3
  end
data/lib/evoasm/x64.rb ADDED
@@ -0,0 +1,115 @@
1
+ require 'evoasm/libevoasm'
2
+ require 'evoasm/capstone'
3
+ require 'evoasm/x64/instruction'
4
+ require 'evoasm/x64/operand'
5
+ require 'evoasm/x64/parameters'
6
+
7
+ module Evoasm
8
+ module X64
9
+ unless Libevoasm.x64_init
10
+ raise Error.last
11
+ end
12
+
13
+ class << self
14
+ # Disassembles x86-64 machine code
15
+ # @param assembly [String] assembly
16
+ # @param address [Integer] optional address to show in the disassembly
17
+ # @return [String] disassembly
18
+ def disassemble(assembly, address = nil)
19
+ Evoasm::Capstone.disassemble_x64 assembly, address
20
+ end
21
+
22
+ # Encodes a x86-64 machine instruction
23
+ # @param instruction_name [Symbol] the name of the instruction
24
+ # @param parameters [X64::Parameters, Hash] the instruction parameters
25
+ # @param buffer [Buffer] the buffer to emit to, if omitted, the encoded instruction is retured as string
26
+ # @param basic [Boolean] whether to use the basic encoder
27
+ # @return [String, nil] the encoded machine code as string, or nil if a buffer was provided
28
+ def encode(instruction_name, parameters, buffer = nil, basic: false)
29
+ instruction(instruction_name).encode parameters, buffer, basic: basic
30
+ end
31
+
32
+ # @return [Array<Symbol>] a list of available registers
33
+ def registers
34
+ Libevoasm.enum_type(:x64_reg_id).symbols[0..-2]
35
+ end
36
+
37
+ # @return [Array<Symbol>] the list of supported CPU features (obtained via CPUID)
38
+ def features
39
+ feature_enum_type = Libevoasm.enum_type(:x64_feature)
40
+ arch_info = Libevoasm.get_arch_info :x64
41
+ features_as_flags = Libevoasm.arch_info_get_features arch_info
42
+ feature_enum_type.symbol_map.each_with_object({}) do |(k, v), features|
43
+ next if k == :none
44
+ supported = (features_as_flags & (1 << v)) != 0
45
+ features[k] = supported
46
+ end
47
+ end
48
+
49
+ # Gives an {Instruction} object for the given instruction name.
50
+ # @param instruction_name [Symbol] instruction name
51
+ # @return [Instruction]
52
+ def instruction(instruction_name)
53
+ Instruction.new Libevoasm.x64_inst(instruction_name), instruction_name
54
+ end
55
+
56
+ # Emits a stack frame for the given ABI
57
+ # @param abi [Symbol] the ABI to use
58
+ # @param buffer [Buffer] the buffer to emit to
59
+ # @return [void]
60
+ def emit_stack_frame(abi = :sysv, buffer)
61
+ unless Libevoasm.x64_emit_func_prolog abi, buffer
62
+ raise Error.last
63
+ end
64
+
65
+ yield
66
+
67
+ unless Libevoasm.x64_emit_func_epilog abi, buffer
68
+ raise Error.last
69
+ end
70
+ end
71
+
72
+ # Gives a list of instructions
73
+ # @param reg_types [Array] restrict to given register types (e.g. +:gp+ for general-purpose registers)
74
+ # @param operand_types [Array<Symbol>] restrict to instructions whose operands are of the specified types
75
+ # @param useless [Bool] whether to include useless instructions
76
+ # @param basic [Bool] restrict to instructions supported by the basic encoder
77
+ # @param features [Array<Symbol>] only give instructions covered by the specified feature set
78
+ # @return [Array<Symbol>] array of instruction names
79
+ def instruction_names(*reg_types, operand_types: [:reg, :rm, :imm], useless: false, basic: true, features: nil)
80
+ inst_id_enum_type = Libevoasm.enum_type(:x64_inst_id)
81
+ feature_enum_type = Libevoasm.enum_type(:x64_feature)
82
+ insts_flags_enum_type = Libevoasm.enum_type(:x64_insts_flags)
83
+ op_type_enum_type = Libevoasm.enum_type(:x64_operand_type)
84
+ reg_type_enum_type = Libevoasm.enum_type(:x64_reg_type)
85
+
86
+ flags = []
87
+
88
+ flags << :include_useless if useless
89
+ flags << :only_basic if basic
90
+ flags_as_flags = insts_flags_enum_type.flags flags, shift: false
91
+
92
+ features_as_flags =
93
+ if features.nil?
94
+ arch_info = Libevoasm.get_arch_info :x64
95
+ Libevoasm.arch_info_get_features arch_info
96
+ else
97
+ feature_enum_type.flags features, shift: true
98
+ end
99
+
100
+ op_types_as_flags = op_type_enum_type.flags operand_types, shift: true
101
+ reg_types_as_flags = reg_type_enum_type.flags reg_types, shift: true
102
+
103
+ n_insts = inst_id_enum_type[:none]
104
+ array = FFI::MemoryPointer.new :int, n_insts
105
+ len = Libevoasm.x64_insts(flags_as_flags, features_as_flags,
106
+ op_types_as_flags, reg_types_as_flags, array)
107
+
108
+ instruction_ids = array.read_array_of_type(:int, :read_int, len)
109
+
110
+ instruction_ids.map { |e| inst_id_enum_type[e] }
111
+ end
112
+
113
+ end
114
+ end
115
+ end