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
@@ -1,176 +0,0 @@
1
- require 'set'
2
-
3
- module Evoasm::Gen
4
- State = Struct.new(:children, :actions, :ret, :_local_params) do
5
- attr_accessor :id, :comment, :parents
6
-
7
- def initialize
8
- self.children = []
9
- self.parents = []
10
- self.actions = []
11
- self._local_params = []
12
- end
13
-
14
- def local_params
15
- child_local_params = children.map do |child, _, _|
16
- child.local_params
17
- end
18
- all_local_params = (_local_params + child_local_params)
19
- all_local_params.flatten!
20
- all_local_params.uniq!
21
-
22
- all_local_params
23
- end
24
-
25
- def add_local_param(param)
26
- if param.to_s[0] != '_'
27
- fail ArgumentError, 'params must start with underscore'
28
- end
29
-
30
- _local_params << param unless _local_params.include? param
31
- end
32
-
33
- protected def add_parent(parent)
34
- parents << parent unless parents.include? parent
35
- end
36
-
37
- def add_child(child, cond = nil, priority)
38
- child.add_parent self
39
- children << [child, cond, priority]
40
- end
41
-
42
- %i(sets asserts calls writes debugs).each do |name|
43
- action_name = name.to_s[0..-2].to_sym
44
- define_method name do
45
- actions.select { |action, _| action == action_name }
46
- .map { |_, args| args }
47
- end
48
- end
49
-
50
- private def roots
51
- return [self] if parents.empty?
52
- parents.flat_map(&:roots)
53
- end
54
-
55
- def root
56
- roots = roots()
57
- fail 'multiple roots' if roots.size > 1
58
- roots.first
59
- end
60
-
61
- def empty?
62
- actions.empty?
63
- end
64
-
65
- def terminal?
66
- children.empty?
67
- end
68
-
69
- def ret?
70
- ret != nil
71
- end
72
-
73
- def to_gv
74
- require 'gv'
75
-
76
- graph = GV::Graph.open 'ast'
77
- graph[:ranksep] = 1.5
78
- graph[:statesep] = 0.8
79
- __to_gv__ graph
80
- graph
81
- end
82
-
83
- def __to_gv__(graph, gv_parent = nil, cond = nil, attrs = {}, index = nil, seen = {})
84
- if seen.key?(self)
85
- # return
86
- else
87
- seen[self] = true
88
- end
89
-
90
- edge_label = ''
91
- state_label = ''
92
-
93
- if cond
94
- if cond.first == :else
95
- edge_label << "<b> else</b><br></br>\n"
96
- else
97
- edge_label << "<b> if</b> #{expr_to_s cond}<br></br>\n"
98
- end
99
- end
100
-
101
- if attrs
102
- attrs.each do |name, value|
103
- edge_label << "<b> #{name}</b>: #{value}<br></br>\n"
104
- end
105
- end
106
-
107
- actions.each do |name, args|
108
- state_label << send(:"label_#{name}", *args)
109
- end
110
-
111
- state_label << "<i>#{comment}</i>\n" if comment
112
-
113
- gv_state = graph.node object_id.to_s,
114
- shape: (self.ret? ? :house : (state_label.empty? ? :point : :box)),
115
- label: graph.html(state_label)
116
-
117
- children.each_with_index do |(child, cond, attrs), index|
118
- child.__to_gv__(graph, gv_state, cond, attrs, index, seen)
119
- end
120
-
121
- if gv_parent
122
- graph.edge gv_parent.name + '.' + gv_state.name + index.to_s,
123
- gv_parent, gv_state,
124
- label: graph.html(edge_label)
125
- end
126
-
127
- graph
128
- end
129
-
130
- private
131
-
132
- def label_set(name, value, _options = {})
133
- "<b>set</b> #{name} := #{expr_to_s value}<br></br>"
134
- end
135
-
136
- def label_assert(cond)
137
- "<b>assert</b> #{expr_to_s cond}<br></br>"
138
- end
139
-
140
- def label_call(name)
141
- "<b>call</b> #{name}<br></br>"
142
- end
143
-
144
- def label_debug(_format, *_args)
145
- ''
146
- end
147
-
148
- def label_write(value, size)
149
- label =
150
- if value.is_a?(Integer) && size.is_a?(Integer)
151
- if size == 8
152
- 'x%x' % value
153
- else
154
- "b%0#{size}b" % value
155
- end
156
- elsif size.is_a? Array
157
- Array(value).zip(Array(size)).map do |v, s|
158
- "#{expr_to_s v} [#{expr_to_s s}]"
159
- end.join ', '
160
- else
161
- "#{expr_to_s value} [#{expr_to_s size}]"
162
- end
163
- "<b>output</b> #{label}<br></br>"
164
- end
165
-
166
- def expr_to_s(pred)
167
- case pred
168
- when Array
169
- pred, *args = *pred
170
- "#{pred}(#{args.map { |a| expr_to_s(a) }.join(', ')})"
171
- else
172
- pred
173
- end
174
- end
175
- end
176
- end
@@ -1,152 +0,0 @@
1
- require 'evoasm/gen/state'
2
-
3
- module Evoasm::Gen
4
- module StateDSL
5
- LOWEST_PRIORITY = 999
6
-
7
- def self.included(base)
8
- base.send :extend, ClassMethods
9
- end
10
-
11
- module ClassMethods
12
- def state(name)
13
- f = instance_method(name)
14
- var_name = :"@#{name}"
15
-
16
- define_method(name) do
17
- return instance_variable_get var_name if instance_variable_defined? var_name
18
- instance_variable_set var_name, f.bind(self).call
19
- end
20
- end
21
- end
22
-
23
- class DSLState
24
- include StateDSL
25
-
26
- def initialize(state)
27
- @__state__ = state
28
- end
29
- end
30
-
31
- def comment(comment = nil)
32
- if comment
33
- @__state__.comment = comment
34
- else
35
- @__state__.comment
36
- end
37
- end
38
-
39
- def exec(name, args)
40
- @__state__.actions << [name, args]
41
- end
42
-
43
- def set(param, value, options = {})
44
- fail ArgumentError, 'nil not allowed' if value.nil?
45
- exec :set, [param.to_sym, value, options]
46
- @__state__.add_local_param param
47
- end
48
-
49
- def write(value = nil, size = nil)
50
- if Array === size && Array === value
51
- fail ArgumentError, 'values and sizes must have same length' unless value.size == size.size
52
- end
53
- exec :write, [value, size]
54
- end
55
-
56
- def unordered_writes(param_name, writes)
57
- exec :unordered_writes, [param_name, writes]
58
- end
59
-
60
- def call(func)
61
- exec :call, [func]
62
- end
63
-
64
- def access(op, modes)
65
- exec :access, [op, modes]
66
- end
67
-
68
- def recover_with(param, range = nil, **opts)
69
- @__state__.recovery << [param, range, opts]
70
- end
71
-
72
- def log(level, msg, *args)
73
- exec :log, [level, msg, *args]
74
- end
75
-
76
- def assert(*args)
77
- exec :assert, args
78
- end
79
-
80
- def calls?(name)
81
- @__state__.calls.include? name
82
- end
83
-
84
- def ret
85
- @__state__.ret = true
86
- end
87
-
88
- def error(code = nil, msg = nil, reg: nil, param: nil)
89
- exec :error, [code, msg, reg, param]
90
- ret
91
- end
92
-
93
- def to(child = nil, **attrs, &block)
94
- if child.nil?
95
- child = State.new
96
- instance_eval_with_state child, &block
97
- end
98
-
99
- @__state__.add_child child, nil, default_attrs(attrs)
100
- child
101
- end
102
-
103
- def lowest_priority
104
- @__state__.children.map { |_, _, attrs| attrs[:priority] }.max || 0
105
- end
106
-
107
- def default_attrs(attrs)
108
- { priority: lowest_priority + 1 }.merge attrs
109
- end
110
-
111
- def else_to(state = nil, &block)
112
- to_if(:else, state, priority: LOWEST_PRIORITY, &block)
113
- end
114
-
115
- def to_if(*args, **attrs, &block)
116
- if block
117
- child = State.new
118
- instance_eval_with_state child, &block
119
-
120
- args.compact!
121
- else
122
- child = args.pop
123
- end
124
-
125
- @__state__.add_child child, args, default_attrs(attrs)
126
- child
127
- end
128
-
129
- def self_state
130
- @__state__
131
- end
132
-
133
- def state(*args, &block)
134
- if args.size == 1 && State === args.first
135
- instance_eval_with_state(args.first, &block)
136
- else
137
- State.new(*args).tap do |s|
138
- instance_eval_with_state(s, &block)
139
- end
140
- end
141
- end
142
-
143
- def instance_eval_with_state(state, &block)
144
- prev_state = @__state__
145
- @__state__ = state
146
- result = instance_eval(&block) if block
147
- @__state__ = prev_state
148
-
149
- result
150
- end
151
- end
152
- end
@@ -1,27 +0,0 @@
1
- module Evoasm
2
- module Gen
3
- class StrIO < ::StringIO
4
- def indent(indent = nil)
5
- @indent ||= 0
6
-
7
- prev_indent = @indent
8
- @indent = indent || @indent + 1
9
- yield
10
- @indent = prev_indent
11
- end
12
-
13
- def indent_str
14
- ' ' * @indent
15
- end
16
-
17
- def puts(line = nil, eol: '')
18
- if line
19
- write indent_str if @indent
20
- super("#{line}#{eol}")
21
- else
22
- super()
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,1102 +0,0 @@
1
- require 'erubis'
2
- require 'evoasm/gen/strio'
3
- require 'evoasm/gen/enum'
4
- require 'evoasm/gen/name_util'
5
- require 'evoasm/gen/x64'
6
-
7
- module Evoasm
8
- module Gen
9
- class BaseTranslator
10
- include NameUtil
11
-
12
- PARAMS_ARG_HELPERS = %i(address_size operand_size disp_size)
13
- NO_ARCH_HELPERS = %i(log2)
14
-
15
- def acc_c_type
16
- name_to_c :bitmap128
17
- end
18
-
19
- def arch_c_type
20
- name_to_c arch
21
- end
22
-
23
- def param_val_c_type
24
- name_to_c 'arch_param_val'
25
- end
26
-
27
- def bitmap_c_type
28
- name_to_c 'bitmap'
29
- end
30
-
31
- def local_param?(name)
32
- name.to_s[0] == '_'
33
- end
34
-
35
- def arch_var_name(indep_arch = false)
36
- "#{indep_arch ? '((evoasm_arch *)' : ''}#{arch}#{indep_arch ? ')' : ''}"
37
- end
38
-
39
- def call_to_c(func, args, prefix = nil, eol: false)
40
- func_name = func.to_s.gsub('?', '_p')
41
-
42
- if prefix
43
- args.unshift arch_var_name(Array(prefix).first != arch)
44
- end
45
-
46
- "#{name_to_c func_name, prefix}(#{args.join ','})" + (eol ? ';' : '')
47
- end
48
-
49
- def params_c_args
50
- "#{param_val_c_type} *param_vals, "\
51
- "#{bitmap_c_type} *set_params"
52
- end
53
-
54
-
55
- def params_args
56
- %w(param_vals set_params)
57
- end
58
-
59
- def param_to_c(name)
60
- register_param name.to_sym
61
- param_name_to_c name
62
- end
63
-
64
- def register_param(name)
65
- return if local_param? name
66
- main_translator.register_param name
67
- registered_params << name
68
- end
69
-
70
- def helper_to_c(expr)
71
- if expr.first.is_a?(Array)
72
- fail expr.inspect unless expr.size == 1
73
- expr = expr.first
74
- end
75
-
76
- name, *args = simplify_helper expr
77
- case name
78
- when :eq, :gt, :lt, :gtq, :ltq
79
- "(#{expr_to_c args[0]} #{cmp_helper_to_c name} #{expr_to_c args[1]})"
80
- when :if
81
- "(#{expr_to_c args[0]} ? (#{expr_to_c args[1]}) : #{expr_to_c args[2]})"
82
- when :neg
83
- "~(#{expr_to_c args[0]})"
84
- when :shl
85
- infix_op_to_c '<<', args
86
- when :mod
87
- infix_op_to_c '%', args
88
- when :div
89
- infix_op_to_c '/', args
90
- when :add
91
- infix_op_to_c '+', args
92
- when :sub
93
- infix_op_to_c '-', args
94
- when :set?
95
- set_p_to_c(*args)
96
- when :not
97
- "!(#{expr_to_c args[0]})"
98
- when :max, :min
99
- "#{name.to_s.upcase}(#{args.map { |a| expr_to_c a }.join(', ')})"
100
- when :and
101
- infix_op_to_c '&&', args
102
- when :or
103
- infix_op_to_c '||', args
104
- when :in?
105
- args[1..-1].map { |a| "#{expr_to_c args[0]} == #{expr_to_c a}" }
106
- .join(" ||\n#{io.indent_str + ' '}")
107
- else
108
- if !name.is_a?(Symbol)
109
- fail unless args.empty?
110
- expr_to_c name
111
- else
112
- call_args = args.map { |a| expr_to_c(a) }
113
- call_args.concat params_args if PARAMS_ARG_HELPERS.include? name
114
- if name == :reg_code
115
- call_args[0] = "(evoasm_#{arch}_reg_id) #{call_args[0]}"
116
- end
117
- helper_call_to_c name, call_args
118
- end
119
- end
120
- end
121
-
122
- def expr_to_c(expr, const_prefix: nil)
123
- case expr
124
- when Array
125
- helper_to_c expr
126
- when TrueClass
127
- 'true'
128
- when FalseClass
129
- 'false'
130
- when Numeric
131
- expr
132
- when Symbol, String
133
- s = expr.to_s
134
- if s != s.upcase
135
- get_to_c s
136
- else
137
- if X64::REGISTER_NAMES.include?(s.to_sym)
138
- const_prefix = [arch, 'reg']
139
- elsif s =~ /^INT\d+_(MAX|MIN)$/
140
- const_prefix = nil
141
- end
142
-
143
- name_to_c s, const_prefix, const: true
144
- end
145
- else
146
- fail "invalid expression #{expr.inspect}"
147
- end
148
- end
149
-
150
- def func_prototype_to_c(name, func_params = [], static: true)
151
- func_name = name_to_c name, arch
152
-
153
- func_params_c =
154
- if func_params.empty?
155
- ''
156
- else
157
- func_params.map do |param_name, type|
158
- "#{type} #{param_name}"
159
- end.join(', ').prepend ', '
160
- end
161
- "#{static ? 'static ' : ''}evoasm_success\n#{func_name}(#{arch_c_type} *#{arch_var_name},"\
162
- " #{params_c_args}#{func_params_c})"
163
- end
164
- end
165
-
166
- class FuncTranslator < BaseTranslator
167
- INST_STATE_ID_MIN = 32
168
- INST_STATE_ID_MAX = 2000
169
-
170
- attr_reader :inst, :registered_params, :root_state
171
- attr_reader :main_translator, :id_map
172
- attr_reader :arch, :io, :param_domains
173
-
174
- def initialize(arch, main_translator)
175
- @arch = arch
176
- @main_translator = main_translator
177
- @id = INST_STATE_ID_MAX
178
- @id_map = Hash.new { |h, k| h[k] = (@id += 1) }
179
- @registered_params = Set.new
180
- @param_domains = {}
181
- end
182
-
183
- def with_io(io)
184
- @io = io
185
- yield
186
- @io = nil
187
- end
188
-
189
- def pref_func_name(id)
190
- "prefs_#{id}"
191
- end
192
-
193
- def inst_id_c_type
194
- name_to_c :inst_id
195
- end
196
-
197
- def called_func_name(func, id)
198
- attrs = func.each_pair.map { |k, v| [k, v].join('_') }.flatten.join('__')
199
- "#{func.class.name.split('::').last.downcase}_#{attrs}_#{id}"
200
- end
201
-
202
- def emit_func(name, root_state, func_params = [], local_acc: true, static: true)
203
- io.puts func_prototype_to_c(name, func_params, static: static), eol: ' {'
204
-
205
- io.indent do
206
- emit_func_prolog root_state, local_acc
207
- emit_state root_state
208
- emit_func_epilog local_acc
209
- end
210
-
211
-
212
- io.puts '}'
213
- io.puts
214
- end
215
-
216
- def emit_acc_ary_copy(back_copy = false)
217
- var_name = 'acc'
218
- src = "#{arch_var_name arch_indep: true}->#{var_name}"
219
- dst = var_name
220
-
221
- dst, src = src, dst if back_copy
222
- io.puts "#{dst} = #{src};"
223
- end
224
-
225
- def emit_func_prolog(root_state, acc)
226
- local_params = root_state.local_params
227
- unless local_params.empty?
228
- io.puts "#{param_val_c_type} #{local_params.join ', '};"
229
- local_params.each do |param|
230
- io.puts "(void) #{param};"
231
- end
232
- end
233
-
234
- io.puts 'bool retval = true;'
235
-
236
- if acc
237
- io.puts "#{acc_c_type} acc;"
238
- emit_acc_ary_copy
239
- end
240
- end
241
-
242
- def error_data_field_to_c(field_name)
243
- "#{arch_var_name arch_indep: true}->error_data.#{field_name}"
244
- end
245
-
246
- def emit_error(state, code, msg, reg = nil, param = nil)
247
- reg_c_val =
248
- if reg
249
- reg_name_to_c reg
250
- else
251
- "(uint8_t) -1"
252
- end
253
- param_c_val =
254
- if param
255
- param_to_c param
256
- else
257
- "(uint8_t) -1"
258
- end
259
-
260
- io.write <<-EOL
261
- evoasm_arch_error_data error_data = {
262
- .reg = #{reg_c_val},
263
- .param = #{param_c_val},
264
- .arch = #{arch_var_name arch_indep: true},
265
- };
266
- EOL
267
-
268
- io.puts %Q{evoasm_set_error(EVOASM_ERROR_TYPE_ARCH, #{error_code_to_c code}, &error_data, "#{msg}");}
269
- io.puts 'retval = false;'
270
- end
271
-
272
- def emit_func_epilog(acc)
273
- io.indent 0 do
274
- io.puts "exit:"
275
- end
276
- emit_acc_ary_copy true if acc
277
- io.puts "return retval;"
278
-
279
- io.indent 0 do
280
- io.puts "error:"
281
- end
282
-
283
- io.puts 'retval = false;'
284
- io.puts 'goto exit;'
285
- end
286
-
287
- def emit_state(state)
288
- fail if state.nil?
289
-
290
- unemitted_states = []
291
-
292
- fail if state.ret? && !state.terminal?
293
-
294
- emit_body state, unemitted_states
295
-
296
- unemitted_states.each do |unemitted_state|
297
- emit_state unemitted_state
298
- end
299
- end
300
-
301
- def emit_body(state, unemitted_states, inlined = false)
302
- fail state.actions.inspect unless deterministic?(state)
303
- io.puts '/* begin inlined */' if inlined
304
-
305
- emit_label state unless inlined
306
-
307
- actions = state.actions.dup.reverse
308
- emit_actions state, actions, unemitted_states
309
-
310
- emit_ret state if state.ret?
311
-
312
- emit_transitions(state, unemitted_states)
313
-
314
- io.puts '/* end inlined */' if inlined
315
- end
316
-
317
- def emit_comment(state)
318
- io.puts "/* #{state.comment} (#{state.object_id}) */" if state.comment
319
- end
320
-
321
- def emit_label(state)
322
- io.indent 0 do
323
- io.puts "#{state_label state}:;"
324
- end
325
- end
326
-
327
- def has_else?(state)
328
- state.children.any? { |_, cond| cond == [:else] }
329
- end
330
-
331
- def emit_ret(state)
332
- io.puts "goto exit;"
333
- end
334
-
335
- def state_label(state, id = nil)
336
- "L#{id || id_map[state]}"
337
- end
338
-
339
- def emit_call(state, func)
340
- id = main_translator.request_func_call func, self
341
-
342
- func_call = call_to_c called_func_name(func, id),
343
- [*params_args, inst_name_to_c(inst), '&acc'],
344
- arch_prefix
345
-
346
- io.puts "if(!#{func_call}){goto error;}"
347
- end
348
-
349
- def emit_goto_transition(child)
350
- io.puts "goto #{state_label child};"
351
- end
352
-
353
- def emit_transitions(state, unemitted_states, &block)
354
- state
355
- .children
356
- .sort_by { |_, _, attrs| attrs[:priority] }
357
- .each do |child, expr|
358
- emit_cond expr do
359
- if inlineable?(child)
360
- block[] if block
361
- emit_body(child, unemitted_states, true)
362
- true
363
- else
364
- unemitted_states << child unless id_map.key?(child)
365
- block[] if block
366
- emit_goto_transition(child)
367
- false
368
- end
369
- end
370
- end
371
-
372
- fail 'missing else branch' if can_get_stuck?(state)
373
- end
374
-
375
- def can_get_stuck?(state)
376
- return false if state.ret?
377
- return false if has_else? state
378
-
379
- fail state.actions.inspect if state.children.empty?
380
-
381
- return false if state.children.any? do |_child, cond|
382
- cond.nil? || cond == [true]
383
- end
384
-
385
- true
386
- end
387
-
388
- def helper_call_to_c(name, args)
389
- prefix =
390
- if NO_ARCH_HELPERS.include?(name)
391
- nil
392
- else
393
- arch_prefix
394
- end
395
-
396
- call_to_c name, args, prefix
397
- end
398
-
399
- def simplify_helper(helper)
400
- simplified_helper = simplify_helper_ helper
401
- return simplified_helper if simplified_helper == helper
402
- simplify_helper simplified_helper
403
- end
404
-
405
- def simplify_helper_(helper)
406
- name, *args = helper
407
- case name
408
- when :neq
409
- [:not, [:eq, *args]]
410
- when :false?
411
- [:eq, *args, 0]
412
- when :true?
413
- [:not, [:false?, *args]]
414
- when :unset?
415
- [:not, [:set?, args[0]]]
416
- when :in?
417
- [:or, *args[1..-1].map { |arg| [:eq, args.first, arg] }]
418
- when :not_in?
419
- [:not, [:in?, *args]]
420
- else
421
- helper
422
- end
423
- end
424
-
425
- def emit_cond(cond, else_if: false, &block)
426
- cond_str =
427
- if cond.nil? || cond == true
428
- ''
429
- elsif cond[0] == :else
430
- 'else '
431
- else
432
- "#{else_if ? 'else ' : ''}if(#{expr_to_c cond})"
433
- end
434
-
435
- emit_c_block cond_str, &block
436
- end
437
-
438
- def emit_log(_state, level, msg, *exprs)
439
- expr_part =
440
- if !exprs.empty?
441
- ", #{exprs.map { |expr| "(#{param_val_c_type}) #{expr_to_c expr}" }.join(', ')}"
442
- else
443
- ''
444
- end
445
- msg = msg.gsub('%', '%" EVOASM_PARAM_VAL_FORMAT "')
446
- io.puts %[evoasm_#{level}("#{msg}" #{expr_part});]
447
- end
448
-
449
- def emit_assert(_state, *expr)
450
- io.puts "assert(#{expr_to_c expr});"
451
- end
452
-
453
- def set_p_to_c(key, eol: false)
454
- call_to_c 'bitmap_get',
455
- ["(#{bitmap_c_type} *) set_params", param_to_c(key)],
456
- eol: eol
457
- end
458
-
459
- def get_to_c(key, eol: false)
460
- if local_param? key
461
- key.to_s
462
- else
463
- "param_vals[#{param_to_c(key)}]" + (eol ? ';' : '')
464
- end
465
- end
466
-
467
- def emit_set(_state, key, value, c_value: false)
468
- fail "setting non-local param '#{key}' is not allowed" unless local_param? key
469
-
470
- c_value =
471
- if c_value
472
- value
473
- else
474
- expr_to_c value
475
- end
476
-
477
- io.puts "#{key} = #{c_value};"
478
- end
479
-
480
- def merge_params(params)
481
- params.each do |param|
482
- register_param param
483
- end
484
- end
485
-
486
- def cmp_helper_to_c(name)
487
- case name
488
- when :eq then '=='
489
- when :gt then '>'
490
- when :lt then '<'
491
- when :gtq then '>='
492
- when :ltq then '<='
493
- else
494
- fail
495
- end
496
- end
497
-
498
- def infix_op_to_c(op, args)
499
- "(#{args.map { |a| expr_to_c a }.join(" #{op} ")})"
500
- end
501
-
502
- def emit_actions(state, actions, _unemitted_states)
503
- io.puts '/* actions */'
504
- until actions.empty?
505
- name, args = actions.last
506
- actions.pop
507
- send :"emit_#{name}", state, *args
508
- end
509
- end
510
-
511
- def deterministic?(state)
512
- n_children = state.children.size
513
-
514
- n_children <= 1 ||
515
- (n_children == 2 && has_else?(state))
516
- end
517
-
518
- def inlineable?(state)
519
- state.parents.size == 1 &&
520
- deterministic?(state.parents.first)
521
- end
522
-
523
- def emit_c_block(code = nil, &block)
524
- io.puts "#{code}{"
525
- io.indent do
526
- block[]
527
- end
528
- io.puts '}'
529
- end
530
-
531
- def emit_unordered_writes(state, param_name, writes)
532
- if writes.size > 1
533
- id, table_size = main_translator.request_pref_func writes, self
534
- func_name = pref_func_name(id)
535
-
536
- call_c = call_to_c(func_name,
537
- [*params_args, param_name_to_c(param_name)],
538
- arch_prefix)
539
-
540
- io.puts call_c, eol: ';'
541
-
542
- register_param param_name
543
- @param_domains[param_name] = (0..table_size - 1)
544
- elsif writes.size > 0
545
- cond, write_args = writes.first
546
- emit_cond cond do
547
- emit_write(state, *write_args)
548
- end
549
- end
550
- end
551
-
552
- def emit_read_access(state, op)
553
- call = access_call_to_c 'read', op, "#{arch_var_name(true)}->acc",
554
- [inst && inst_name_to_c(inst) || 'inst']
555
-
556
- #emit_c_block "if(!#{call})" do
557
- # emit_exit error: true
558
- #end
559
- io.puts call, eol: ';'
560
- end
561
-
562
- def access_call_to_c(name, op, acc = 'acc', params = [], eol: false)
563
- call_to_c("#{name}_access",
564
- [
565
- "(#{bitmap_c_type} *) &#{acc}",
566
- "(#{regs.c_type}) #{expr_to_c(op)}",
567
- *params
568
- ],
569
- indep_arch_prefix,
570
- eol: eol)
571
- end
572
-
573
- def emit_write_access(_state, op)
574
- io.puts access_call_to_c('write', op, eol: true)
575
- end
576
-
577
- def emit_undefined_access(_state, op)
578
- io.puts access_call_to_c('undefined', op, eol: true)
579
- end
580
-
581
- def write_to_c(value, size)
582
- if size.is_a?(Array) && value.is_a?(Array)
583
- value_c, size_c = value.reverse.zip(size.reverse).inject(['0', 0]) do |(v_, s_), (v, s)|
584
- [v_ + " | ((#{expr_to_c v} & ((1 << #{s}) - 1)) << #{s_})", s_ + s]
585
- end
586
- else
587
- value_c =
588
- case value
589
- when Integer
590
- '0x' + value.to_s(16)
591
- else
592
- expr_to_c value
593
- end
594
-
595
- size_c = expr_to_c size
596
- end
597
-
598
- call_to_c "write#{size_c}", [value_c], indep_arch_prefix, eol: true
599
- end
600
-
601
- def emit_write(_state, value, size)
602
- io.puts write_to_c(value, size)
603
- end
604
-
605
- def emit_access(state, op, access)
606
- #access.each do |mode|
607
- # case mode
608
- # when :r
609
- # emit_read_access state, op
610
- # when :w
611
- # emit_write_access state, op
612
- # when :u
613
- # emit_undefined_access state, op
614
- # else
615
- # fail "unexpected access mode '#{rw.inspect}'"
616
- # end
617
- #end
618
- end
619
-
620
- def emit_inst_func(io, inst)
621
- @inst = inst
622
- with_io io do
623
- emit_func inst.name, inst.root_state, static: false
624
- end
625
- end
626
-
627
- def emit_called_func(io, func, id)
628
- with_io io do
629
- emit_func(called_func_name(func, id),
630
- func.root_state,
631
- {'inst' => inst_id_c_type, 'acc' => "#{acc_c_type} *"},
632
- local_acc: false)
633
- end
634
- end
635
-
636
- def emit_pref_func(io, writes, id)
637
- with_io io do
638
- table_var_name, _table_size = main_translator.request_permutation_table writes.size
639
- func_name = name_to_c pref_func_name(id), arch_prefix
640
-
641
- emit_c_block "static void\n#{func_name}(#{arch_c_type} *#{arch_var_name},"\
642
- " #{params_c_args}, #{main_translator.param_names.c_type} order)" do
643
- io.puts 'int i;'
644
- emit_c_block "for(i = 0; i < #{writes.size}; i++)" do
645
- emit_c_block "switch(#{table_var_name}[param_vals[order]][i])" do
646
- writes.each_with_index do |write, index|
647
- cond, write_args = write
648
- emit_c_block "case #{index}:" do
649
- emit_cond cond do
650
- io.puts write_to_c(*write_args)
651
- end
652
- io.puts 'break;'
653
- end
654
- end
655
- io.puts "default: evoasm_assert_not_reached();"
656
- end
657
- end
658
- end
659
- end
660
- end
661
- end
662
-
663
- class Translator < BaseTranslator
664
- attr_reader :params, :param_names
665
- attr_reader :id_map, :arch
666
- attr_reader :options
667
- attr_reader :features, :inst_flags
668
- attr_reader :reg_names, :exceptions
669
- attr_reader :reg_types, :operand_types
670
- attr_reader :bit_masks
671
- attr_reader :insts, :regs
672
- attr_reader :registered_param_domains
673
-
674
- STATIC_PARAMS = %i(reg0 reg1 reg2 reg3 reg4 imm operand_size address_size)
675
- PARAM_ALIASES = { imm0: :imm }
676
-
677
- def initialize(arch, insts, options = {})
678
- @arch = arch
679
- @insts = insts
680
- @pref_funcs = {}
681
- @called_funcs = {}
682
- @options = options
683
- @registered_param_domains = Set.new
684
-
685
- load_enums
686
- end
687
-
688
- def self.target_filename(arch, header: false)
689
- "evoasm-#{arch}.#{header ? 'h' : 'c'}"
690
- end
691
-
692
- def self.template_path(arch, header: false)
693
- File.join Evoasm.data, 'templates', "#{target_filename(arch, header: header)}.erb"
694
- end
695
-
696
- def translate!(&block)
697
- case arch
698
- when :x64
699
- translate_x64(&block)
700
- else
701
- fail "unsupported architecture #{@arch}"
702
- end
703
- end
704
-
705
- def main_translator
706
- self
707
- end
708
-
709
- def register_param(name)
710
- param_names.add name, PARAM_ALIASES[name]
711
- end
712
-
713
- def request_pref_func(writes, translator)
714
- _, table_size = request_permutation_table(writes.size)
715
- [request(@pref_funcs, writes, translator), table_size]
716
- end
717
-
718
- def request_func_call(func, translator)
719
- request @called_funcs, func, translator
720
- end
721
-
722
- def request_permutation_table(n)
723
- @permutation_tables ||= Hash.new { |h, k| h[k] = (0...k).to_a.permutation }
724
- [permutation_table_var_name(n), @permutation_tables[n].size]
725
- end
726
-
727
- private
728
- def load_enums
729
- @param_names = Enum.new :param_id, STATIC_PARAMS, prefix: arch
730
-
731
- case arch
732
- when :x64
733
- @features = Enum.new :feature, prefix: arch, flags: true
734
- @inst_flags = Enum.new :inst_flag, prefix: arch, flags: true
735
- @exceptions = Enum.new :exception_id, prefix: arch
736
- @reg_types = Enum.new :reg_type, Evoasm::Gen::X64::REGISTERS.keys, prefix: arch
737
- @operand_types = Enum.new :operand_type, Evoasm::Gen::X64::Inst::OPERAND_TYPES, prefix: arch
738
- @reg_names = Enum.new :reg_id, Evoasm::Gen::X64::REGISTER_NAMES, prefix: arch
739
- @bit_masks = Enum.new :bit_mask, %i(rest 64_127 32_63 0_31), prefix: arch, flags: true
740
- end
741
- end
742
-
743
- def register_param_domain(domain)
744
- @registered_param_domains << domain
745
- end
746
-
747
- def translate_x64(&block)
748
- translate_x64_c(&block)
749
-
750
- # NOTE: must be done after
751
- # translating C file
752
- # as we are collecting information
753
- # in the translation process
754
- translate_x64_h(&block)
755
- end
756
-
757
- def translate_x64_h(&block)
758
- target_filename = self.class.target_filename(arch, header: true)
759
- template_path = self.class.template_path(arch, header: true)
760
-
761
- renderer = Erubis::Eruby.new(File.read(template_path))
762
- block[target_filename, renderer.result(binding)]
763
- end
764
-
765
- def translate_x64_c(&block)
766
- target_filename = self.class.target_filename(arch)
767
- template_path = self.class.template_path(arch)
768
-
769
- # NOTE: keep in correct order
770
- inst_funcs = inst_funcs_to_c
771
- pref_funcs = pref_funcs_to_c
772
- permutation_tables = permutation_tables_to_c
773
- called_funcs = called_funcs_to_c
774
- insts_c = insts_to_c
775
- inst_operands = inst_operands_to_c
776
- inst_params = inst_params_to_c
777
- param_domains = param_domains_to_c
778
-
779
- renderer = Erubis::Eruby.new(File.read(template_path))
780
- block[target_filename, renderer.result(binding)]
781
- end
782
-
783
- def operand_c_type
784
- name_to_c :operand, arch_prefix
785
- end
786
-
787
- def param_c_type
788
- name_to_c :arch_param
789
- end
790
-
791
- def inst_params_var_name(inst)
792
- "params_#{inst.name}"
793
- end
794
-
795
- def insts_var_name
796
- "_evoasm_#{arch}_insts"
797
- end
798
-
799
- def inst_operands_var_name(inst)
800
- "operands_#{inst.name}"
801
- end
802
-
803
- def inst_param_domains_var_name(inst)
804
- "domains_#{inst.name}"
805
- end
806
-
807
- def param_domain_var_name(domain)
808
- case domain
809
- when Range
810
- "param_domain__#{domain.begin.to_s.tr('-', 'm')}_#{domain.end}"
811
- when Array
812
- "param_domain_enum__#{domain.join '_'}"
813
- else
814
- fail "unexpected domain type #{domain.class} (#{domain.inspect})"
815
- end
816
- end
817
-
818
- def permutation_table_var_name(n)
819
- "permutations#{n}"
820
- end
821
-
822
- def inst_encode_func_name(inst)
823
- name_to_c inst.name, arch_prefix
824
- end
825
-
826
- def inst_funcs_to_c(io = StrIO.new)
827
- @inst_translators = insts.map do |inst|
828
- @features.add_all inst.features
829
- @inst_flags.add_all inst.flags
830
- @exceptions.add_all inst.exceptions
831
-
832
- inst_translator = FuncTranslator.new arch, self
833
- inst_translator.emit_inst_func io, inst
834
-
835
- inst_translator
836
- end
837
-
838
- io.string
839
- end
840
-
841
- def permutation_tables_to_c(io = StrIO.new)
842
- Hash(@permutation_tables).each do |n, perms|
843
- io.puts "static int #{permutation_table_var_name n}"\
844
- "[#{perms.size}][#{perms.first.size}] = {"
845
-
846
- perms.each do |perm|
847
- io.puts " {#{perm.join ', '}},"
848
- end
849
- io.puts '};'
850
- io.puts
851
- end
852
-
853
- io.string
854
- end
855
-
856
- def called_funcs_to_c(io = StrIO.new)
857
- @called_funcs.each do |func, (id, translators)|
858
- func_translator = FuncTranslator.new arch, self
859
- func_translator.emit_called_func io, func, id
860
-
861
- translators.each do |translator|
862
- translator.merge_params func_translator.registered_params
863
- end
864
- end
865
-
866
- io.string
867
- end
868
-
869
- def inst_to_c(io, inst, params)
870
- io.puts '{'
871
- io.indent do
872
- io.puts '{'
873
- io.indent do
874
- io.puts inst_name_to_c(inst), eol: ','
875
- io.puts params.size, eol: ','
876
- if params.empty?
877
- io.puts "NULL,"
878
- else
879
- io.puts "(#{param_c_type} *)" + inst_params_var_name(inst), eol: ','
880
- end
881
- io.puts '(evoasm_inst_encode_func)' + inst_encode_func_name(inst), eol: ','
882
- end
883
- io.puts '},'
884
-
885
- io.puts "#{features_bitmap(inst)}ull", eol: ','
886
- if inst.operands.empty?
887
- io.puts 'NULL,'
888
- else
889
- io.puts "(#{operand_c_type} *)#{inst_operands_var_name inst}", eol: ','
890
- end
891
- io.puts inst.operands.size, eol: ','
892
- io.puts exceptions_bitmap(inst), eol: ','
893
- io.puts inst_flags_to_c(inst)
894
- end
895
- io.puts '},'
896
- end
897
-
898
- def insts_to_c(io = StrIO.new)
899
- io.puts "static const evoasm_x64_inst #{insts_var_name}[] = {"
900
- @inst_translators.each do |translator|
901
- inst_to_c io, translator.inst, translator.registered_params
902
- end
903
- io.puts '};'
904
-
905
- io.string
906
- end
907
-
908
- def inst_param_to_c(io, inst, params, param_domains)
909
- if !params.empty?
910
- io.puts "static const #{param_c_type} #{inst_params_var_name inst}[] = {"
911
- io.indent do
912
- params.each do |param|
913
- next if local_param? param
914
-
915
- param_domain = param_domains[param] || inst.param_domain(param)
916
- register_param_domain param_domain
917
-
918
- io.puts '{'
919
- io.indent do
920
- io.puts param_name_to_c(param), eol: ','
921
- io.puts '(evoasm_domain *) &' + param_domain_var_name(param_domain)
922
- end
923
- io.puts '},'
924
- end
925
- end
926
- io.puts '};'
927
- io.puts
928
- end
929
- end
930
-
931
- def inst_params_to_c(io = StrIO.new)
932
- @inst_translators.each do |translator|
933
- inst_param_to_c io, translator.inst, translator.registered_params, translator.param_domains
934
- end
935
-
936
- io.string
937
- end
938
-
939
- def inst_operand_to_c(translator, op, io = StrIO.new, eol:)
940
- io.puts '{'
941
- io.indent do
942
- io.puts op.access.include?(:r) ? '1' : '0', eol: ','
943
- io.puts op.access.include?(:w) ? '1' : '0', eol: ','
944
- io.puts op.access.include?(:u) ? '1' : '0', eol: ','
945
- io.puts op.access.include?(:c) ? '1' : '0', eol: ','
946
- io.puts op.implicit? ? '1' : '0', eol: ','
947
-
948
- params = translator.registered_params.reject{|p| local_param? p}
949
- if op.param
950
- param_idx = params.index(op.param) or \
951
- raise "param #{op.param} not found in #{translator.params.inspect}" \
952
- " (#{translator.inst.mnem}/#{translator.inst.index})"
953
-
954
- io.puts param_idx, eol: ','
955
- else
956
- io.puts params.size, eol: ','
957
- end
958
-
959
- io.puts operand_type_to_c(op.type), eol: ','
960
-
961
- if op.size
962
- io.puts operand_size_to_c(op.size), eol: ','
963
- else
964
- io.puts 'EVOASM_N_OPERAND_SIZES', eol: ','
965
- end
966
-
967
- if op.reg
968
- io.puts reg_name_to_c(op.reg), eol: ','
969
- else
970
- io.puts reg_names.n_elem_to_c, eol: ','
971
- end
972
-
973
- if op.reg_type
974
- io.puts reg_type_to_c(op.reg_type), eol: ','
975
- else
976
- io.puts reg_types.n_elem_to_c, eol: ','
977
- end
978
-
979
- if op.accessed_bits.key? :w
980
- io.puts bit_mask_to_c(op.accessed_bits[:w])
981
- else
982
- io.puts bit_masks.all_to_c
983
- end
984
- end
985
- io.puts '}', eol: eol
986
- end
987
-
988
- def inst_operands_to_c(io = StrIO.new)
989
- @inst_translators.each do |translator|
990
- if !translator.inst.operands.empty?
991
- io.puts "static const #{operand_c_type} #{inst_operands_var_name translator.inst}[] = {"
992
- io.indent do
993
- translator.inst.operands.each do |op|
994
- inst_operand_to_c(translator, op, io, eol: ',')
995
- end
996
- end
997
- io.puts '};'
998
- io.puts
999
- end
1000
- end
1001
-
1002
- io.string
1003
- end
1004
-
1005
- ENUM_MAX_LENGTH = 32
1006
- def param_domain_to_c(io, domain, index)
1007
- domain_c =
1008
- case domain
1009
- when (:INT64_MIN..:INT64_MAX)
1010
- "{EVOASM_DOMAIN_TYPE_INTERVAL64, #{index}, #{0}, #{0}}"
1011
- when Range
1012
- min_c = expr_to_c domain.begin
1013
- max_c = expr_to_c domain.end
1014
- "{EVOASM_DOMAIN_TYPE_INTERVAL, #{index}, #{min_c}, #{max_c}}"
1015
- when Array
1016
- if domain.size > ENUM_MAX_LENGTH
1017
- raise 'enum exceeds maximal enum length of'
1018
- end
1019
- values_c = "#{domain.map { |expr| expr_to_c expr }.join ', '}"
1020
- "{EVOASM_DOMAIN_TYPE_ENUM, #{index}, #{domain.length}, {#{values_c}}}"
1021
- end
1022
-
1023
- domain_c_type =
1024
- case domain
1025
- when Range
1026
- 'evoasm_interval'
1027
- when Array
1028
- "evoasm_enum#{domain.size}"
1029
- end
1030
- io.puts "static const #{domain_c_type} #{param_domain_var_name domain} = #{domain_c};"
1031
- end
1032
-
1033
- def param_domains_to_c(io = StrIO.new)
1034
- registered_param_domains.each_with_index do |domain, index|
1035
- param_domain_to_c io, domain, index
1036
- end
1037
-
1038
- io.puts "const uint16_t evoasm_n_domains = #{registered_param_domains.size};"
1039
-
1040
- io.string
1041
- end
1042
-
1043
- def request(hash, key, translator)
1044
- id, translators = hash[key]
1045
- if id.nil?
1046
- id = hash.size
1047
- translators = []
1048
-
1049
- hash[key] = [id, translators]
1050
- end
1051
-
1052
- translators << translator
1053
- id
1054
- end
1055
-
1056
- def pref_funcs_to_c(io = StrIO.new)
1057
- @pref_funcs.each do |writes, (id, translators)|
1058
- func_translator = FuncTranslator.new arch, self
1059
- func_translator.emit_pref_func io, writes, id
1060
-
1061
- translators.each do |translator|
1062
- translator.merge_params func_translator.registered_params
1063
- end
1064
- end
1065
-
1066
- io.string
1067
- end
1068
-
1069
- def inst_flags_to_c(inst)
1070
- if inst.flags.empty?
1071
- "0"
1072
- else
1073
- inst.flags.map { |flag| inst_flag_to_c flag }
1074
- .join ' | '
1075
- end
1076
- end
1077
-
1078
- def features_bitmap(inst)
1079
- bitmap(features) do |flag, index|
1080
- inst.features.include?(flag)
1081
- end
1082
- end
1083
-
1084
- def exceptions_bitmap(inst)
1085
- bitmap(exceptions) do |flag, index|
1086
- inst.exceptions.include?(flag)
1087
- end
1088
- end
1089
-
1090
- def bitmap(enum, &block)
1091
- enum.keys.each_with_index.inject(0) do |acc, (flag, index)|
1092
- if block[flag, index]
1093
- acc | (1 << index)
1094
- else
1095
- acc
1096
- end
1097
- end
1098
- end
1099
-
1100
- end
1101
- end
1102
- end