kompiler 0.3.3 → 0.3.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5938bafe84031bb6dfb99ab6452d66fb1da892a42520e5e05c274e2b89f0b73
4
- data.tar.gz: 8d80c58a6d2b689fbd3bfcd69f780cb2aa258c0f02d5b905c0b16b7d1b2c8a12
3
+ metadata.gz: 70dad0d1372236affa1fba712fff8b5a7d07d5cb99aa13fe41f4e39b92294901
4
+ data.tar.gz: 38345074dffd505b6ba7f99283bc851ed17e0d7afc7df684933e8bd3420854b6
5
5
  SHA512:
6
- metadata.gz: e79f4af903656d29d7d2a4b9b5b1c1e75f7bc10461d4a1e203d68b98c70420d920e13e651e263469a679e361349e7b4106b519a3712efa5185d5124cbe71c1ed
7
- data.tar.gz: b8065b466b2b5bca9234b7ba8fd00a5560914cc819cfa9c973884f5c489eed1d797d1eb1d633a47570629133c616caedff3ce6743d69502c7069715d1c0ae1ec
6
+ metadata.gz: 42997a073796509d38379a196c0caafd0dfa3e5ee3c0f588072dd936dd84220e4186a963d78f75525075d79a72d549667daaae79915f60629bdca3b51b06461e
7
+ data.tar.gz: 925cccfb86ddd19a56798b8af0070e7217678fa4a0d3159064057885e40790a26a3b7e07ccc4775bd2a93614f428082bab8c8b68fe13c18c191fd456a1236330
data/bin/kompile CHANGED
@@ -26,10 +26,18 @@ arg_letters = []
26
26
 
27
27
  current_i = 0
28
28
 
29
- permitted_word_chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["_", ".", "-"]
29
+ permitted_word_chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["_", ".", "-", "[", "]"]
30
30
 
31
31
  whitespace_chars = ["\t", " "]
32
32
 
33
+
34
+ $positive_opts = ["true", "yes"]
35
+ $negative_opts = ["false", "no"]
36
+
37
+ $bool_opts = $positive_opts + $negative_opts
38
+
39
+
40
+
33
41
  def get_word string, permitted_word_chars, offset = 0
34
42
  if string[0] == '"'
35
43
  str_content, n_parsed = Kompiler::Parsers.parse_str(string[offset..])
@@ -77,7 +85,17 @@ while current_i < arg_string.size
77
85
 
78
86
  letters, current_i = get_word(arg_string, permitted_word_chars, current_i)
79
87
 
80
- arg_letters += letters.chars
88
+ if arg_string[current_i] == "="
89
+ current_i += 1
90
+ value, current_i = get_word(arg_string, permitted_word_chars, current_i)
91
+
92
+ arg_keys << [letters, value]
93
+ elsif whitespace_chars.include?(arg_string[current_i]) || current_i == arg_string.size
94
+ arg_letters += letters.chars
95
+ else
96
+ puts "Unrecognized argument syntax at index #{current_i}"
97
+ exit
98
+ end
81
99
 
82
100
  next
83
101
  end
@@ -90,6 +108,44 @@ end
90
108
 
91
109
 
92
110
 
111
+
112
+ def get_number str
113
+ bool, val = Kompiler::Parsers.check_immediate_operand(str)
114
+ return (bool == false) ? nil : val
115
+ end
116
+
117
+
118
+ def get_arg_key arg_keys, keys, default_value=0
119
+ keys = [keys] if !keys.is_a?(Array)
120
+ filtered = arg_keys.filter{keys.include? _1[0]}[0]
121
+ value = (filtered != nil) ? filtered[1] : default_value
122
+ return value
123
+ end
124
+
125
+
126
+ class String
127
+ def to_num
128
+ status, val = Kompiler::Parsers.check_immediate_operand(self)
129
+ return (status == false) ? nil : val[:value]
130
+ end
131
+ end
132
+
133
+
134
+ def is_bool_opt opt
135
+ $bool_opts.include?(opt)
136
+ end
137
+
138
+ def is_pos_bool opt
139
+ $positive_opts.include? opt
140
+ end
141
+
142
+ def is_neg_bool opt
143
+ $negative_opts.include? opt
144
+ end
145
+
146
+
147
+
148
+
93
149
  # Print the help screen if requested
94
150
  if arg_opts.include?("help") || arg_letters.include?("h")
