kompiler 0.3.0 → 0.3.2
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 +26 -7
- data/lib/kompiler/directives.rb +29 -0
- data/lib/kompiler/wrappers/elf_wrapper.rb +320 -122
- data/lib/kompiler/wrappers/macho_wrapper.rb +441 -0
- data/lib/kompiler/wrappers.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12bbbb642809ac234ac1cfdcd59b3d43362c0ba284a6286656fecc2cf5024e99
|
4
|
+
data.tar.gz: 86e653003489923b7a63bd24b0d6019b07fde08c10c8dc426357dca265b3445e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e729dfc9ee22702200ea082beef419bdbcbaa6bc2ba5a4cadbc2899f6442c6f65c163ec90675ce8d8e2fe41cd80e97cee445fb7386547e78f5569016bbba69ed
|
7
|
+
data.tar.gz: d88ba4f53b56086cae6e63f8308058f3f28735f8db671d122c3eecbd3270e5443a1945407b7e8e73b15859758897992f2183481f667282fea29ee57f47f2b494
|
data/bin/kompile
CHANGED
@@ -107,13 +107,15 @@ Available wrapping formats:
|
|
107
107
|
none
|
108
108
|
elf.obj
|
109
109
|
elf.exec
|
110
|
-
mach-o.obj
|
110
|
+
mach-o.obj
|
111
111
|
mach-o.exec [not implemented yet]
|
112
112
|
|
113
113
|
Additional options for wrapping are:
|
114
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)
|
115
116
|
--mach-o-machine=<cputype.subtype> Specifies Mach-O header's cputype and subtype
|
116
117
|
to be the type provided
|
118
|
+
--mach-o-archtype=<type> Specifies the file architecture type to either 32 or 64 (default is 64)
|
117
119
|
|
118
120
|
Available options:
|
119
121
|
--help, -h Prints this information
|
@@ -260,7 +262,7 @@ code = File.binread(in_filename)
|
|
260
262
|
|
261
263
|
detailed_out = Kompiler::CompilerFunctions.detailed_compile(code)
|
262
264
|
|
263
|
-
#
|
265
|
+
# pp detailed_out
|
264
266
|
|
265
267
|
out = nil
|
266
268
|
|
@@ -276,18 +278,35 @@ when "none"
|
|
276
278
|
when "elf.obj"
|
277
279
|
elf_machine = arg_keys.filter{_1[0] == "elf-machine"}[0]
|
278
280
|
elf_machine = (elf_machine != nil) ? elf_machine[1].to_i : 0
|
281
|
+
|
282
|
+
elf_class = arg_keys.filter{_1[0] == "elf-class"}[0]
|
283
|
+
elf_class ||= ["elf-class", "64"]
|
284
|
+
elf_class = elf_class[1].to_i
|
285
|
+
|
279
286
|
symbols = Kompiler::Wrappers::ELF.labels_to_symbols(labels)
|
280
|
-
out = Kompiler::Wrappers::ELF.wrap_obj(code, symbols, machine: elf_machine)
|
287
|
+
out = Kompiler::Wrappers::ELF.wrap_obj(code, symbols, machine: elf_machine, elf_class: elf_class)
|
281
288
|
when "elf.exec"
|
282
289
|
elf_machine = arg_keys.filter{_1[0] == "elf-machine"}[0]
|
283
290
|
elf_machine = (elf_machine != nil) ? elf_machine[1].to_i : 0
|
291
|
+
|
292
|
+
elf_class = arg_keys.filter{_1[0] == "elf-class"}[0]
|
293
|
+
elf_class ||= ["elf-class", "64"]
|
294
|
+
elf_class = elf_class[1].to_i
|
295
|
+
|
284
296
|
symbols = Kompiler::Wrappers::ELF.labels_to_symbols(labels)
|
285
|
-
out = Kompiler::Wrappers::ELF.wrap_exec(code, symbols, machine: elf_machine)
|
297
|
+
out = Kompiler::Wrappers::ELF.wrap_exec(code, symbols, machine: elf_machine, elf_class: elf_class)
|
286
298
|
when "mach-o.obj"
|
287
|
-
|
288
|
-
|
299
|
+
macho_cpu = arg_keys.filter{_1[0] == "mach-o-machine"}[0]
|
300
|
+
macho_cpu = (macho_cpu != nil) ? macho_cpu[1] : "0.0"
|
301
|
+
cputype, cpusubtype = macho_cpu.split(".").map(&:to_i)
|
302
|
+
|
303
|
+
arch_type = arg_keys.filter{_1[0] == "mach-o-archtype"}[0]
|
304
|
+
arch_type = (arch_type != nil) ? arch_type[1].to_i : 64
|
305
|
+
|
306
|
+
symbols = Kompiler::Wrappers::MachO.labels_to_symbols(labels)
|
307
|
+
out = Kompiler::Wrappers::MachO.wrap_obj(code, symbols, cputype: cputype, cpusubtype: cpusubtype, arch_type: arch_type)
|
289
308
|
when "mach-o.exec"
|
290
|
-
puts "Mach-O not yet implemented."
|
309
|
+
puts "Mach-O executable not yet implemented."
|
291
310
|
exit
|
292
311
|
end
|
293
312
|
|
data/lib/kompiler/directives.rb
CHANGED
@@ -519,6 +519,35 @@ end
|
|
519
519
|
|
520
520
|
state[:line_i] += 1
|
521
521
|
|
522
|
+
state
|
523
|
+
end
|
524
|
+
},
|
525
|
+
{
|
526
|
+
keyword: "info",
|
527
|
+
func: lambda do |operands, state|
|
528
|
+
|
529
|
+
begin
|
530
|
+
info_name = operands[0][:definition]
|
531
|
+
info_value = operands[1][:definition]
|
532
|
+
rescue
|
533
|
+
puts "Incorrect use of the \".info\" directive."
|
534
|
+
end
|
535
|
+
|
536
|
+
|
537
|
+
state[:line_i] += 1
|
538
|
+
|
539
|
+
context_info = {}
|
540
|
+
|
541
|
+
context_info[:current_address] = state[:current_address]
|
542
|
+
|
543
|
+
context_info[:line_i] = state[:line_i]
|
544
|
+
|
545
|
+
state[:extra_state][:info_entries] ||= Hash.new
|
546
|
+
|
547
|
+
state[:extra_state][:info_entries][info_name] ||= Array.new
|
548
|
+
|
549
|
+
state[:extra_state][:info_entries][info_name] << {context_info: context_info, input_str: info_value, input_full: operands[1]}
|
550
|
+
|
522
551
|
state
|
523
552
|
end
|
524
553
|
}
|
@@ -28,7 +28,7 @@ module Kompiler
|
|
28
28
|
|
29
29
|
sections, shstrndx = create_default_sections(code, symbols, elf_class: elf_class).values
|
30
30
|
|
31
|
-
output = build(sections: sections,
|
31
|
+
output = build(sections: sections, e_machine: e_machine, elf_class: elf_class, e_shstrndx: shstrndx, e_type: 1)
|
32
32
|
|
33
33
|
output
|
34
34
|
end
|
@@ -40,14 +40,18 @@ module Kompiler
|
|
40
40
|
# Arguments:
|
41
41
|
# code - raw byte string
|
42
42
|
# options - a hash of configurable options:
|
43
|
+
# machine - a raw machine ID to fill in the e_machine field (default is 0)
|
43
44
|
# elf_class - 32 for ELFClass32 or 64 for ELFClass64 (default is 64)
|
44
|
-
# machine - a raw machine ID to fill in the e_machine field
|
45
45
|
# vaddr - virtual address for the program and entry (default is 0x80000)
|
46
|
+
# align - alignment value for the load segment (default is 0x1000)
|
47
|
+
# flags - segment flags (default is 0b111, bits are in form 0bRWX)
|
46
48
|
def self.wrap_exec code, symbols, **options
|
47
49
|
|
48
50
|
elf_class = options[:elf_class] || 64
|
49
|
-
e_machine = options[:machine]
|
51
|
+
e_machine = options[:machine] || 0
|
50
52
|
vaddr = options[:vaddr] || 0x80000
|
53
|
+
align = options[:align] || 0x1000
|
54
|
+
flags = options[:flags] || 0b111
|
51
55
|
|
52
56
|
sections, shstrndx = create_default_sections(code, symbols, elf_class: elf_class).values
|
53
57
|
|
@@ -56,15 +60,15 @@ module Kompiler
|
|
56
60
|
segments = [
|
57
61
|
{
|
58
62
|
type: 1, # Loadable segment
|
59
|
-
flags:
|
63
|
+
flags: flags, # Execute, write, read permissions
|
60
64
|
vaddr: vaddr, # Virtual address of segment in memory
|
61
65
|
# content: code,
|
62
66
|
content_section_i: 1,
|
63
|
-
align:
|
67
|
+
align: align
|
64
68
|
},
|
65
69
|
]
|
66
70
|
|
67
|
-
output = build(sections: sections, segments: segments,
|
71
|
+
output = build(sections: sections, segments: segments, e_machine: e_machine, elf_class: elf_class, e_type: 2, virtual_entry_address: vaddr, e_shstrndx: shstrndx)
|
68
72
|
|
69
73
|
output
|
70
74
|
end
|
@@ -76,11 +80,19 @@ module Kompiler
|
|
76
80
|
def self.labels_to_symbols labels
|
77
81
|
out = []
|
78
82
|
labels.each do |name, value|
|
79
|
-
out << {name: name, value: value, type:
|
83
|
+
out << {name: name, value: value, type: 0, binding: 0}
|
80
84
|
end
|
81
85
|
out
|
82
86
|
end
|
83
87
|
|
88
|
+
# Converts a values hash of name-value pairs into an array of symbols
|
89
|
+
def self.values_to_symbols values
|
90
|
+
out = []
|
91
|
+
values.each do |name, value|
|
92
|
+
out << {name: name, value: value, type: 0, binding: 0}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
84
96
|
|
85
97
|
# Build ELF
|
86
98
|
# Builds an ELF from provided sections, segments, and other options
|
@@ -88,15 +100,42 @@ module Kompiler
|
|
88
100
|
# Arguments:
|
89
101
|
# sections - ELF sections (structure below)
|
90
102
|
# segments - ELF segments (structure below)
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
# e_shstrndx - the value for ELF header's e_shstrndx field (index of the section header string table section)
|
95
|
-
# e_type - the value for ELF header's e_type field (e.g., 1 for relocatable, 3 for executable)
|
103
|
+
# virtual_entry_address - the virtual entry address for the ELF header (default is 0)
|
104
|
+
# elf_class - the ELF class (32 or 64) (default is 0)
|
105
|
+
# e_machine - a raw machine ID for the ELF header (default is 0)
|
106
|
+
# e_shstrndx - the value for ELF header's e_shstrndx field (index of the section header string table section) (default is 0)
|
107
|
+
# e_type - the value for ELF header's e_type field (e.g., 1 for relocatable, 3 for executable) (default is 0)
|
108
|
+
# e_os_abi - the value for the ELF Identification header's osabi field (default is 0) (not used with elf_class = 32)
|
109
|
+
# e_abi_version - the value for the ELF Identification header's abiversion field (default is 0) (not used with elf_class = 32)
|
110
|
+
#
|
111
|
+
# Section structure:
|
112
|
+
# name_offset - section's name field value
|
113
|
+
# type - section's type field value
|
114
|
+
# flags - section's flags field value
|
115
|
+
# addr - section's addr field value
|
116
|
+
# link - section's link field value
|
117
|
+
# info - section's info field value
|
118
|
+
# addralign - section's addralign field value
|
119
|
+
# entsize - section's entsize field value
|
120
|
+
# content - section's content (offset and size will be computed automatically)
|
121
|
+
# segment_content_i - index of segment that contains this section's content (useful to remove repeated info and 'link' a section with a segment)
|
122
|
+
# offset - if segment_content_i is present, an optional offset can be added to take only part of the segment's content (default is 0)
|
123
|
+
# size - if segment_content_i is present, size can be provided optionally to take only part of the segment's content (default is 0)
|
96
124
|
#
|
97
|
-
|
125
|
+
# Segment structure:
|
126
|
+
# type - segment's type field value
|
127
|
+
# flags - segment's flags field value
|
128
|
+
# vaddr - segment's vaddr field value (default is 0)
|
129
|
+
# paddr - segment's paddr field value (default is value of vaddr)
|
130
|
+
# vsize - segment's memsz / vsize field value (default is same as content.size)
|
131
|
+
# align - segment's alignment value. This will also ensure that the segment's content is aligned to this boundary in the file
|
132
|
+
# content - segment's content (offset and size will be computed automatically)
|
133
|
+
# section_content_i - index of section that contaisn this segment's content (idea is same as section[:segment_content_i])
|
134
|
+
# offset - idea same as section[:offset]
|
135
|
+
# size - idea same as section[:size]
|
136
|
+
#
|
137
|
+
def self.build sections: [], segments: [], virtual_entry_address: 0, elf_class: 64, e_machine: 0, e_shstrndx: 0, e_type: 0, e_os_abi: 0, e_abi_version: 0
|
98
138
|
|
99
|
-
raise "Machine ID not specified for the ELF header." if machine == nil
|
100
139
|
|
101
140
|
case elf_class
|
102
141
|
when 64
|
@@ -158,7 +197,12 @@ module Kompiler
|
|
158
197
|
# EI_Version (current)
|
159
198
|
e_ident.bytes 1, elf_char
|
160
199
|
|
161
|
-
e_ident.
|
200
|
+
e_ident.bytes e_os_abi, 1 # OS_ABI
|
201
|
+
e_ident.bytes e_abi_version, 1 # ABI_VERSION
|
202
|
+
|
203
|
+
e_ident.bytes [0] * 6 # Pad to 15
|
204
|
+
|
205
|
+
e_ident.bytes [16] # E_Ident size
|
162
206
|
|
163
207
|
elf_header.add e_ident
|
164
208
|
|
@@ -166,7 +210,7 @@ module Kompiler
|
|
166
210
|
elf_header.bytes e_type, elf_half
|
167
211
|
|
168
212
|
# E_Machine (input)
|
169
|
-
elf_header.bytes
|
213
|
+
elf_header.bytes e_machine, elf_half
|
170
214
|
|
171
215
|
# E_version (current)
|
172
216
|
elf_header.bytes 1, elf_word
|
@@ -219,7 +263,8 @@ module Kompiler
|
|
219
263
|
|
220
264
|
sections_content = PackedBytes.new
|
221
265
|
|
222
|
-
sections.each_with_index do |section, section_i|
|
266
|
+
sections.each_with_index do |section, section_i|
|
267
|
+
|
223
268
|
if !section.keys.include?(:content)
|
224
269
|
section[:size] = 0
|
225
270
|
section[:offset] = 0
|
@@ -240,10 +285,11 @@ module Kompiler
|
|
240
285
|
section[:offset] = sections_content.result.bytesize + sections_contents_offset
|
241
286
|
|
242
287
|
matching_segments.each do |segment|
|
243
|
-
segment[:offset]
|
244
|
-
|
245
|
-
|
246
|
-
|
288
|
+
segment[:offset] ||= 0
|
289
|
+
|
290
|
+
segment[:size] ||= section[:size] - segment[:offset]
|
291
|
+
|
292
|
+
segment[:offset] += section[:offset]
|
247
293
|
end
|
248
294
|
|
249
295
|
sections_content.add section[:content]
|
@@ -256,49 +302,54 @@ module Kompiler
|
|
256
302
|
|
257
303
|
segments.each_with_index do |segment, segment_i|
|
258
304
|
|
259
|
-
|
260
|
-
segment[:align] = 1
|
261
|
-
end
|
305
|
+
segment[:align] ||= 1
|
262
306
|
|
263
|
-
|
264
|
-
segment[:vaddr] = 0
|
265
|
-
end
|
307
|
+
segment[:vaddr] ||= 0
|
266
308
|
|
267
|
-
|
268
|
-
segment[:paddr] = segment[:vaddr]
|
269
|
-
end
|
309
|
+
segment[:paddr] ||= segment[:vaddr]
|
270
310
|
|
271
311
|
if segment.keys.include?(:content)
|
272
312
|
segment[:size] = segment[:content].bytesize
|
273
313
|
end
|
274
314
|
|
275
|
-
|
276
|
-
|
277
|
-
end
|
315
|
+
segment[:vsize] ||= segment[:size]
|
316
|
+
|
278
317
|
|
279
318
|
if segment[:vaddr] % segment[:align] != 0
|
280
319
|
raise "Improper segment at index #{segment_i} - the virtual address is not aligned to the specified alignment boundary."
|
281
320
|
end
|
282
321
|
|
322
|
+
# If the segment uses :content, add the segment's content to the file and compute the offset
|
323
|
+
if !segment.keys.include?(:content_section_i)
|
283
324
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
325
|
+
# ELF requires file_offset and vaddr to be a multiple of the alignment value
|
326
|
+
|
327
|
+
file_offset = segments_contents_offset + segments_content.result.bytesize
|
288
328
|
|
289
|
-
|
290
|
-
|
291
|
-
|
329
|
+
pad_amount = 0
|
330
|
+
if file_offset % segment[:align] != 0
|
331
|
+
pad_amount = segment[:align] - (file_offset % segment[:align])
|
332
|
+
end
|
333
|
+
|
334
|
+
segments_content.bytes "\0" * pad_amount
|
335
|
+
|
336
|
+
segment[:offset] = segments_content.result.bytesize + segments_contents_offset
|
337
|
+
segments_content.add segment[:content]
|
292
338
|
|
293
|
-
pad_amount = 0
|
294
|
-
if file_offset % segment[:align] != 0
|
295
|
-
pad_amount = segment[:align] - (file_offset % segment[:align])
|
296
339
|
end
|
297
340
|
|
298
|
-
segments_content.bytes "\0" * pad_amount
|
299
341
|
|
300
|
-
segment
|
301
|
-
|
342
|
+
# If some sections depend on the segment, update their values
|
343
|
+
|
344
|
+
matching_sections = sections.filter{_1[:segment_content_i] == segment_i}
|
345
|
+
|
346
|
+
matching_sections.each do |section|
|
347
|
+
section[:offset] ||= 0
|
348
|
+
|
349
|
+
section[:size] ||= segment[:size] - section[:offset]
|
350
|
+
|
351
|
+
section[:offset] += segment[:offset]
|
352
|
+
end
|
302
353
|
|
303
354
|
end
|
304
355
|
|
@@ -324,15 +375,29 @@ module Kompiler
|
|
324
375
|
|
325
376
|
ph = PackedBytes.new
|
326
377
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
378
|
+
case elf_class
|
379
|
+
when 64
|
380
|
+
segments.each do |segment|
|
381
|
+
ph.bytes segment[:type], elf_word
|
382
|
+
ph.bytes segment[:flags], elf_word
|
383
|
+
ph.bytes segment[:offset], elf_off
|
384
|
+
ph.bytes segment[:vaddr], elf_addr
|
385
|
+
ph.bytes segment[:paddr], elf_addr
|
386
|
+
ph.bytes segment[:size], elf_xword
|
387
|
+
ph.bytes segment[:vsize], elf_xword
|
388
|
+
ph.bytes segment[:align], elf_xword
|
389
|
+
end
|
390
|
+
when 32
|
391
|
+
segments.each do |segment|
|
392
|
+
ph.bytes segment[:type], elf_word
|
393
|
+
ph.bytes segment[:offset], elf_off
|
394
|
+
ph.bytes segment[:vaddr], elf_addr
|
395
|
+
ph.bytes segment[:paddr], elf_addr
|
396
|
+
ph.bytes segment[:size], elf_word
|
397
|
+
ph.bytes segment[:vsize], elf_word
|
398
|
+
ph.bytes segment[:flags], elf_word
|
399
|
+
ph.bytes segment[:align], elf_word
|
400
|
+
end
|
336
401
|
end
|
337
402
|
|
338
403
|
file_content.add ph
|
@@ -398,101 +463,234 @@ module Kompiler
|
|
398
463
|
entsize: 0,
|
399
464
|
content: program_bytes,
|
400
465
|
},
|
401
|
-
{
|
402
|
-
name: ".symtab",
|
403
|
-
type: 2,
|
404
|
-
flags: 0,
|
405
|
-
addr: 0,
|
406
|
-
link: sym_strtab_section_index, # Index of string table used for symbol names
|
407
|
-
info: symbols.size + 1, # Index of first non-local symbol
|
408
|
-
addralign: 0,
|
409
|
-
entsize: symtab_ent_size,
|
410
|
-
content: "",
|
411
|
-
},
|
412
|
-
{
|
413
|
-
name: ".strtab",
|
414
|
-
type: 3,
|
415
|
-
flags: 0,
|
416
|
-
addr: 0,
|
417
|
-
link: 0,
|
418
|
-
info: 0,
|
419
|
-
addralign: 0,
|
420
|
-
entsize: 0,
|
421
|
-
content: "",
|
422
|
-
},
|
423
|
-
{
|
424
|
-
name: ".shstrtab",
|
425
|
-
type: 3,
|
426
|
-
flags: 0,
|
427
|
-
addr: 0,
|
428
|
-
link: 0,
|
429
|
-
info: 0,
|
430
|
-
addralign: 0,
|
431
|
-
entsize: 0,
|
432
|
-
content: "",
|
433
|
-
},
|
434
466
|
]
|
435
467
|
|
436
|
-
symtab = PackedBytes.new
|
437
468
|
|
438
|
-
|
439
|
-
|
469
|
+
symbols.map! do |sym|
|
470
|
+
sym[:section_index] = sym[:section_index] || progbits_section_index
|
471
|
+
sym
|
472
|
+
end
|
473
|
+
|
474
|
+
symtab_section, sym_strtab_contents = create_symtab_section(symbols, link: sym_strtab_section_index, info: "first-non-local", elf_class: elf_class)
|
440
475
|
|
476
|
+
sections << symtab_section
|
441
477
|
|
442
|
-
|
478
|
+
sections << create_strtab_section(sym_strtab_contents, name: ".strtab", elf_class: elf_class)
|
443
479
|
|
444
|
-
|
480
|
+
|
481
|
+
sections << create_strtab_section("\0", name: ".shstrtab", elf_class: elf_class)
|
445
482
|
|
446
|
-
|
447
|
-
|
448
|
-
|
483
|
+
|
484
|
+
sections.each_with_index do |section, section_i|
|
485
|
+
if section.keys.include? :name
|
486
|
+
section[:name_offset] = sections[sh_strtab_section_index][:content].bytesize
|
487
|
+
sections[sh_strtab_section_index][:content] << section[:name] + "\0"
|
449
488
|
else
|
450
|
-
name_offset = 0
|
489
|
+
section[:name_offset] = 0
|
451
490
|
end
|
491
|
+
end
|
492
|
+
|
493
|
+
|
494
|
+
return {sections: sections, shstrndx: sh_strtab_section_index}
|
495
|
+
|
496
|
+
end
|
497
|
+
|
452
498
|
|
453
|
-
# name
|
454
|
-
symtab.bytes name_offset, elf_word
|
455
499
|
|
456
|
-
|
500
|
+
# Creates a section structure with type symtab, builds symbol entries and symbol string table contents
|
501
|
+
# Returns [symtab_section, sym_strtab_contents]
|
502
|
+
#
|
503
|
+
# Arguments:
|
504
|
+
# symbols - an array of hashes with info about each symbol (structure below)
|
505
|
+
# **options - additional options
|
506
|
+
#
|
507
|
+
# Options are:
|
508
|
+
# elf_class - elf class, either 64 or 32 (default is 64)
|
509
|
+
# name - the symtab section's name (default is .symtab)
|
510
|
+
# link - the symtab section's link field value (default is 0)
|
511
|
+
# info - the symtab section's info field value (default is 0)
|
512
|
+
# set to "first-non-local" to auto-sort all symbols and
|
513
|
+
# set info field to the index of the first non-local symbol
|
514
|
+
# flags - the symtab section's flags field value (default is 0)
|
515
|
+
#
|
516
|
+
# Symbol hash structure:
|
517
|
+
# :name - the symbol's name (optional)
|
518
|
+
# :type - symbol type (0 - notype, 1 - object, 2 - func, 3 - section, 4 - file)
|
519
|
+
# :binding - symbol binding (0 - local, 1 - global, 2 - weak)
|
520
|
+
# :section_index - corresponding section's index (0 - undef, 0xfff1 - absolute, 0xfff2 - common block)
|
521
|
+
# :value - the symbol's value
|
522
|
+
# :size - the symbol's size (default is 0)
|
523
|
+
#
|
524
|
+
def self.create_symtab_section symbols, **options
|
525
|
+
|
526
|
+
elf_class = options[:elf_class] || 64
|
527
|
+
|
528
|
+
section_name = options[:name] || ".symtab"
|
529
|
+
section_link = options[:link] || 0
|
530
|
+
section_info = options[:info] || 0
|
531
|
+
section_flags = options[:flags] || 0
|
457
532
|
|
458
|
-
|
459
|
-
|
533
|
+
# Check if the auto option was selected
|
534
|
+
if section_info == "first-non-local"
|
460
535
|
|
461
|
-
#
|
462
|
-
symtab.bytes 0, elf_char
|
536
|
+
# Sort symbols for global symbols to come last
|
463
537
|
|
464
|
-
|
465
|
-
|
538
|
+
local_symbols = symbols.filter{_1[:binding] == 0}
|
539
|
+
non_local_symbols = symbols.filter{_1[:binding] != 0}
|
466
540
|
|
467
|
-
|
468
|
-
symtab.bytes symbol[:value], elf_addr
|
541
|
+
first_non_local_i = local_symbols.size
|
469
542
|
|
470
|
-
#
|
471
|
-
|
472
|
-
|
543
|
+
# Sort symbols for local ones to come first
|
544
|
+
symbols = local_symbols + non_local_symbols
|
545
|
+
|
546
|
+
# + 1 because the first symbol will be pre-forced to be all zeros and local
|
547
|
+
section_info = first_non_local_i + 1
|
548
|
+
end
|
549
|
+
|
550
|
+
|
551
|
+
case elf_class
|
552
|
+
when 64
|
553
|
+
elf_char = 1
|
554
|
+
elf_half = 2
|
555
|
+
elf_word = 4
|
556
|
+
elf_addr = 8
|
557
|
+
elf_xword = 8
|
558
|
+
symtab_ent_size = 24
|
559
|
+
when 32
|
560
|
+
elf_char = 1
|
561
|
+
elf_half = 2
|
562
|
+
elf_word = 4
|
563
|
+
elf_addr = 4
|
564
|
+
elf_xword = 4
|
565
|
+
symtab_ent_size = 16
|
473
566
|
end
|
474
567
|
|
475
|
-
|
476
|
-
|
568
|
+
symtab_content = PackedBytes.new
|
569
|
+
sym_strtab_contents = "\0".encode "ASCII"
|
477
570
|
|
571
|
+
# First entry must be all zeros
|
572
|
+
symtab_content.bytes [0] * symtab_ent_size
|
478
573
|
|
479
|
-
|
574
|
+
case elf_class
|
575
|
+
when 64
|
576
|
+
symbols.each do |symbol|
|
577
|
+
if symbol.keys.include? :name
|
578
|
+
name_offset = sym_strtab_contents.bytesize
|
579
|
+
sym_strtab_contents << symbol[:name] + "\0"
|
580
|
+
else
|
581
|
+
name_offset = 0
|
582
|
+
end
|
480
583
|
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
584
|
+
# name
|
585
|
+
symtab_content.bytes name_offset, elf_word
|
586
|
+
|
587
|
+
symbol_info = symbol[:type] | (symbol[:binding] << 4)
|
588
|
+
# info
|
589
|
+
symtab_content.bytes symbol_info, elf_char
|
590
|
+
|
591
|
+
# other
|
592
|
+
symtab_content.bytes 0, elf_char
|
593
|
+
|
594
|
+
# shndx
|
595
|
+
symtab_content.bytes symbol[:section_index], elf_half
|
596
|
+
|
597
|
+
# value
|
598
|
+
symtab_content.bytes symbol[:value], elf_addr
|
599
|
+
|
600
|
+
# size
|
601
|
+
symtab_content.bytes symbol[:size] || 0, elf_xword
|
602
|
+
end
|
603
|
+
when 32
|
604
|
+
symbols.each do |symbol|
|
605
|
+
if symbol.keys.include? :name
|
606
|
+
name_offset = sym_strtab_contents.bytesize
|
607
|
+
sym_strtab_contents << symbol[:name] + "\0"
|
608
|
+
else
|
609
|
+
name_offset = 0
|
610
|
+
end
|
611
|
+
|
612
|
+
# name
|
613
|
+
symtab_content.bytes name_offset, elf_word
|
614
|
+
|
615
|
+
# value
|
616
|
+
symtab_content.bytes symbol[:value], elf_addr
|
617
|
+
|
618
|
+
# size
|
619
|
+
symtab_content.bytes symbol[:size] || 0, elf_xword
|
620
|
+
|
621
|
+
symbol_info = symbol[:type] | (symbol[:binding] << 4)
|
622
|
+
# info
|
623
|
+
symtab_content.bytes symbol_info, elf_char
|
624
|
+
|
625
|
+
# other
|
626
|
+
symtab_content.bytes 0, elf_char
|
627
|
+
|
628
|
+
# shndx
|
629
|
+
symtab_content.bytes symbol[:section_index], elf_half
|
487
630
|
end
|
488
631
|
end
|
489
632
|
|
490
|
-
sections[sh_strtab_section_index][:content] = sections_string_table_content
|
491
633
|
|
492
|
-
|
634
|
+
symtab_section = {
|
635
|
+
name: ".symtab",
|
636
|
+
type: 2,
|
637
|
+
flags: section_flags,
|
638
|
+
addr: 0,
|
639
|
+
link: section_link,
|
640
|
+
info: section_info,
|
641
|
+
addralign: 0,
|
642
|
+
entsize: symtab_ent_size,
|
643
|
+
content: symtab_content.result,
|
644
|
+
}
|
645
|
+
|
646
|
+
return symtab_section, sym_strtab_contents
|
493
647
|
|
494
648
|
end
|
495
649
|
|
650
|
+
|
651
|
+
# Create string table section
|
652
|
+
# Creates a hash with information for a string table section
|
653
|
+
#
|
654
|
+
# Arguments:
|
655
|
+
# string_content - the string table's content
|
656
|
+
# **options - additional options
|
657
|
+
#
|
658
|
+
# Options:
|
659
|
+
# name - the section's name (default is nil)
|
660
|
+
# info - the section's info field value (default is 0)
|
661
|
+
# link - the section's link field value (default is 0)
|
662
|
+
# flags - the section's flags field value (default is 0)
|
663
|
+
# addr - the section's addr field value (default is 0)
|
664
|
+
# addralign - the section's addralign field value (default is 0)
|
665
|
+
# elf_class - ELF class 32 or 64 (not used)
|
666
|
+
#
|
667
|
+
def self.create_strtab_section string_content, **options
|
668
|
+
name = options[:name]
|
669
|
+
info = options[:info] || 0
|
670
|
+
link = options[:link] || 0
|
671
|
+
flags = options[:flags] || 0
|
672
|
+
addr = options[:addr] || 0
|
673
|
+
addralign = options[:addralign] || 0
|
674
|
+
|
675
|
+
|
676
|
+
section = {
|
677
|
+
type: 3,
|
678
|
+
info: info,
|
679
|
+
link: link,
|
680
|
+
flags: flags,
|
681
|
+
addr: addr,
|
682
|
+
addralign: addralign,
|
683
|
+
content: string_content,
|
684
|
+
entsize: 0,
|
685
|
+
}
|
686
|
+
|
687
|
+
section[:name] = name if name != nil
|
688
|
+
|
689
|
+
return section
|
690
|
+
end
|
691
|
+
|
692
|
+
|
693
|
+
|
496
694
|
end # Kompiler::ELF
|
497
695
|
end # Kompiler::Wrappers
|
498
696
|
|
@@ -0,0 +1,441 @@
|
|
1
|
+
require 'kompiler/wrappers/packed_bytes'
|
2
|
+
|
3
|
+
|
4
|
+
module Kompiler
|
5
|
+
|
6
|
+
module Wrappers
|
7
|
+
|
8
|
+
|
9
|
+
module MachO
|
10
|
+
|
11
|
+
MH_MAGIC_32 = 0xfeedface
|
12
|
+
MH_MAGIC_64 = 0xfeedfacf
|
13
|
+
|
14
|
+
|
15
|
+
def self.wrap_obj code, symbols, arch_type: 64, cputype: 0, cpusubtype: 0
|
16
|
+
|
17
|
+
segments = [
|
18
|
+
{
|
19
|
+
name: "__TEXT",
|
20
|
+
vaddr: 0,
|
21
|
+
vsize: code.bytesize,
|
22
|
+
maxprot: 7,
|
23
|
+
initprot: 7,
|
24
|
+
flags: 0,
|
25
|
+
|
26
|
+
sections: [
|
27
|
+
{
|
28
|
+
name: "__text",
|
29
|
+
vaddr: 0,
|
30
|
+
vsize: 0,
|
31
|
+
align: 1,
|
32
|
+
flags: 0,
|
33
|
+
content: code,
|
34
|
+
},
|
35
|
+
]
|
36
|
+
}
|
37
|
+
]
|
38
|
+
|
39
|
+
|
40
|
+
output = MachO.build(segments: segments, symbols: symbols, arch_type: arch_type, cputype: cputype, cpusubtype: cpusubtype, filetype: 1, align_section_contents: false)
|
41
|
+
|
42
|
+
return output
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
def self.build_macho_header arch_type: 64, cputype: 0, cpusubtype: 0, filetype: 0, ncmds: 0, sizeofcmds: 0, flags: 0
|
53
|
+
|
54
|
+
macho_header = PackedBytes.new
|
55
|
+
|
56
|
+
case arch_type
|
57
|
+
when 64
|
58
|
+
macho_header.uint32 MH_MAGIC_64
|
59
|
+
when 32
|
60
|
+
macho_header.uint32 MH_MAGIC_32
|
61
|
+
end
|
62
|
+
|
63
|
+
macho_header.uint32 cputype
|
64
|
+
macho_header.uint32 cpusubtype
|
65
|
+
|
66
|
+
macho_header.uint32 filetype
|
67
|
+
|
68
|
+
macho_header.uint32 ncmds
|
69
|
+
|
70
|
+
macho_header.uint32 sizeofcmds
|
71
|
+
|
72
|
+
macho_header.uint32 flags
|
73
|
+
|
74
|
+
if arch_type == 64
|
75
|
+
# Reserved field in 64-bit
|
76
|
+
macho_header.uint32 0
|
77
|
+
end
|
78
|
+
|
79
|
+
return macho_header
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# Build a Mach-O file from the input segments, symbols and other pre-built load commands
|
84
|
+
#
|
85
|
+
# Arguments:
|
86
|
+
# segments - list of segments to include in the file (structure below)
|
87
|
+
# symbols - list of symbols to be included inside a single symtab (structure below)
|
88
|
+
# prebuilt_lcs - a list of other already built load commands (strings) to be included in the file
|
89
|
+
# arch_type - architecture type, either 32- or 64-bit (default is 64)
|
90
|
+
# cputype - Mach-O header cputype field
|
91
|
+
# cpusubtype - Mach-O header cpusubtype field
|
92
|
+
# filetype - Mach-O file type
|
93
|
+
# align_section_contents - specifies whether to align the contents of each section to its alignment boundary (default is false)
|
94
|
+
#
|
95
|
+
# Segment structure:
|
96
|
+
# name - the segment's name
|
97
|
+
# vaddr - virtual load address of the segment
|
98
|
+
# vsize - virtual size in memory of the segment
|
99
|
+
# maxprot - Mach-O segment maxprot field
|
100
|
+
# initprot - Mach-O segment initprot field
|
101
|
+
# flags - Mach-O segment flags field
|
102
|
+
# sections - a list of segment's section (structure below)
|
103
|
+
#
|
104
|
+
# Segment section structure:
|
105
|
+
# name - the section's name
|
106
|
+
# vaddr - virtual load address of section
|
107
|
+
# vsize - virtual size in memory of the section
|
108
|
+
# align - section's byte alignment
|
109
|
+
# flags - section's flags
|
110
|
+
# content - section's content
|
111
|
+
#
|
112
|
+
# Symbol structure:
|
113
|
+
# name - symbol's name
|
114
|
+
# value - symbol's value
|
115
|
+
# type - symbol's type field value
|
116
|
+
# sect - symbol's sect field value
|
117
|
+
# desc - symbol's desc field value
|
118
|
+
#
|
119
|
+
def self.build segments: [], symbols: [], prebuilt_lcs: [], arch_type: 64, cputype: 0, cpusubtype: 0, filetype: 0, align_section_contents: false
|
120
|
+
|
121
|
+
file_content = PackedBytes.new
|
122
|
+
|
123
|
+
case arch_type
|
124
|
+
when 32
|
125
|
+
flexval_size = 4
|
126
|
+
when 64
|
127
|
+
flexval_size = 8
|
128
|
+
end
|
129
|
+
|
130
|
+
segment_entry_size = 4 * 2 + 16 + flexval_size * 4 + 4 * 2 + 4 * 2
|
131
|
+
|
132
|
+
section_entry_size = 16 + 16 + flexval_size * 2 + 7 * 4
|
133
|
+
|
134
|
+
if arch_type == 64
|
135
|
+
section_entry_size += 4 # one more reserved field for 64-bit
|
136
|
+
end
|
137
|
+
|
138
|
+
symtab_entry_size = 4 * 6
|
139
|
+
|
140
|
+
|
141
|
+
n_sections = 1
|
142
|
+
|
143
|
+
prebuilt_lcs_size = prebuilt_lcs.map(&:bytesize).sum
|
144
|
+
|
145
|
+
cmds_size = segment_entry_size + section_entry_size * n_sections + symtab_entry_size + prebuilt_lcs_size
|
146
|
+
|
147
|
+
|
148
|
+
n_cmds = segments.size + 1 + prebuilt_lcs.size # One segment (with possibly multiple sections), one symtab
|
149
|
+
|
150
|
+
macho_header = build_macho_header(
|
151
|
+
arch_type: 64,
|
152
|
+
cputype: cputype,
|
153
|
+
cpusubtype: cpusubtype,
|
154
|
+
filetype: filetype,
|
155
|
+
ncmds: n_cmds,
|
156
|
+
sizeofcmds: cmds_size,
|
157
|
+
flags: 0
|
158
|
+
)
|
159
|
+
|
160
|
+
|
161
|
+
file_content.add macho_header
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
# Calculate where all of the content can be placed
|
166
|
+
contents_offset = cmds_size + file_content.result.bytesize
|
167
|
+
|
168
|
+
|
169
|
+
contents = ""
|
170
|
+
|
171
|
+
|
172
|
+
|
173
|
+
segments.each do |segment|
|
174
|
+
|
175
|
+
raise "Segment name is larger than 16 characters" if segment[:name].bytesize > 16
|
176
|
+
|
177
|
+
start_size = contents.bytesize
|
178
|
+
|
179
|
+
segment[:sections].each_with_index do |section, section_i|
|
180
|
+
|
181
|
+
raise "Section name \"#{section[:name]}\" is larger than 16 characters" if section[:name].bytesize > 16
|
182
|
+
|
183
|
+
section[:align] ||= 1
|
184
|
+
|
185
|
+
raise "Section alignment value cannot be 0" if section[:align] == 0
|
186
|
+
|
187
|
+
sec_offset = contents_offset + contents.bytesize
|
188
|
+
|
189
|
+
pad_amount = 0
|
190
|
+
if (sec_offset % section[:align] != 0) && align_sections
|
191
|
+
pad_amount = section[:align] - (sec_offset % section[:align])
|
192
|
+
end
|
193
|
+
|
194
|
+
sec_offset += pad_amount
|
195
|
+
contents << "\0" * pad_amount
|
196
|
+
|
197
|
+
section[:file_offset] = sec_offset
|
198
|
+
|
199
|
+
if section_i == 0
|
200
|
+
segment[:file_offset] = sec_offset
|
201
|
+
start_size = contents.bytesize
|
202
|
+
end
|
203
|
+
|
204
|
+
contents << section[:content]
|
205
|
+
|
206
|
+
section[:vaddr] ||= 0
|
207
|
+
section[:vsize] ||= section[:content].bytesize
|
208
|
+
end
|
209
|
+
|
210
|
+
end_size = contents.bytesize
|
211
|
+
|
212
|
+
segment[:file_offset] ||= 0
|
213
|
+
segment[:filesize] = end_size - start_size
|
214
|
+
|
215
|
+
segment[:vaddr] ||= 0
|
216
|
+
segment[:vsize] ||= segment[:filesize]
|
217
|
+
|
218
|
+
segment[:flags] ||= 0
|
219
|
+
|
220
|
+
segment[:maxprot] ||= 0
|
221
|
+
segment[:initprot] ||= 0
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
symtab_contents = PackedBytes.new
|
228
|
+
|
229
|
+
sym_strtab_contents = "\0"
|
230
|
+
|
231
|
+
symbols.each do |symbol|
|
232
|
+
if symbol.keys.include? :name
|
233
|
+
symbol[:name_offset] = sym_strtab_contents.bytesize
|
234
|
+
sym_strtab_contents << symbol[:name] + "\0"
|
235
|
+
else
|
236
|
+
symbol[:name_offset] = 0
|
237
|
+
end
|
238
|
+
|
239
|
+
symtab_contents.uint32 symbol[:name_offset]
|
240
|
+
symtab_contents.uint8 symbol[:type]
|
241
|
+
symtab_contents.uint8 symbol[:sect]
|
242
|
+
symtab_contents.uint16 symbol[:desc]
|
243
|
+
symtab_contents.bytes symbol[:value], flexval_size
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
symtab_offset = contents.bytesize + contents_offset
|
248
|
+
symtab_align = 8
|
249
|
+
|
250
|
+
if symtab_offset % symtab_align != 0
|
251
|
+
pad = (symtab_align - (symtab_offset % symtab_align))
|
252
|
+
contents << "\0" * pad
|
253
|
+
symtab_offset += pad
|
254
|
+
end
|
255
|
+
|
256
|
+
contents << symtab_contents.result
|
257
|
+
|
258
|
+
sym_strtab_offset = contents.bytesize + contents_offset
|
259
|
+
|
260
|
+
contents << sym_strtab_contents
|
261
|
+
|
262
|
+
|
263
|
+
|
264
|
+
load_commands = PackedBytes.new
|
265
|
+
|
266
|
+
|
267
|
+
segments.each do |segment|
|
268
|
+
|
269
|
+
case arch_type
|
270
|
+
when 64
|
271
|
+
load_commands.uint32 0x19 # LC_SEGMENT_64
|
272
|
+
when 32
|
273
|
+
load_commands.uint32 0x1 # LC_SEGMENT
|
274
|
+
end
|
275
|
+
|
276
|
+
load_commands.uint32 segment_entry_size + section_entry_size * segment[:sections].size
|
277
|
+
|
278
|
+
load_commands.bytes segment[:name] + "\0" * (16 - segment[:name].bytesize)
|
279
|
+
|
280
|
+
load_commands.bytes segment[:vaddr], flexval_size
|
281
|
+
load_commands.bytes segment[:vsize], flexval_size
|
282
|
+
|
283
|
+
load_commands.bytes segment[:file_offset], flexval_size
|
284
|
+
load_commands.bytes segment[:filesize], flexval_size
|
285
|
+
|
286
|
+
load_commands.uint32 segment[:maxprot]
|
287
|
+
load_commands.uint32 segment[:initprot]
|
288
|
+
|
289
|
+
load_commands.uint32 segment[:sections].size
|
290
|
+
|
291
|
+
load_commands.uint32 segment[:flags]
|
292
|
+
|
293
|
+
|
294
|
+
|
295
|
+
segment[:sections].each do |section|
|
296
|
+
|
297
|
+
load_commands.bytes section[:name] + "\0" * (16 - section[:name].bytesize)
|
298
|
+
load_commands.bytes segment[:name] + "\0" * (16 - segment[:name].bytesize)
|
299
|
+
|
300
|
+
load_commands.bytes section[:vaddr], flexval_size
|
301
|
+
load_commands.bytes section[:vsize], flexval_size
|
302
|
+
|
303
|
+
load_commands.uint32 section[:file_offset]
|
304
|
+
load_commands.uint32 section[:align]
|
305
|
+
|
306
|
+
load_commands.uint32 0 # reloff
|
307
|
+
load_commands.uint32 0 # nreloc
|
308
|
+
|
309
|
+
load_commands.uint32 section[:flags]
|
310
|
+
|
311
|
+
load_commands.uint32 0 # reserved 1
|
312
|
+
load_commands.uint32 0 # reserved 2
|
313
|
+
|
314
|
+
if arch_type == 64
|
315
|
+
load_commands.uint32 0 # reserved 3 (only in 64-bit)
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
|
322
|
+
|
323
|
+
# Symtab load command
|
324
|
+
|
325
|
+
load_commands.uint32 0x2 # LC_SYMTAB
|
326
|
+
load_commands.uint32 symtab_entry_size
|
327
|
+
|
328
|
+
load_commands.uint32 symtab_offset
|
329
|
+
load_commands.uint32 symbols.size
|
330
|
+
|
331
|
+
load_commands.uint32 sym_strtab_offset
|
332
|
+
load_commands.uint32 sym_strtab_contents.bytesize
|
333
|
+
|
334
|
+
|
335
|
+
load_commands.add prebuilt_lcs
|
336
|
+
|
337
|
+
|
338
|
+
file_content.add load_commands
|
339
|
+
|
340
|
+
|
341
|
+
file_content.add contents
|
342
|
+
|
343
|
+
|
344
|
+
return file_content.result
|
345
|
+
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
# Converts a hash of label name-address pairs into section symbols suitable for the MachO.build method
|
350
|
+
#
|
351
|
+
# Arguments:
|
352
|
+
# labels - the hash of labels
|
353
|
+
# section_index - index of the section the symbols belong to (default is 1)
|
354
|
+
# external - specifies if the label is external or not (default is false)
|
355
|
+
# private_external - specifies if the label is private external or not (default is false)
|
356
|
+
# debug_entry - specifies if the label is a debug entry or not (default is false)
|
357
|
+
def self.labels_to_symbols labels,
|
358
|
+
out = []
|
359
|
+
labels.each do |name, value|
|
360
|
+
out << create_symbol(name: name, value: value, type: :sect, external: false, section_number: 1)
|
361
|
+
end
|
362
|
+
return out
|
363
|
+
end
|
364
|
+
|
365
|
+
|
366
|
+
# Creates a symbol from input information suitable for the MachO.build method
|
367
|
+
#
|
368
|
+
# Arguments:
|
369
|
+
# name - the symbol's name
|
370
|
+
# value - the symbol's value
|
371
|
+
# type - the symbol's type: :undef, :abs, :sect, :prebound, :indirect (default is :sect)
|
372
|
+
# private_external - specifies whether the symbol is private external (default is false)
|
373
|
+
# external - specifies whether the symbol is external (default is false)
|
374
|
+
# debug_entry - specifies whether the symbol is a debugging entry (default is false)
|
375
|
+
# options - options depending on the symbol's type
|
376
|
+
#
|
377
|
+
# Type == :sect options:
|
378
|
+
# section_number - section number the symbol is defined in
|
379
|
+
#
|
380
|
+
def self.create_symbol name: nil, value: nil, type: :sect, private_external: false, external: false, debug_entry: false, **options
|
381
|
+
|
382
|
+
raise "No name provided for the symbol" if name == nil
|
383
|
+
raise "No value provided for the symbol" if value == nil
|
384
|
+
|
385
|
+
symbol = {name: name, value: value}
|
386
|
+
|
387
|
+
type_encodings = {undef: 0x0, abs: 0x2, sect: 0xe, prebound: 0xc, indirect: 0xa}
|
388
|
+
encoded_type = type_encodings[type]
|
389
|
+
|
390
|
+
raise "Unknown symbol type \"#{type}\" - must be :undef, :abs, :sect, :prebound, or :indirect." if encoded_type == nil
|
391
|
+
|
392
|
+
|
393
|
+
pext_bit = 0x0
|
394
|
+
if private_external == true
|
395
|
+
pext_bit = 0x10
|
396
|
+
end
|
397
|
+
|
398
|
+
ext_bit = 0x0
|
399
|
+
if external == true
|
400
|
+
ext_bit = 0x1
|
401
|
+
end
|
402
|
+
|
403
|
+
debug_entry_bit = 0x0
|
404
|
+
if debug_entry == true
|
405
|
+
debug_entry_bit = 0xe
|
406
|
+
end
|
407
|
+
|
408
|
+
type_field = encoded_type | pext_bit | ext_bit | debug_entry_bit
|
409
|
+
|
410
|
+
symbol[:type] = type_field
|
411
|
+
|
412
|
+
|
413
|
+
case type
|
414
|
+
when :undef
|
415
|
+
symbol[:sect] = 0
|
416
|
+
when :abs
|
417
|
+
symbol[:sect] = 0
|
418
|
+
when :sect
|
419
|
+
section_number = options[:section_number] || 0
|
420
|
+
raise "Section number too high - maximum is 255." if section_number > 255
|
421
|
+
symbol[:sect] = section_number
|
422
|
+
when :prebound
|
423
|
+
symbol[:sect] = 0
|
424
|
+
when :indirect
|
425
|
+
symbol[:sect] = 0
|
426
|
+
end
|
427
|
+
|
428
|
+
symbol[:desc] = 0
|
429
|
+
|
430
|
+
return symbol
|
431
|
+
end
|
432
|
+
|
433
|
+
|
434
|
+
|
435
|
+
end # Kompiler::Wrappers::MachO
|
436
|
+
|
437
|
+
end # Kompiler::Wrappers
|
438
|
+
|
439
|
+
end # Kompiler
|
440
|
+
|
441
|
+
|
data/lib/kompiler/wrappers.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.2
|
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-
|
11
|
+
date: 2025-04-06 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
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- lib/kompiler/parsers.rb
|
43
43
|
- lib/kompiler/wrappers.rb
|
44
44
|
- lib/kompiler/wrappers/elf_wrapper.rb
|
45
|
+
- lib/kompiler/wrappers/macho_wrapper.rb
|
45
46
|
- lib/kompiler/wrappers/packed_bytes.rb
|
46
47
|
homepage: https://github.com/kyryloshy/kompiler
|
47
48
|
licenses:
|