kompiler 0.3.0.pre.4 → 0.3.1
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 +241 -33
- data/lib/kompiler/arch_manager.rb +10 -1
- data/lib/kompiler/architecture.rb +5 -1
- data/lib/kompiler/architectures/armv8a/instructions.rb +76 -27
- data/lib/kompiler/architectures/armv8a/load.rb +3 -1
- data/lib/kompiler/architectures/armv8a/simd_fp_instructions.rb +1308 -0
- data/lib/kompiler/architectures/armv8a/simd_fp_registers.rb +23 -0
- data/lib/kompiler/architectures/armv8a/sys_registers.rb +3 -0
- data/lib/kompiler/compiler_functions.rb +32 -8
- data/lib/kompiler/config.rb +12 -1
- data/lib/kompiler/directives.rb +13 -0
- data/lib/kompiler/math_ast.rb +29 -1
- data/lib/kompiler/mc_builder.rb +48 -0
- data/lib/kompiler/parsers.rb +21 -0
- data/lib/kompiler/wrappers/elf_wrapper.rb +697 -0
- data/lib/kompiler/wrappers/packed_bytes.rb +68 -0
- data/lib/kompiler/wrappers.rb +1 -0
- data/lib/kompiler.rb +2 -1
- metadata +8 -3
@@ -0,0 +1,697 @@
|
|
1
|
+
#
|
2
|
+
# This file implements ELF Wrappers for raw programs.
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'kompiler/wrappers/packed_bytes'
|
6
|
+
|
7
|
+
|
8
|
+
module Kompiler
|
9
|
+
|
10
|
+
module Wrappers
|
11
|
+
|
12
|
+
module ELF
|
13
|
+
|
14
|
+
# ELF Wrap Object
|
15
|
+
# Wraps a raw program in the ELF relocatable format
|
16
|
+
#
|
17
|
+
# Arguments:
|
18
|
+
# code - raw byte string
|
19
|
+
# symbols - a list of labels and other objects and their corresponding values
|
20
|
+
# options - a hash of configurable options:
|
21
|
+
# elf_class - 32 for ELFClass32 or 64 for ELFClass64 (default is 64)
|
22
|
+
# machine - a raw machine ID to fill in the e_machine field
|
23
|
+
#
|
24
|
+
def self.wrap_obj code, symbols, **options
|
25
|
+
|
26
|
+
elf_class = options[:elf_class] || 64
|
27
|
+
e_machine = options[:machine]
|
28
|
+
|
29
|
+
sections, shstrndx = create_default_sections(code, symbols, elf_class: elf_class).values
|
30
|
+
|
31
|
+
output = build(sections: sections, e_machine: e_machine, elf_class: elf_class, e_shstrndx: shstrndx, e_type: 1)
|
32
|
+
|
33
|
+
output
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# ELF Wrap Executable
|
38
|
+
# Wraps a raw program in the ELF executable format
|
39
|
+
#
|
40
|
+
# Arguments:
|
41
|
+
# code - raw byte string
|
42
|
+
# options - a hash of configurable options:
|
43
|
+
# machine - a raw machine ID to fill in the e_machine field (default is 0)
|
44
|
+
# elf_class - 32 for ELFClass32 or 64 for ELFClass64 (default is 64)
|
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)
|
48
|
+
def self.wrap_exec code, symbols, **options
|
49
|
+
|
50
|
+
elf_class = options[:elf_class] || 64
|
51
|
+
e_machine = options[:machine] || 0
|
52
|
+
vaddr = options[:vaddr] || 0x80000
|
53
|
+
align = options[:align] || 0x1000
|
54
|
+
flags = options[:flags] || 0b111
|
55
|
+
|
56
|
+
sections, shstrndx = create_default_sections(code, symbols, elf_class: elf_class).values
|
57
|
+
|
58
|
+
sections[1][:addr] = vaddr
|
59
|
+
|
60
|
+
segments = [
|
61
|
+
{
|
62
|
+
type: 1, # Loadable segment
|
63
|
+
flags: flags, # Execute, write, read permissions
|
64
|
+
vaddr: vaddr, # Virtual address of segment in memory
|
65
|
+
# content: code,
|
66
|
+
content_section_i: 1,
|
67
|
+
align: align
|
68
|
+
},
|
69
|
+
]
|
70
|
+
|
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)
|
72
|
+
|
73
|
+
output
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
# Converts a label hash of name-address pairs into an array of symbols
|
80
|
+
def self.labels_to_symbols labels
|
81
|
+
out = []
|
82
|
+
labels.each do |name, value|
|
83
|
+
out << {name: name, value: value, type: 0, binding: 0}
|
84
|
+
end
|
85
|
+
out
|
86
|
+
end
|
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
|
+
|
96
|
+
|
97
|
+
# Build ELF
|
98
|
+
# Builds an ELF from provided sections, segments, and other options
|
99
|
+
#
|
100
|
+
# Arguments:
|
101
|
+
# sections - ELF sections (structure below)
|
102
|
+
# segments - ELF segments (structure below)
|
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)
|
124
|
+
#
|
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
|
138
|
+
|
139
|
+
|
140
|
+
case elf_class
|
141
|
+
when 64
|
142
|
+
elf_addr = 8
|
143
|
+
elf_off = 8
|
144
|
+
elf_half = 2
|
145
|
+
elf_word = 4
|
146
|
+
elf_char = 1
|
147
|
+
elf_xword = 8
|
148
|
+
elf_header_size = 64
|
149
|
+
elf_shentsize = 64
|
150
|
+
elf_phentsize = 56
|
151
|
+
when 32
|
152
|
+
elf_addr = 4
|
153
|
+
elf_off = 4
|
154
|
+
elf_half = 2
|
155
|
+
elf_word = 4
|
156
|
+
elf_char = 1
|
157
|
+
elf_xword = 4
|
158
|
+
elf_header_size = 52
|
159
|
+
elf_shentsize = 40
|
160
|
+
elf_phentsize = 32
|
161
|
+
else
|
162
|
+
raise "Invalid elf_class - must be 32 or 64."
|
163
|
+
end
|
164
|
+
|
165
|
+
# Calculate section header and program header sizes
|
166
|
+
sh_size = sections.size * elf_shentsize
|
167
|
+
ph_size = segments.size * elf_phentsize
|
168
|
+
|
169
|
+
# Calculate the offsets for the section header and program header
|
170
|
+
# In this method, the section header is placed right after the ELF header, and the program header is placed right after the section header
|
171
|
+
elf_shoff = elf_header_size
|
172
|
+
elf_phoff = elf_shoff + sh_size
|
173
|
+
|
174
|
+
|
175
|
+
file_content = PackedBytes.new
|
176
|
+
|
177
|
+
elf_header = PackedBytes.new
|
178
|
+
|
179
|
+
e_ident = PackedBytes.new
|
180
|
+
|
181
|
+
# Magic number
|
182
|
+
e_ident.bytes [127]
|
183
|
+
e_ident.bytes "ELF"
|
184
|
+
|
185
|
+
# EI_Class
|
186
|
+
case elf_class
|
187
|
+
when 64
|
188
|
+
e_ident.bytes 2, elf_char
|
189
|
+
when 32
|
190
|
+
e_ident.bytes 1, elf_char
|
191
|
+
end
|
192
|
+
|
193
|
+
# EI_Data (LSB)
|
194
|
+
e_ident.bytes 1, elf_char
|
195
|
+
|
196
|
+
|
197
|
+
# EI_Version (current)
|
198
|
+
e_ident.bytes 1, elf_char
|
199
|
+
|
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
|
206
|
+
|
207
|
+
elf_header.add e_ident
|
208
|
+
|
209
|
+
# E_Type (input)
|
210
|
+
elf_header.bytes e_type, elf_half
|
211
|
+
|
212
|
+
# E_Machine (input)
|
213
|
+
elf_header.bytes e_machine, elf_half
|
214
|
+
|
215
|
+
# E_version (current)
|
216
|
+
elf_header.bytes 1, elf_word
|
217
|
+
|
218
|
+
# E_entry (input)
|
219
|
+
elf_header.bytes virtual_entry_address, elf_addr
|
220
|
+
|
221
|
+
# E_phoff (calculated earlier)
|
222
|
+
# If there aren't any segments, the elf_phoff should be zero
|
223
|
+
if segments.size == 0
|
224
|
+
elf_header.bytes 0, elf_off
|
225
|
+
else
|
226
|
+
elf_header.bytes elf_phoff, elf_off
|
227
|
+
end
|
228
|
+
|
229
|
+
# E_shoff (calculated earlier)
|
230
|
+
# If there aren't any sections, the elf_shoff should be zero
|
231
|
+
if sections.size == 0
|
232
|
+
elf_header.bytes 0, elf_off
|
233
|
+
else
|
234
|
+
elf_header.bytes elf_shoff, elf_off
|
235
|
+
end
|
236
|
+
|
237
|
+
# E_flags
|
238
|
+
elf_header.bytes 0, elf_word
|
239
|
+
|
240
|
+
# E_ehsize (ELF header size)
|
241
|
+
elf_header.bytes elf_header_size, elf_half
|
242
|
+
|
243
|
+
# E_phentsize
|
244
|
+
elf_header.bytes elf_phentsize, elf_half
|
245
|
+
|
246
|
+
# E_phnum
|
247
|
+
elf_header.bytes segments.size, elf_half
|
248
|
+
|
249
|
+
# E_shentsize
|
250
|
+
elf_header.bytes elf_shentsize, elf_half
|
251
|
+
|
252
|
+
# E_shnum
|
253
|
+
elf_header.bytes sections.size, elf_half
|
254
|
+
|
255
|
+
# E_shstrndx
|
256
|
+
elf_header.bytes e_shstrndx, elf_half
|
257
|
+
|
258
|
+
file_content.add elf_header
|
259
|
+
|
260
|
+
|
261
|
+
# Used later
|
262
|
+
sections_contents_offset = elf_phoff + ph_size
|
263
|
+
|
264
|
+
sections_content = PackedBytes.new
|
265
|
+
|
266
|
+
sections.each_with_index do |section, section_i|
|
267
|
+
|
268
|
+
if !section.keys.include?(:content)
|
269
|
+
section[:size] = 0
|
270
|
+
section[:offset] = 0
|
271
|
+
next
|
272
|
+
end
|
273
|
+
|
274
|
+
matching_segments = segments.filter{_1[:content_section_i] == section_i}
|
275
|
+
|
276
|
+
largest_alignment = matching_segments.map{|segment| segment[:align] || 1}.max || 1
|
277
|
+
|
278
|
+
file_offset = sections_content.result.bytesize + sections_contents_offset
|
279
|
+
|
280
|
+
if file_offset % largest_alignment != 0
|
281
|
+
sections_content.bytes [0] * (largest_alignment - (file_offset % largest_alignment))
|
282
|
+
end
|
283
|
+
|
284
|
+
section[:size] = section[:content].bytesize
|
285
|
+
section[:offset] = sections_content.result.bytesize + sections_contents_offset
|
286
|
+
|
287
|
+
matching_segments.each do |segment|
|
288
|
+
segment[:offset] ||= 0
|
289
|
+
|
290
|
+
segment[:size] ||= section[:size] - segment[:offset]
|
291
|
+
|
292
|
+
segment[:offset] += section[:offset]
|
293
|
+
end
|
294
|
+
|
295
|
+
sections_content.add section[:content]
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
segments_content = PackedBytes.new
|
300
|
+
|
301
|
+
segments_contents_offset = sections_contents_offset + sections_content.result.bytesize
|
302
|
+
|
303
|
+
segments.each_with_index do |segment, segment_i|
|
304
|
+
|
305
|
+
segment[:align] ||= 1
|
306
|
+
|
307
|
+
segment[:vaddr] ||= 0
|
308
|
+
|
309
|
+
segment[:paddr] ||= segment[:vaddr]
|
310
|
+
|
311
|
+
if segment.keys.include?(:content)
|
312
|
+
segment[:size] = segment[:content].bytesize
|
313
|
+
end
|
314
|
+
|
315
|
+
segment[:vsize] ||= segment[:size]
|
316
|
+
|
317
|
+
|
318
|
+
if segment[:vaddr] % segment[:align] != 0
|
319
|
+
raise "Improper segment at index #{segment_i} - the virtual address is not aligned to the specified alignment boundary."
|
320
|
+
end
|
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)
|
324
|
+
|
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
|
328
|
+
|
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]
|
338
|
+
|
339
|
+
end
|
340
|
+
|
341
|
+
|
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
|
353
|
+
|
354
|
+
end
|
355
|
+
|
356
|
+
|
357
|
+
sh = PackedBytes.new
|
358
|
+
|
359
|
+
sections.each do |section|
|
360
|
+
sh.bytes section[:name_offset], elf_word
|
361
|
+
sh.bytes section[:type], elf_word
|
362
|
+
sh.bytes section[:flags], elf_xword
|
363
|
+
sh.bytes section[:addr], elf_addr
|
364
|
+
sh.bytes section[:offset], elf_off
|
365
|
+
sh.bytes section[:size], elf_xword
|
366
|
+
sh.bytes section[:link], elf_word
|
367
|
+
sh.bytes section[:info], elf_word
|
368
|
+
sh.bytes section[:addralign], elf_xword
|
369
|
+
sh.bytes section[:entsize], elf_xword
|
370
|
+
end
|
371
|
+
|
372
|
+
|
373
|
+
file_content.add sh
|
374
|
+
|
375
|
+
|
376
|
+
ph = PackedBytes.new
|
377
|
+
|
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
|
401
|
+
end
|
402
|
+
|
403
|
+
file_content.add ph
|
404
|
+
|
405
|
+
|
406
|
+
file_content.add sections_content
|
407
|
+
|
408
|
+
file_content.add segments_content
|
409
|
+
|
410
|
+
|
411
|
+
return file_content.result
|
412
|
+
end
|
413
|
+
|
414
|
+
|
415
|
+
|
416
|
+
# Builds a basic section structure with one progbits section and one symbol table
|
417
|
+
|
418
|
+
def self.create_default_sections program_bytes, symbols, elf_class: 64
|
419
|
+
|
420
|
+
case elf_class
|
421
|
+
when 64
|
422
|
+
symtab_ent_size = 24
|
423
|
+
elf_char = 1
|
424
|
+
elf_half = 2
|
425
|
+
elf_word = 4
|
426
|
+
elf_addr = 8
|
427
|
+
elf_off = 8
|
428
|
+
elf_xword = 8
|
429
|
+
when 32
|
430
|
+
symtab_ent_size = 16
|
431
|
+
elf_char = 1
|
432
|
+
elf_half = 2
|
433
|
+
elf_word = 4
|
434
|
+
elf_addr = 8
|
435
|
+
elf_off = 8
|
436
|
+
elf_xword = 8
|
437
|
+
end
|
438
|
+
|
439
|
+
sym_strtab_section_index = 3
|
440
|
+
sh_strtab_section_index = 4
|
441
|
+
symtab_section_index = 2
|
442
|
+
progbits_section_index = 1
|
443
|
+
|
444
|
+
sections = [
|
445
|
+
# First section is all zeros
|
446
|
+
{
|
447
|
+
type: 0,
|
448
|
+
flags: 0,
|
449
|
+
addr: 0,
|
450
|
+
link: 0,
|
451
|
+
info: 0,
|
452
|
+
addralign: 0,
|
453
|
+
entsize: 0,
|
454
|
+
},
|
455
|
+
{
|
456
|
+
name: ".text",
|
457
|
+
type: 1,
|
458
|
+
flags: 7,
|
459
|
+
addr: 0,
|
460
|
+
link: 0,
|
461
|
+
info: 0,
|
462
|
+
addralign: 4,
|
463
|
+
entsize: 0,
|
464
|
+
content: program_bytes,
|
465
|
+
},
|
466
|
+
]
|
467
|
+
|
468
|
+
|
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)
|
475
|
+
|
476
|
+
sections << symtab_section
|
477
|
+
|
478
|
+
sections << create_strtab_section(sym_strtab_contents, name: ".strtab", elf_class: elf_class)
|
479
|
+
|
480
|
+
|
481
|
+
sections << create_strtab_section("\0", name: ".shstrtab", elf_class: elf_class)
|
482
|
+
|
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"
|
488
|
+
else
|
489
|
+
section[:name_offset] = 0
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
|
494
|
+
return {sections: sections, shstrndx: sh_strtab_section_index}
|
495
|
+
|
496
|
+
end
|
497
|
+
|
498
|
+
|
499
|
+
|
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
|
532
|
+
|
533
|
+
# Check if the auto option was selected
|
534
|
+
if section_info == "first-non-local"
|
535
|
+
|
536
|
+
# Sort symbols for global symbols to come last
|
537
|
+
|
538
|
+
local_symbols = symbols.filter{_1[:binding] == 0}
|
539
|
+
non_local_symbols = symbols.filter{_1[:binding] != 0}
|
540
|
+
|
541
|
+
first_non_local_i = local_symbols.size
|
542
|
+
|
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
|
566
|
+
end
|
567
|
+
|
568
|
+
symtab_content = PackedBytes.new
|
569
|
+
sym_strtab_contents = "\0".encode "ASCII"
|
570
|
+
|
571
|
+
# First entry must be all zeros
|
572
|
+
symtab_content.bytes [0] * symtab_ent_size
|
573
|
+
|
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
|
583
|
+
|
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
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
|
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
|
647
|
+
|
648
|
+
end
|
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
|
+
|
694
|
+
end # Kompiler::ELF
|
695
|
+
end # Kompiler::Wrappers
|
696
|
+
|
697
|
+
end # Kompiler
|