95
151
  puts """Usage: kompile <input_file> [<output_file>] [compile_options]
@@ -100,8 +156,10 @@ Compile a file:
100
156
  output_file Path to the output file (optional, default is out.bin)
101
157
 
102
158
  Compilation options:
103
- --arch=<arch_name> Compile for the specified architecture (optional, default is armv8a)
104
- --wrap=<format> Wrap the compiled program in the specified format (default is none)
159
+ --arch=<arch_name>, -ar Compile for the specified architecture (optional, default is armv8a)
160
+ --wrap=<format>, -w Wrap the compiled program in the specified format (default is none)
161
+ --no-aliases, -n Specifies whether to use the aliases configuration file (default is yes)
162
+ --aliases-file=<file>, -a Loads the provided aliases file instead of the usual one
105
163
 
106
164
  Available wrapping formats:
107
165
  none
@@ -111,31 +169,157 @@ Available wrapping formats:
111
169
  mach-o.exec
112
170
 
113
171
  Additional options for wrapping are:
114
- --elf-machine=<type> Specifies ELF header's e_machine to be the type provided (default is 0)
115
- --elf-class=<class> Specifies the ELF file's class to either 32 or 64 (default is 64)
116
- --mach-o-machine=<cputype.subtype> Specifies Mach-O header's cputype and subtype
117
- to be the type provided
118
- --mach-o-archtype=<type> Specifies the file architecture type to either 32 or 64 (default is 64)
119
- --exec-type=<type> Used with --wrap=mach-o.exec. Specifies whether the executable is
120
- statically (static) or dynamically (dylink) linked (default is dylink)
121
- --mach-o-threadstate=<type> Used with --wrap=mach-o.exec and --exec-type=static. Specifies which
122
- thread state type to use (arm64, arm32, x86-64 or x86-32)
123
- --codesign=<bool> Used with --wrap=mach-o.*. Specifies whether to add a basic
124
- code signature to the Mach-O file (default is false)
172
+ --elf-machine=<type>, -m Specifies ELF header's e_machine to be the type provided (default is 0)
173
+ --elf-class=<class>, -c Specifies the ELF file's class to either 32 or 64 (default is 64)
174
+ --mach-o-machine=<cputype.subtype>, -m Specifies Mach-O header's cputype and subtype
175
+ to be the type provided
176
+ --mach-o-archtype=<type>, -t Specifies the file architecture type to either 32 or 64 (default is 64)
177
+ --exec-type=<type>, -et Used with --wrap=mach-o.exec. Specifies whether the executable is
178
+ statically (static) or dynamically (dylink) linked (default is dylink)
179
+ --mach-o-threadstate=<type>, -ts Used with --wrap=mach-o.exec and --exec-type=static. Specifies which
180
+ thread state type to use (arm64, arm32, x86-64 or x86-32)
181
+ --codesign=<yes|no>, -cs Used with --wrap=mach-o.*. Specifies whether to add a basic
182
+ code signature to the Mach-O file (default is no)
125
183
 
126
184
  Available options:
127
- --help, -h Prints this information
128
- --list-architectures Lists available architectures
129
- --list-instructions [arch] Lists available instructions for the specified architecture
130
- --list-registers [arch] Lists available registers for the specified architecture
131
- --list-lexis Lists available lexis entries
185
+ --help, -h Prints this information
186
+ --list-architectures,-lar Lists available architectures
187
+ --list-instructions [arch],-li Lists available instructions for the specified architecture
188
+ --list-registers [arch],-lr Lists available registers for the specified architecture
189
+ --list-aliases,-la Lists instruction aliases in the current configuration
190
+ --compact,-c Used with --list-instructions or --list-registers to print compact information
191
+
192
+ Available options for controlling aliases:
193
+ --add-alias[es] index keyword aliases Add the specified aliases to the configuration
194
+ --remove-alias[es] index keyword aliases Remove the specified aliases from the configuration
195
+ --reset-aliases Resets aliases to an empty configuration
196
+ --import-aliases filename Set the provided configuration as the default aliases
197
+ --export-aliases filename Export the default aliases into a file
132
198
  """
133
199
  exit # Exit
134
200
  end
135
201
 
