asmrepl 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,205 @@
1
+ require "fisk/helpers"
2
+
3
+ module ASMREPL
4
+ module MacOS
5
+ include Fiddle
6
+
7
+ def self.make_function name, args, ret
8
+ ptr = Handle::DEFAULT[name]
9
+ func = Function.new ptr, args, ret, name: name
10
+ define_singleton_method name, &func.to_proc
11
+ end
12
+
13
+ # from sys/mman.h on macOS
14
+ PROT_READ = 0x01
15
+ PROT_WRITE = 0x02
16
+ PROT_EXEC = 0x04
17
+ MAP_PRIVATE = 0x0002
18
+ MAP_SHARED = 0x0001
19
+ MAP_ANON = 0x1000
20
+
21
+ make_function "ptrace", [TYPE_INT, TYPE_INT, TYPE_VOIDP, TYPE_INT], TYPE_INT
22
+ make_function "memset", [TYPE_VOIDP, TYPE_INT, TYPE_SIZE_T], TYPE_VOID
23
+ make_function "strerror", [TYPE_INT], TYPE_CONST_STRING
24
+ make_function "mach_task_self", [], TYPE_VOIDP
25
+ make_function "task_threads", [TYPE_VOIDP, TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP
26
+ make_function "task_for_pid", [TYPE_VOIDP, TYPE_INT, TYPE_VOIDP], TYPE_INT
27
+ make_function "task_threads", [TYPE_VOIDP, TYPE_VOIDP, TYPE_VOIDP], TYPE_INT
28
+ make_function "thread_get_state", [TYPE_VOIDP, TYPE_INT, TYPE_VOIDP, TYPE_VOIDP], TYPE_INT
29
+ make_function "mmap", [TYPE_VOIDP,
30
+ TYPE_SIZE_T,
31
+ TYPE_INT,
32
+ TYPE_INT,
33
+ TYPE_INT,
34
+ TYPE_INT], TYPE_VOIDP
35
+
36
+ def self.mmap_jit size
37
+ ptr = mmap 0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANON, -1, 0
38
+ ptr.size = size
39
+ ptr
40
+ end
41
+
42
+ def self.jitbuffer size
43
+ Fisk::Helpers::JITBuffer.new mmap_jit(size), size
44
+ end
45
+
46
+ def self.traceme
47
+ raise unless ptrace(PT_TRACE_ME, 0, 0, 0).zero?
48
+ end
49
+
50
+ class ThreadState
51
+ fields = (<<-eostruct).scan(/uint64_t ([^;]*);/).flatten
52
+ struct x86_thread_state64_t {
53
+ uint64_t rax;
54
+ uint64_t rbx;
55
+ uint64_t rcx;
56
+ uint64_t rdx;
57
+ uint64_t rdi;
58
+ uint64_t rsi;
59
+ uint64_t rbp;
60
+ uint64_t rsp;
61
+ uint64_t r8;
62
+ uint64_t r9;
63
+ uint64_t r10;
64
+ uint64_t r11;
65
+ uint64_t r12;
66
+ uint64_t r13;
67
+ uint64_t r14;
68
+ uint64_t r15;
69
+ uint64_t rip;
70
+ uint64_t rflags;
71
+ uint64_t cs;
72
+ uint64_t fs;
73
+ uint64_t gs;
74
+ }
75
+ eostruct
76
+ fields.each_with_index do |field, i|
77
+ define_method(field) do
78
+ to_ptr[Fiddle::SIZEOF_INT64_T * i, Fiddle::SIZEOF_INT64_T].unpack1("l!")
79
+ end
80
+ end
81
+
82
+ define_singleton_method(:sizeof) do
83
+ fields.length * Fiddle::SIZEOF_INT64_T
84
+ end
85
+
86
+ def [] name
87
+ idx = fields.index(name)
88
+ return unless idx
89
+ to_ptr[Fiddle::SIZEOF_INT64_T * idx, Fiddle::SIZEOF_INT64_T].unpack1("l!")
90
+ end
91
+
92
+ def self.malloc
93
+ new Fiddle::Pointer.malloc sizeof
94
+ end
95
+
96
+ attr_reader :to_ptr
97
+
98
+ def initialize buffer
99
+ @to_ptr = buffer
100
+ end
101
+
102
+ define_method(:fields) do
103
+ fields
104
+ end
105
+
106
+ def to_s
107
+ buf = ""
108
+ fields.first(8).zip(fields.drop(8).first(8)).each do |l, r|
109
+ buf << "#{l.ljust(3)} #{sprintf("%#018x", send(l))}"
110
+ buf << " "
111
+ buf << "#{r.ljust(3)} #{sprintf("%#018x", send(r))}\n"
112
+ end
113
+
114
+ buf << "\n"
115
+
116
+ fields.drop(16).each do |reg|
117
+ buf << "#{reg.ljust(6)} #{sprintf("%#018x", send(reg))}\n"
118
+ end
119
+ buf
120
+ end
121
+
122
+ FLAGS = [
123
+ ['CF', 'Carry Flag'],
124
+ [nil, 'Reserved'],
125
+ ['PF', 'Parity Flag'],
126
+ [nil, 'Reserved'],
127
+ ['AF', 'Adjust Flag'],
128
+ [nil, 'Reserved'],
129
+ ['ZF', 'Zero Flag'],
130
+ ['SF', 'Sign Flag'],
131
+ ['TF', 'Trap Flag'],
132
+ ['IF', 'Interrupt Enable Flag'],
133
+ ['DF', 'Direction Flag'],
134
+ ['OF', 'Overflow Flag'],
135
+ ['IOPL_H', 'I/O privilege level High bit'],
136
+ ['IOPL_L', 'I/O privilege level Low bit'],
137
+ ['NT', 'Nested Task Flag'],
138
+ [nil, 'Reserved'],
139
+ ]
140
+
141
+ def flags
142
+ flags = rflags
143
+ f = []
144
+ FLAGS.each do |abbrv, _|
145
+ if abbrv && flags & 1 == 1
146
+ f << abbrv
147
+ end
148
+ flags >>= 1
149
+ end
150
+ f
151
+ end
152
+ end
153
+
154
+ PT_TRACE_ME = 0
155
+ PT_CONTINUE = 7
156
+
157
+ class Tracer
158
+ def initialize pid
159
+ @pid = pid
160
+ @target = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)
161
+
162
+ unless MacOS.task_for_pid(MacOS.mach_task_self, pid, @target.ref).zero?
163
+ raise "Couldn't get task pid. Did you run with sudo?"
164
+ end
165
+
166
+ @thread_list = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)
167
+ thread_count = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP)
168
+
169
+ raise unless MacOS.task_threads(@target, @thread_list.ref, thread_count).zero?
170
+
171
+ @thread = Fiddle::Pointer.new(@thread_list[0, Fiddle::SIZEOF_VOIDP].unpack1("l!"))
172
+ end
173
+
174
+ def wait
175
+ Process.waitpid @pid
176
+ end
177
+
178
+ def state
179
+ # Probably should use this for something
180
+ # count = thread_count[0]
181
+
182
+ # I can't remember what header I found this in, but it's from a macOS header
183
+ # :sweat-smile:
184
+ x86_THREAD_STATE64_COUNT = ThreadState.sizeof / Fiddle::SIZEOF_INT
185
+
186
+ # Same here
187
+ x86_THREAD_STATE64 = 4
188
+
189
+ state_count = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT64_T)
190
+ state_count[0, Fiddle::SIZEOF_INT64_T] = [x86_THREAD_STATE64_COUNT].pack("l!")
191
+
192
+ state = ThreadState.malloc
193
+ raise unless MacOS.thread_get_state(@thread, x86_THREAD_STATE64, state, state_count).zero?
194
+
195
+ state
196
+ end
197
+
198
+ def continue
199
+ unless MacOS.ptrace(MacOS::PT_CONTINUE, @pid, 1, 0).zero?
200
+ raise
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,101 @@
1
+ require "racc/parser"
2
+ require "ripper"
3
+ require "fisk"
4
+ require "set"
5
+ require "strscan"
6
+
7
+ module ASMREPL
8
+ class Lexer
9
+ INTEGER = /(?:[-+]?0b[0-1_,]+ (?# base 2)
10
+ |[-+]?(?:0(?!x)|[1-9][0-9_,]*) (?# base 10)
11
+ |[-+]?0x[0-9a-fA-F_,]+ (?# base 16))/x
12
+
13
+ def initialize input
14
+ @input = input
15
+ @scanner = StringScanner.new input
16
+ end
17
+
18
+ REGISTERS = Set.new Fisk::Registers.constants.map(&:to_s)
19
+ INSTRUCTIONS = Set.new Fisk::Instructions.constants.map(&:to_s)
20
+
21
+ def next_token
22
+ return if @scanner.eos?
23
+
24
+ if @scanner.scan(INTEGER)
25
+ [:on_int, @scanner.matched]
26
+ elsif @scanner.scan(/\[/)
27
+ [:on_lbracket, @scanner.matched]
28
+ elsif @scanner.scan(/\]/)
29
+ [:on_rbracket, @scanner.matched]
30
+ elsif @scanner.scan(/,/)
31
+ [:on_comma, @scanner.matched]
32
+ elsif @scanner.scan(/qword/)
33
+ [:qword, @scanner.matched]
34
+ elsif @scanner.scan(/dword/)
35
+ [:dword, @scanner.matched]
36
+ elsif @scanner.scan(/word/)
37
+ [:word, @scanner.matched]
38
+ elsif @scanner.scan(/byte/)
39
+ [:byte, @scanner.matched]
40
+ elsif @scanner.scan(/ptr/)
41
+ [:ptr, @scanner.matched]
42
+ elsif @scanner.scan(/rip/i)
43
+ [:on_rip, @scanner.matched]
44
+ elsif @scanner.scan(/int/i)
45
+ [:on_instruction, Fisk::Instructions::INT]
46
+ elsif @scanner.scan(/movabs/i)
47
+ [:on_instruction, Fisk::Instructions::MOV]
48
+ elsif @scanner.scan(/\w+/)
49
+ ident = @scanner.matched
50
+ if INSTRUCTIONS.include?(ident.upcase)
51
+ [:on_instruction, Fisk::Instructions.const_get(ident.upcase)]
52
+ elsif REGISTERS.include?(ident.upcase)
53
+ [:on_register, Fisk::Registers.const_get(ident.upcase)]
54
+ else
55
+ [:on_ident, @scanner.matched]
56
+ end
57
+ elsif @scanner.scan(/\s+/)
58
+ [:on_sp, @scanner.matched]
59
+ elsif @scanner.scan(/\+/)
60
+ [:plus, @scanner.matched]
61
+ elsif @scanner.scan(/-/)
62
+ [:minus, @scanner.matched]
63
+ else
64
+ raise
65
+ end
66
+ end
67
+ end
68
+
69
+ class Parser < Racc::Parser
70
+ def initialize
71
+ @registers = Set.new Fisk::Registers.constants.map(&:to_s)
72
+ @instructions = Set.new Fisk::Instructions.constants.map(&:to_s)
73
+ end
74
+
75
+ def parse input
76
+ @lexer = Lexer.new input
77
+ do_parse
78
+ end
79
+
80
+ def new_command mnemonic, arg1, arg2
81
+ [:command, mnemonic, arg1, arg2]
82
+ end
83
+
84
+ def new_tuple mnemonic, arg1
85
+ [:command, mnemonic, arg1]
86
+ end
87
+
88
+ def new_single mnemonic
89
+ [:command, mnemonic]
90
+ end
91
+
92
+ def next_token
93
+ while tok = @lexer.next_token
94
+ next if tok.first == :on_sp
95
+ return tok
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ require "asmrepl/parser.tab"
@@ -0,0 +1,297 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by Racc 1.5.1
4
+ # from Racc grammar file "".
5
+ #
6
+
7
+ require 'racc/parser.rb'
8
+ module ASMREPL
9
+ class Parser < Racc::Parser
10
+ ##### State transition tables begin ###
11
+
12
+ racc_action_table = [
13
+ 12, 3, 9, 4, 14, 18, 16, 15, 17, 10,
14
+ 11, 12, 8, 9, 19, 14, 20, 16, 15, 17,
15
+ 10, 11, 9, 8, 21, 35, 9, 37, 9, 10,
16
+ 11, 22, 8, 10, 11, 10, 11, 43, 9, 45,
17
+ 9, 8, 24, 8, 39, 10, 11, 10, 11, 25,
18
+ 26, 27, 28, 29, 41, 42, 47, 48 ]
19
+
20
+ racc_action_check = [
21
+ 2, 0, 2, 1, 2, 4, 2, 2, 2, 2,
22
+ 2, 19, 2, 19, 5, 19, 6, 19, 19, 19,
23
+ 19, 19, 20, 19, 10, 23, 23, 24, 24, 20,
24
+ 20, 11, 20, 23, 23, 24, 24, 39, 39, 40,
25
+ 40, 12, 12, 25, 25, 39, 39, 40, 40, 13,
26
+ 14, 15, 16, 17, 36, 38, 44, 46 ]
27
+
28
+ racc_action_pointer = [
29
+ -12, 3, -2, nil, 5, 9, 11, nil, nil, nil,
30
+ 20, 27, 27, 47, 43, 44, 45, 46, nil, 9,
31
+ 18, nil, nil, 22, 24, 29, nil, nil, nil, nil,
32
+ nil, nil, nil, nil, nil, nil, 51, nil, 52, 34,
33
+ 36, nil, nil, nil, 53, nil, 54, nil, nil ]
34
+
35
+ racc_action_default = [
36
+ -27, -27, -9, -10, -27, -6, -7, -8, -11, -12,
37
+ -27, -27, -27, -27, -27, -27, -27, -27, 49, -27,
38
+ -27, -13, -14, -27, -27, -27, -23, -24, -25, -26,
39
+ -1, -2, -3, -4, -5, -15, -27, -16, -27, -27,
40
+ -27, -20, -17, -18, -27, -21, -27, -19, -22 ]
41
+
42
+ racc_goto_table = [
43
+ 7, 1, 5, 2, nil, nil, 6, nil, nil, nil,
44
+ nil, nil, 23, nil, nil, nil, nil, 30, 34, 31,
45
+ 33, 36, 38, 32, nil, 40, nil, nil, nil, nil,
46
+ nil, nil, nil, nil, nil, nil, nil, 44, 46 ]
47
+
48
+ racc_goto_check = [
49
+ 4, 1, 3, 2, nil, nil, 5, nil, nil, nil,
50
+ nil, nil, 3, nil, nil, nil, nil, 4, 4, 3,
51
+ 3, 4, 4, 5, nil, 3, nil, nil, nil, nil,
52
+ nil, nil, nil, nil, nil, nil, nil, 4, 4 ]
53
+
54
+ racc_goto_pointer = [
55
+ nil, 1, 3, 0, -2, 4, nil ]
56
+
57
+ racc_goto_default = [
58
+ nil, nil, nil, nil, nil, nil, 13 ]
59
+
60
+ racc_reduce_table = [
61
+ 0, 0, :racc_error,
62
+ 4, 17, :_reduce_1,
63
+ 4, 17, :_reduce_2,
64
+ 4, 17, :_reduce_3,
65
+ 4, 17, :_reduce_4,
66
+ 4, 17, :_reduce_5,
67
+ 2, 17, :_reduce_6,
68
+ 2, 17, :_reduce_7,
69
+ 2, 17, :_reduce_8,
70
+ 1, 17, :_reduce_9,
71
+ 1, 18, :_reduce_10,
72
+ 1, 19, :_reduce_11,
73
+ 1, 20, :_reduce_12,
74
+ 2, 20, :_reduce_13,
75
+ 2, 20, :_reduce_14,
76
+ 3, 21, :_reduce_15,
77
+ 3, 21, :_reduce_16,
78
+ 4, 21, :_reduce_17,
79
+ 4, 21, :_reduce_18,
80
+ 5, 21, :_reduce_19,
81
+ 4, 21, :_reduce_20,
82
+ 4, 21, :_reduce_21,
83
+ 5, 21, :_reduce_22,
84
+ 2, 22, :_reduce_23,
85
+ 2, 22, :_reduce_24,
86
+ 2, 22, :_reduce_25,
87
+ 2, 22, :_reduce_26 ]
88
+
89
+ racc_reduce_n = 27
90
+
91
+ racc_shift_n = 49
92
+
93
+ racc_token_table = {
94
+ false => 0,
95
+ :error => 1,
96
+ :on_lbracket => 2,
97
+ :on_rbracket => 3,
98
+ :on_int => 4,
99
+ :on_comma => 5,
100
+ :qword => 6,
101
+ :ptr => 7,
102
+ :word => 8,
103
+ :dword => 9,
104
+ :byte => 10,
105
+ :plus => 11,
106
+ :minus => 12,
107
+ :on_instruction => 13,
108
+ :on_register => 14,
109
+ :on_rip => 15 }
110
+
111
+ racc_nt_base = 16
112
+
113
+ racc_use_result_var = true
114
+
115
+ Racc_arg = [
116
+ racc_action_table,
117
+ racc_action_check,
118
+ racc_action_default,
119
+ racc_action_pointer,
120
+ racc_goto_table,
121
+ racc_goto_check,
122
+ racc_goto_default,
123
+ racc_goto_pointer,
124
+ racc_nt_base,
125
+ racc_reduce_table,
126
+ racc_token_table,
127
+ racc_shift_n,
128
+ racc_reduce_n,
129
+ racc_use_result_var ]
130
+
131
+ Racc_token_to_s_table = [
132
+ "$end",
133
+ "error",
134
+ "on_lbracket",
135
+ "on_rbracket",
136
+ "on_int",
137
+ "on_comma",
138
+ "qword",
139
+ "ptr",
140
+ "word",
141
+ "dword",
142
+ "byte",
143
+ "plus",
144
+ "minus",
145
+ "on_instruction",
146
+ "on_register",
147
+ "on_rip",
148
+ "$start",
149
+ "command",
150
+ "instruction",
151
+ "register",
152
+ "int",
153
+ "memory",
154
+ "memsize" ]
155
+
156
+ Racc_debug_parser = false
157
+
158
+ ##### State transition tables end #####
159
+
160
+ # reduce 0 omitted
161
+
162
+ def _reduce_1(val, _values, result)
163
+ result = new_command(val[0], val[1], val[3])
164
+ result
165
+ end
166
+
167
+ def _reduce_2(val, _values, result)
168
+ result = new_command(val[0], val[1], val[3])
169
+ result
170
+ end
171
+
172
+ def _reduce_3(val, _values, result)
173
+ result = new_command(val[0], val[1], val[3])
174
+ result
175
+ end
176
+
177
+ def _reduce_4(val, _values, result)
178
+ result = new_command(val[0], val[1], val[3])
179
+ result
180
+ end
181
+
182
+ def _reduce_5(val, _values, result)
183
+ result = new_command(val[0], val[1], val[3])
184
+ result
185
+ end
186
+
187
+ def _reduce_6(val, _values, result)
188
+ result = new_tuple(val[0], val[1])
189
+ result
190
+ end
191
+
192
+ def _reduce_7(val, _values, result)
193
+ result = new_tuple(val[0], val[1])
194
+ result
195
+ end
196
+
197
+ def _reduce_8(val, _values, result)
198
+ result = new_tuple(val[0], val[1])
199
+ result
200
+ end
201
+
202
+ def _reduce_9(val, _values, result)
203
+ result = new_single(val[0])
204
+ result
205
+ end
206
+
207
+ def _reduce_10(val, _values, result)
208
+ result = [:instruction, val[0]]
209
+ result
210
+ end
211
+
212
+ def _reduce_11(val, _values, result)
213
+ result = [:register, val[0]]
214
+ result
215
+ end
216
+
217
+ def _reduce_12(val, _values, result)
218
+ result = [:int, Integer(val[0])]
219
+ result
220
+ end
221
+
222
+ def _reduce_13(val, _values, result)
223
+ result = [:int, Integer(val[1])]
224
+ result
225
+ end
226
+
227
+ def _reduce_14(val, _values, result)
228
+ result = [:int, -Integer(val[1])]
229
+ result
230
+ end
231
+
232
+ def _reduce_15(val, _values, result)
233
+ result = [:memory, Fisk::M64.new(val[1].last, 0)]
234
+ result
235
+ end
236
+
237
+ def _reduce_16(val, _values, result)
238
+ result = [:memory, Fisk::Registers::Rip.new(0)]
239
+ result
240
+ end
241
+
242
+ def _reduce_17(val, _values, result)
243
+ result = [:memory, Fisk::Registers::Rip.new(val[2].last)]
244
+ result
245
+ end
246
+
247
+ def _reduce_18(val, _values, result)
248
+ result = [:memory, Fisk::Registers::Rip.new(0)]
249
+ result
250
+ end
251
+
252
+ def _reduce_19(val, _values, result)
253
+ result = [:memory, Fisk::Registers::Rip.new(val[3].last)]
254
+ result
255
+ end
256
+
257
+ def _reduce_20(val, _values, result)
258
+ result = [:memory, Fisk::M64.new(val[1].last, val[2].last)]
259
+ result
260
+ end
261
+
262
+ def _reduce_21(val, _values, result)
263
+ result = [:memory, val[0].new(val[2].last, 0)]
264
+ result
265
+ end
266
+
267
+ def _reduce_22(val, _values, result)
268
+ result = [:memory, val[0].new(val[2].last, val[3].last)]
269
+ result
270
+ end
271
+
272
+ def _reduce_23(val, _values, result)
273
+ result = Fisk::M64
274
+ result
275
+ end
276
+
277
+ def _reduce_24(val, _values, result)
278
+ result = Fisk::M32
279
+ result
280
+ end
281
+
282
+ def _reduce_25(val, _values, result)
283
+ result = Fisk::M16
284
+ result
285
+ end
286
+
287
+ def _reduce_26(val, _values, result)
288
+ result = Fisk::M8
289
+ result
290
+ end
291
+
292
+ def _reduce_none(val, _values, result)
293
+ val[0]
294
+ end
295
+
296
+ end # class Parser
297
+ end # module ASMREPL
@@ -0,0 +1,44 @@
1
+ class ASMREPL::Parser
2
+ token on_lbracket on_rbracket on_int on_comma qword ptr word dword byte
3
+ token plus minus on_instruction on_register on_rip
4
+
5
+ rule
6
+
7
+ command: instruction register on_comma int { result = new_command(val[0], val[1], val[3]) }
8
+ | instruction register on_comma register { result = new_command(val[0], val[1], val[3]) }
9
+ | instruction register on_comma memory { result = new_command(val[0], val[1], val[3]) }
10
+ | instruction memory on_comma register { result = new_command(val[0], val[1], val[3]) }
11
+ | instruction memory on_comma int { result = new_command(val[0], val[1], val[3]) }
12
+ | instruction register { result = new_tuple(val[0], val[1]) }
13
+ | instruction memory { result = new_tuple(val[0], val[1]) }
14
+ | instruction int { result = new_tuple(val[0], val[1]) }
15
+ | instruction { result = new_single(val[0]) }
16
+ ;
17
+
18
+ instruction: on_instruction { result = [:instruction, val[0]] }
19
+ ;
20
+
21
+ register: on_register { result = [:register, val[0]] }
22
+ ;
23
+
24
+ int: on_int { result = [:int, Integer(val[0])] }
25
+ | plus on_int { result = [:int, Integer(val[1])] }
26
+ | minus on_int { result = [:int, -Integer(val[1])] }
27
+ ;
28
+
29
+ memory: on_lbracket register on_rbracket { result = [:memory, Fisk::M64.new(val[1].last, 0)] }
30
+ | on_lbracket on_rip on_rbracket { result = [:memory, Fisk::Registers::Rip.new(0)] }
31
+ | on_lbracket on_rip int on_rbracket { result = [:memory, Fisk::Registers::Rip.new(val[2].last)] }
32
+ | memsize on_lbracket on_rip on_rbracket { result = [:memory, Fisk::Registers::Rip.new(0)] }
33
+ | memsize on_lbracket on_rip int on_rbracket { result = [:memory, Fisk::Registers::Rip.new(val[3].last)] }
34
+ | on_lbracket register int on_rbracket { result = [:memory, Fisk::M64.new(val[1].last, val[2].last)] }
35
+ | memsize on_lbracket register on_rbracket { result = [:memory, val[0].new(val[2].last, 0)] }
36
+ | memsize on_lbracket register int on_rbracket { result = [:memory, val[0].new(val[2].last, val[3].last)] }
37
+ ;
38
+
39
+ memsize: qword ptr { result = Fisk::M64 }
40
+ | dword ptr { result = Fisk::M32 }
41
+ | word ptr { result = Fisk::M16 }
42
+ | byte ptr { result = Fisk::M8 }
43
+ ;
44
+ end