evoasm 0.0.2.pre7 → 0.1.0.pre2

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