202
+ no_aliases = arg_opts.include?("no-aliases") || arg_letters.include?("n")
203
+
204
+ arg_opts.delete "no-aliases"
205
+ arg_letters.delete "n"
206
+
207
+ use_aliases = !no_aliases
208
+
209
+ aliases_file = get_arg_key(arg_keys, ["aliases-file", "a"], nil)
210
+
211
+ if aliases_file
212
+ aliases_file = File.expand_path(aliases_file)
213
+ end
214
+
215
+ if use_aliases
216
+ if aliases_file
217
+ Kompiler::AliasManager.import_aliases_file aliases_file
218
+ else
219
+ Kompiler::AliasManager.load_aliases()
220
+ end
221
+ end
222
+
223
+
224
+ if arg_opts == ["add-aliases"] || arg_opts == ["add-alias"]
225
+ idx = arg_words[0]
226
+ keyword = arg_words[1]
227
+ aliases = arg_words[2..]
228
+ if idx[0] == "[" && idx[-1] == "]"
229
+ idx = idx[1...-1]
230
+ end
231
+ idx = idx.to_i
232
+
233
+ Kompiler::AliasManager.add_alias idx, keyword, *aliases
234
+
235
+ if aliases_file
236
+ Kompiler::AliasManager.export_aliases_file aliases_file
237
+ else
238
+ Kompiler::AliasManager.save_aliases()
239
+ end
240
+
241
+ exit
242
+ end
243
+
244
+ if arg_opts == ["remove-aliases"] || arg_opts == ["remove-alias"]
245
+ idx = arg_words[0]
246
+ keyword = arg_words[1]
247
+ aliases = arg_words[2..]
248
+ if idx[0] == "[" && idx[-1] == "]"
249
+ idx = idx[1...-1]
250
+ end
251
+ idx = idx.to_i
252
+
253
+ Kompiler::AliasManager.remove_alias idx, keyword, *aliases
254
+
255
+ if aliases_file
256
+ Kompiler::AliasManager.export_aliases_file aliases_file
257
+ else
258
+ Kompiler::AliasManager.save_aliases()
259
+ end
260
+
261
+ exit
262
+ end
263
+
264
+
265
+ if arg_opts == ["reset-aliases"]
266
+ Kompiler::AliasManager.reset_aliases()
267
+
268
+ if aliases_file
269
+ Kompiler::AliasManager.export_aliases_file aliases_file
270
+ else
271
+ Kompiler::AliasManager.save_aliases()
272
+ end
273
+
274
+ exit
275
+ end
276
+
277
+
278
+ if arg_opts == ["import-aliases"]
279
+ filename = arg_words[0]
280
+ if filename == nil
281
+ puts "kompile: A file path must be provided with --aliases-import."
282
+ puts "Type \"kompile --help\" for more information."
283
+ exit
284
+ end
285
+ filename = File.expand_path(filename)
286
+ if !File.exist?(filename)
287
+ puts "kompile: File \"#{filename}\" does not exist."
288
+ exit
289
+ end
290
+ Kompiler::AliasManager.import_aliases_file(filename)
291
+ Kompiler::AliasManager.save_aliases()
292
+
293
+ exit
294
+ end
295
+
296
+ if arg_opts == ["export-aliases"]
297
+ filename = arg_words[0]
298
+ if filename == nil
299
+ puts "kompile: A file path must be provided with --aliases-import."
300
+ puts "Type \"kompile --help\" for more information."
301
+ exit
302
+ end
303
+ filename = File.expand_path(filename)
304
+
305
+ Kompiler::AliasManager.export_aliases_file(filename)
306
+
307
+ exit
308
+ end
309
+
310
+ if arg_opts.include?("list-aliases") || arg_letters == ["l", "a"]
311
+ max_index = Kompiler::AliasManager.aliases.map{_1[:index]}.max
312
+ pad_width = max_index.to_s.size + 2
313
+ Kompiler::AliasManager.aliases.each do |alias_entry|
314
+ idx_string = alias_entry[:index].to_s
315
+ puts "[#{idx_string}]" + " " * (pad_width - idx_string.size) + "#{alias_entry[:keyword]}: " + alias_entry[:aliases].join(" ")
316
+ end
317
+ exit
318
+ end
319
+
136
320
 
137
321
  # Print the available architectures if requested
138
- if arg_opts == ["list-architectures"]
322
+ if arg_opts.include?("list-architectures") || arg_letters == ["l", "a", "r"]
139
323
  Kompiler::ArchManager.load_all_entries()
140
324
  puts "Available architectures:"
141
325
 
@@ -145,35 +329,82 @@ if arg_opts == ["list-architectures"]
145
329
  exit # Exit
146
330
  end
147
331
 
