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 +4 -4
- data/bin/kompile +289 -96
- data/lib/kompiler/alias_manager.rb +160 -0
- data/lib/kompiler/architectures/armv8a/instructions.rb +42 -0
- data/lib/kompiler/config/aliases +0 -0
- data/lib/kompiler/math_ast.rb +2 -2
- data/lib/kompiler/parsers.rb +1 -1
- data/lib/kompiler.rb +1 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70dad0d1372236affa1fba712fff8b5a7d07d5cb99aa13fe41f4e39b92294901
|
4
|
+
data.tar.gz: 38345074dffd505b6ba7f99283bc851ed17e0d7afc7df684933e8bd3420854b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
104
|
-
--wrap=<format
|
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
|
115
|
-
--elf-class=<class
|
116
|
-
--mach-o-machine=<cputype.subtype
|
117
|
-
|
118
|
-
--mach-o-archtype=<type
|
119
|
-
--exec-type=<type
|
120
|
-
|
121
|
-
--mach-o-threadstate=<type
|
122
|
-
|
123
|
-
--codesign=<
|
124
|
-
|
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
|
128
|
-
--list-architectures Lists available architectures
|
129
|
-
--list-instructions [arch]
|
130
|
-
--list-registers [arch]
|
131
|
-
--list-
|
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 == ["
|
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 == ["
|
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::
|
154
|
-
|
337
|
+
Kompiler::AliasManager.apply_aliases()
|
338
|
+
|
339
|
+
if !(arg_opts.include?("compact") || arg_letters.include?("c"))
|
155
340
|
|
156
|
-
|
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
|
-
|
344
|
+
console_width = IO.console.winsize[1] rescue 80
|
159
345
|
|
160
|
-
|
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
|
-
|
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
|
-
|
172
|
-
|
173
|
-
require arch[:include_path]
|
400
|
+
Kompiler::ArchManager.load_arch(arch_name)
|
174
401
|
|
175
|
-
|
176
|
-
|
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 !
|
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
|
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 !
|
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
|
-
|
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
|
data/lib/kompiler/math_ast.rb
CHANGED
@@ -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
|
-
|
544
|
+
token_i += token_i_change
|
545
545
|
|
546
546
|
break
|
547
547
|
end
|
data/lib/kompiler/parsers.rb
CHANGED
@@ -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
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.
|
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-
|
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.
|
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
|