148
- if arg_opts == ["list-instructions"]
332
+ if arg_opts.include?("list-instructions") || arg_letters[...2] == ["l", "i"]
149
333
  arch_name = arg_words[0] || "armv8a"
150
334
  Kompiler::ArchManager.load_all_entries()
151
335
  Kompiler::ArchManager.load_arch arch_name
152
336
 
153
- Kompiler::Architecture.instructions.each do |instruction|
154
- print instruction[:keyword]
337
+ Kompiler::AliasManager.apply_aliases()
338
+
339
+ if !(arg_opts.include?("compact") || arg_letters.include?("c"))
155
340
 
156
- print " "
341
+ # Calculate the size of the index column
342
+ idx_col_width = [7, (Kompiler::Architecture.instructions.length + 1).to_s.size + 3].max
157
343
 
158
- puts instruction[:operands].map{"<" + (_1[:name] || _1[:type] || "") + ">"}.join(" ")
344
+ console_width = IO.console.winsize[1] rescue 80
159
345
 
160
- puts instruction[:description]
346
+ desc_col_width = console_width - idx_col_width
347
+
348
+ desc_col_padding = " " * idx_col_width
349
+
350
+ Kompiler::Architecture.instructions.each_with_index do |instruction, index|
351
+
352
+ display_index = (index + 1).to_s
353
+
354
+ print "[#{display_index}]"
355
+
356
+ print " " * (idx_col_width - 2 - display_index.bytesize)
357
+
358
+ print instruction[:keyword]
359
+
360
+ print " "
361
+
362
+ puts instruction[:operands].map{"<" + (_1[:name] || _1[:type] || "") + ">"}.join(" ")
363
+
364
+ desc = instruction[:description] || ""
365
+
366
+ puts desc_col_padding + desc
367
+
368
+
369
+ if instruction.keys.include?(:aliases) && instruction[:aliases].size > 0
370
+ aliases_str = "Aliases: " + instruction[:aliases].join(" ")
371
+ puts desc_col_padding + aliases_str
372
+ end
373
+
374
+ print "\n"
375
+ end
376
+
377
+ else
378
+
379
+ strings = []
380
+
381
+ Kompiler::Architecture.instructions.each_with_index do |instruction, index|
382
+ str = "#{index + 1} #{instruction[:keyword]}"
383
+ strings << str
384
+ end
385
+
386
+ puts strings.join(", ")
161
387
 
162
- print "\n"
163
388
  end
164
389
 
165
390
  exit
166
391
  end
167
392
 
168
- if arg_opts == ["list-registers"]
393
+
394
+
395
+
396
+
397
+ if arg_opts.include?("list-registers") || arg_letters[...2] == ["l", "r"]
169
398
  arch_name = arg_words[0] || "armv8a"
170
399
  Kompiler::ArchManager.load_all_entries()
171
- arch = Kompiler::ArchManager.get_arch(arch_name)
172
-
173
- require arch[:include_path]
400
+ Kompiler::ArchManager.load_arch(arch_name)
174
401
 
175
- Kompiler::Architecture.registers.each do |reg|
176
- puts "#{reg[:reg_name]}"
402
+ if !(arg_opts.include?("compact") || arg_letters.include?("c"))
403
+ Kompiler::Architecture.registers.each do |reg|
404
+ puts "#{reg[:reg_name]}"
405
+ end
406
+ else
407
+ puts Kompiler::Architecture.registers.map{_1[:reg_name]}.join(", ")
177
408
  end
178
409
 
179
410
  exit
@@ -210,19 +441,7 @@ end
210
441
 
211
442
 
212
443
 
213
-
214
- wrap_opt = arg_keys.select{_1[0] == "wrap"}
215
-
216
-
217
- if wrap_opt.size > 1
218
- puts "kompile: Only one wrapping option can be provided with \"--wrap\"."
219
- puts "Type \"kompile --help\" for more information."
220
- exit
221
- elsif wrap_opt.size == 1
222
- wrap_opt = wrap_opt[0][1]
223
- else
224
- wrap_opt = "none"
225
- end
444
+ wrap_opt = get_arg_key(arg_keys, ["wrap", "w"], "none")
226
445
 
227
446
 
228
447
  if !["elf.obj", "elf.exec", "mach-o.obj", "mach-o.exec", "none"].include?(wrap_opt)
@@ -233,18 +452,8 @@ end
233
452
 
234
453
 
235
454
 
455
+ arch_name = get_arg_key(arg_keys, ["arch", "ar"], "armv8a")
236
456
 
237
- arch_opt = arg_keys.select{_1[0] == "arch"}
238
-
239
- if arch_opt.size > 1
240
- puts "kompile: Only one architecture can be provided with \"--arch\"."
241
- puts "Type \"kompile --help\" for more information."
242
- exit
243
- elsif arch_opt.size == 1
244
- arch_name = arch_opt[0][1]
245
- else
246
- arch_name = "armv8a"
247
- end
248
457
 
249
458
 
250
459
  # Load all the architecture entries
@@ -270,6 +479,10 @@ end
270
479
 
271
480
 
272
481
 
482
+ Kompiler::AliasManager.apply_aliases()
483
+
484
+
485
+
273
486
  code = File.binread(in_filename)
274
487
 
275
488
  detailed_out = Kompiler::CompilerFunctions.detailed_compile(code)
@@ -284,26 +497,6 @@ labels = detailed_out[:labels]
284
497
  labels.delete "here"
285
498
 
286
499
 
287
- def get_number str
288
- bool, val = Kompiler::Parsers.check_immediate_operand(str)
289
- return (bool == false) ? nil : val
290
- end
291
-
292
-
293
- def get_arg_key arg_keys, key, default_value=0
294
- filtered = arg_keys.filter{_1[0] == key}[0]
295
- value = (filtered != nil) ? filtered[1] : default_value
296
- return value
297
- end
298
-
299
-
300
- class String
301
- def to_num
302
- status, val = Kompiler::Parsers.check_immediate_operand(self)
303
- return (status == false) ? nil : val[:value]
304
- end
305
- end
306
-
307
500
 
308
501
  add_exec_permission = false
309
502
 
@@ -312,8 +505,8 @@ case wrap_opt
312
505
  when "none"
313
506
  out = code
314
507
  when "elf.obj"
315
- elf_machine = get_arg_key(arg_keys, "elf-machine", "0").to_num
316
- elf_class = get_arg_key(arg_keys, "elf-class", "64").to_num
508
+ elf_machine = get_arg_key(arg_keys, ["elf-machine", "m"], "0").to_num
509
+ elf_class = get_arg_key(arg_keys, ["elf-class", "c"], "64").to_num
317
510
 
318
511
  if ![32, 64].include?(elf_class)
319
512
  puts "kompile: Invalid ELF class specified."
@@ -326,8 +519,8 @@ when "elf.obj"
326
519
  when "elf.exec"
327
520
  vaddr = 0x80000
328
521
 
329
- elf_machine = get_arg_key(arg_keys, "elf-machine", "0").to_num
330
- elf_class = get_arg_key(arg_keys, "elf-class", "64").to_num
522
+ elf_machine = get_arg_key(arg_keys, ["elf-machine", "m"], "0").to_num
523
+ elf_class = get_arg_key(arg_keys, ["elf-class", "c"], "64").to_num
331
524
 
332
525
  if ![32, 64].include?(elf_class)
333
526
  puts "kompile: Invalid ELF class specified."
@@ -342,7 +535,7 @@ when "elf.exec"
342
535
  add_exec_permission = true
343
536
 
344
537
  when "mach-o.obj"
345
- macho_cpu = get_arg_key(arg_keys, "mach-o-machine", "0.0")
538
+ macho_cpu = get_arg_key(arg_keys, ["mach-o-machine", "m"], "0.0")
346
539
  cputype, cpusubtype = macho_cpu.split(".").map(&:to_num)
347
540
 
348
541
  if [cputype, cpusubtype].include? nil
@@ -351,21 +544,21 @@ when "mach-o.obj"
351
544
  exit
352
545
  end
353
546
 
354
- arch_type = get_arg_key(arg_keys, "mach-o-archtype", "64").to_num
547
+ arch_type = get_arg_key(arg_keys, ["mach-o-archtype", "at"], "64").to_num
355
548
 
356
- codesign = get_arg_key(arg_keys, "codesign", "false")
357
- if !["true", "false"].include?(codesign)
549
+ codesign = get_arg_key(arg_keys, ["codesign", "cs"], "false")
550
+ if !is_bool_opt(codesign)
358
551
  puts "kompile: Invalid --codesign value."
359
552
  puts "Type \"kompile --help\" for more information."
360
553
  exit
361
554
  end
362
555
 
363
- codesign = (codesign == "true")
556
+ codesign = is_pos_bool(codesign)
364
557
 
365
558
  symbols = Kompiler::Wrappers::MachO.labels_to_symbols(labels)
366
559
  out = Kompiler::Wrappers::MachO.wrap_obj(code, symbols, cputype: cputype, cpusubtype: cpusubtype, arch_type: arch_type)
367
560
  when "mach-o.exec"
368
- macho_cpu = get_arg_key(arg_keys, "mach-o-machine", "0.0")
561
+ macho_cpu = get_arg_key(arg_keys, ["mach-o-machine", "m"], "0.0")
369
562
  cputype, cpusubtype = macho_cpu.split(".").map(&:to_num)
370
563
 
371
564
  if [cputype, cpusubtype].include? nil
@@ -374,19 +567,19 @@ when "mach-o.exec"
374
567
  exit
375
568
  end
376
569
 
377
- arch_type = get_arg_key(arg_keys, "mach-o-archtype", "64").to_num
378
-
379
- exec_type = get_arg_key(arg_keys, "exec-type", "dylink")
380
-
570
+ arch_type = get_arg_key(arg_keys, ["mach-o-archtype", "t"], "64").to_num
381
571
 
382
- codesign = get_arg_key(arg_keys, "codesign", "false")
383
- if !["true", "false"].include?(codesign)
572
+ codesign = get_arg_key(arg_keys, ["codesign", "cs"], "false")
573
+ if !is_bool_opt(codesign)
384
574
  puts "kompile: Invalid --codesign value."
385
575
  puts "Type \"kompile --help\" for more information."
386
576
  exit
387
577
  end
388
578
 
389
- codesign = (codesign == "true")
579
+ exec_type = get_arg_key(arg_keys, ["exec-type", "et"], "dylink")
580
+
581
+
582
+ codesign = is_pos_bool(codesign)
390
583
 
391
584
 
392
585
  case exec_type
@@ -396,7 +589,7 @@ when "mach-o.exec"
396
589
  when "static"
397
590
  symbols = Kompiler::Wrappers::MachO.labels_to_symbols(labels)
398
591
 
399
- thread_state_arch = get_arg_key(arg_keys, "mach-o-threadstate", "arm64")
592
+ thread_state_arch = get_arg_key(arg_keys, ["mach-o-threadstate", "ts"], "arm64")
400
593
 
401
594
  entry_address = 0x1000000
402
595
 
@@ -0,0 +1,160 @@
1
+
2
+ module Kompiler
3
+
4
+ module AliasManager
5
+
6
+ @aliases = []
7
+
8
+ def self.aliases
9
+ @aliases
10
+ end
11
+
12
+ def self.default_alias_file_path()
13
+ ENV["KOMPILER_ALIASES_FILE_PATH"] || Gem.find_files("kompiler/config/aliases")[0]
14
+ end
15
+
16
+ # Load aliases from the config file in Kompiler
17
+ def self.load_aliases()
18
+ file_path = AliasManager.default_alias_file_path()
19
+ AliasManager.import_aliases_file(file_path)
20
+ end
21
+
22
+ # Save aliases to the config file in Kompiler
23
+ def self.save_aliases()
24
+ file_path = AliasManager.default_alias_file_path()
25
+ AliasManager.export_aliases_file(file_path)
26
+ end
27
+
28
+ def self.reset_aliases()
29
+ @aliases = []
30
+ nil
31
+ end
32
+
33
+ # Apply aliases to the instruction set
34
+ def self.apply_aliases()
35
+
36
+ @aliases.each do |alias_entry|
37
+
38
+ instr_index = alias_entry[:index] - 1
39
+ instr_keyword = alias_entry[:keyword]
40
+
41
+ instruction = Kompiler::Architecture.instructions[instr_index]
42
+
43
+ # Something is not right in the alias config, so just skip
44
+ next if instruction[:keyword] != instr_keyword
45
+
46
+ instruction[:aliases] = alias_entry[:aliases]
47
+
48
+ end
49
+
50
+ return true
51
+ end
52
+
53
+ # Import aliases from a string
54
+ def self.import_aliases(aliases_content)
55
+ lines = Kompiler::Parsers.get_code_lines(aliases_content)
56
+
57
+ line_words = []
58
+
59
+ @aliases = []
60
+
61
+ lines.each_with_index do |line, line_i|
62
+
63
+ words = []
64
+
65
+ curr_i = 0
66
+ max_i = line.bytesize
67
+
68
+ while curr_i < max_i
69
+
70
+ while curr_i < max_i && Kompiler::Config.whitespace_chars.include?(line[curr_i])
71
+ curr_i += 1
72
+ end
73
+
74
+ word = ""
75
+
76
+ while curr_i < max_i && !Kompiler::Config.whitespace_chars.include?(line[curr_i])
77
+ word << line[curr_i]
78
+ curr_i += 1
79
+ end
80
+
81
+ words << word
82
+ end
83
+
84
+ instr_index = words[0].to_i
85
+ instr_keyword = words[1]
86
+ instr_aliases = words[2..]
87
+
88
+ @aliases << {index: instr_index, keyword: instr_keyword, aliases: instr_aliases}
89
+
90
+ end
91
+
92
+ @aliases.size
93
+ end
94
+
95
+ # Import aliases from a file
96
+ def self.import_aliases_file(filename)
97
+ content = File.binread(filename)
98
+ AliasManager.import_aliases(content)
99
+ end
100
+
101
+ # Export aliases to a string
102
+ def self.export_aliases()
103
+ separator = Kompiler::Config.whitespace_chars[0]
104
+
105
+ output = ""
106
+
107
+ @aliases.each do |instr_alias|
108
+ line = ([instr_alias[:index], instr_alias[:keyword]] + instr_alias[:aliases]).join(separator)
109
+
110
+ output << line
111
+ output << "\n"
112
+ end
113
+
114
+ output
115
+ end
116
+
117
+ # Export aliases to a file
118
+ def self.export_aliases_file(filename)
119
+ content = AliasManager.export_aliases()
120
+ File.binwrite filename, content
121
+ end
122
+
123
+ # Add alias
124
+ def self.add_alias(index, keyword, *aliases)
125
+ alias_entry, entry_index = @aliases.each_with_index.filter{|entry, idx| entry[:index] == index && entry[:keyword] == keyword }[0]
126
+
127
+ if alias_entry == nil
128
+ alias_entry = {index: index, keyword: keyword, aliases: []}
129
+ entry_index = @aliases.size
130
+ end
131
+
132
+ alias_entry[:aliases] += aliases
133
+
134
+ @aliases[entry_index] = alias_entry
135
+
136
+ return true
137
+ end
138
+
139
+ # Remove alias
140
+ def self.remove_alias(index, keyword, *aliases)
141
+ alias_entry, entry_index = @aliases.each_with_index.filter{|entry, idx| entry[:index] == index && entry[:keyword] == keyword }[0]
142
+
143
+ if alias_entry == nil
144
+ return false
145
+ end
146
+
147
+ alias_entry[:aliases] -= aliases
148
+
149
+ if alias_entry[:aliases].size == 0
150
+ @aliases.delete_at entry_index
151
+ else
152
+ @aliases[entry_index] = alias_entry
153
+ end
154
+
155
+ return true
156
+ end
157
+
158
+ end # Kompiler::AliasManager
159
+
160
+ end # Kompiler
@@ -22,6 +22,20 @@ end
22
22
  ],
23
23
  bitsize: 32
24
24
  },
25
+ { keyword: "mov",
26
+ name: "Move (immediate, with shift)",
27
+ description: "Moves a shifted immediate value to the destination register.",
28
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "immediate", restrictions: {}, name: "Immediate value"}, {type: "immediate", name: "Shift amount (multiple of 16)"}],
29
+ mc_constructor: [
30
+ ["if_eq_else", ["modulo", ["get_operand", 2], 16], 0, [], ["raise_error", "movk Error: Shift amount must be divisible by 16."]],
31
+ ["get_bits", ["encode_gp_register", ["get_operand", 0]], 0, 5],
32
+ ["get_bits", ["get_operand", 1], 0, 16],
33
+ ["get_bits", ["divide", ["get_operand", 2], 16], 0, 2],
34
+ ["bits", 1,0,1,0,0,1, 0,1],
35
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], 0],
36
+ ],
37
+ bitsize: 32
38
+ },
25
39
  { keyword: "mov",
26
40
  name: "Move (register)",
27
41
  description: "Copies the value in the source register to the destination register",
@@ -52,6 +66,34 @@ end
52
66
  ],
53
67
  bitsize: 32
54
68
  },
69
+ {
70
+ keyword: "movk",
71
+ name: "Move with keep (immediate)",
72
+ description: "Moves a 16-bit immediate value to the destination register, keeping other bits unchanged.",
73
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "immediate", restrictions: {}, name: "Immediate value"}],
74
+ mc_constructor: [
75
+ ["get_bits", ["encode_gp_register", ["get_operand", 0]], 0, 5],
76
+ ["get_bits", ["get_operand", 1], 0, 16],
77
+ ["bits", 0,0, 1,0,1,0,0,1, 1,1],
78
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], 0],
79
+ ],
80
+ bitsize: 32
81
+ },
82
+ {
83
+ keyword: "movk",
84
+ name: "Move with keep (immediate, with shift)",
85
+ description: "Moves a shifted 16-bit immediate value to the destination register, keeping other bits unchanged.",
86
+ operands: [{type: "register", restrictions: {reg_type: "gpr"}, name: "Destination register"}, {type: "immediate", restrictions: {}, name: "Immediate value"}, {type: "immediate", name: "Shift amount (multiple of 16)"}],
87
+ mc_constructor: [
88
+ ["if_eq_else", ["modulo", ["get_operand", 2], 16], 0, [], ["raise_error", "movk Error: Shift amount must be divisible by 16."]],
89
+ ["get_bits", ["encode_gp_register", ["get_operand", 0]], 0, 5],
90
+ ["get_bits", ["get_operand", 1], 0, 16],
91
+ ["get_bits", ["divide", ["get_operand", 2], 16], 0, 2],
92
+ ["bits", 1,0,1,0,0,1, 1,1],
93
+ ["case", ["get_key", ["get_operand", 0], :reg_size], 64, ["bits", 1], 32, ["bits", 0], 0],
94
+ ],
95
+ bitsize: 32
96
+ },
55
97
  { keyword: "mvn", # MVN writes the bitwise opposite of the source register to a destination register
56
98
  name: "Move inverse",
57
99
  description: "Writes the bitwise opposite of the source register value to the destination register.",
File without changes
@@ -537,11 +537,11 @@ module SymAST
537
537
 
538
538
  operation_found = true
539
539
 
540
- ast_node = {type: "operation", op_type: operation[:name], elements: }
540
+ ast_node = {type: "operation", op_type: operation[:name], elements: elements}
541
541
 
542
542
  tokens = tokens[...(token_i - 1)] + [ast_node] + tokens[(token_i + 1 + 1)..]
543
543
 
544
- # token_i += token_i_change
544
+ token_i += token_i_change
545
545
 
546
546
  break
547
547
  end
@@ -436,7 +436,7 @@ def self.match_parsed_line_to_instruction(parsed_line, instruction)
436
436
  keyword, operands = parsed_line
437
437
 
438
438
  # Check if the keyword matches
439
- if instruction[:keyword] != keyword
439
+ if instruction[:keyword] != keyword && !(instruction[:aliases] != nil && instruction[:aliases].include?(keyword))
440
440
  return [false, nil]
441
441
  end
442
442
 
data/lib/kompiler.rb CHANGED
@@ -21,3 +21,4 @@ require 'kompiler/directives.rb'
21
21
  require 'kompiler/arch_manager.rb'
22
22
  require 'kompiler/math_ast.rb'
23
23
  require 'kompiler/wrappers'
24
+ require 'kompiler/alias_manager.rb'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kompiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyryl Shyshko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-20 00:00:00.000000000 Z
11
+ date: 2025-05-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Kompiler is a low-level, modular and extendable compiler for any architecture.
14
14
  By default Kompiler supports ARMv8-a, but other architecture extensions can be downloaded
@@ -24,6 +24,7 @@ files:
24
24
  - LICENSE
25
25
  - bin/kompile
26
26
  - lib/kompiler.rb
27
+ - lib/kompiler/alias_manager.rb
27
28
  - lib/kompiler/arch_entries/kompiler_armv8a.rb
28
29
  - lib/kompiler/arch_manager.rb
29
30
  - lib/kompiler/architecture.rb
@@ -36,6 +37,7 @@ files:
36
37
  - lib/kompiler/architectures/armv8a/sys_registers.rb
37
38
  - lib/kompiler/compiler_functions.rb
38
39
  - lib/kompiler/config.rb
40
+ - lib/kompiler/config/aliases
39
41
  - lib/kompiler/directives.rb
40
42
  - lib/kompiler/math_ast.rb
41
43
  - lib/kompiler/mc_builder.rb
@@ -65,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
67
  - !ruby/object:Gem::Version
66
68
  version: '0'
67
69
  requirements: []
68
- rubygems_version: 3.4.10
70
+ rubygems_version: 3.5.10
69
71
  signing_key:
70
72
  specification_version: 4
71
73
  summary: Kir's compiler for low-level machine code