/
elfobject.rb
380 lines (309 loc) · 6.6 KB
/
elfobject.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
require_relative 'streamreader'
module ELF
ET_NONE = 0
ET_REL = 1
ET_EXEC = 2
ET_DYN = 3
ET_CORE = 4
EM_NONE = 0
EM_M32 = 1
EM_SPARC = 2
EM_386 = 3
EM_68K = 4
EM_88K = 5
EM_860 = 7
EM_MIPS = 8
EM_ARM = 40
# Custom
EM_TTK91 = 50000
EV_NONE = 0
EV_CURRENT = 1
ELFCLASSNONE = 0
ELFCLASS32 = 1
ELFCLASS64 = 2
ELFDATANONE = 0
ELFDATA2LSB = 1
ELFDATA2MSB = 2
SHT_NULL = 0
SHT_PROGBITS = 1
SHT_SYMTAB = 2
SHT_STRTAB = 3
SHT_RELA = 4
SHT_HASH = 5
SHT_DYNAMIC = 6
SHT_NOTE = 7
SHT_NOBITS = 8
SHT_REL = 9
SHT_SHLIB = 10
SHT_DYNSYM = 11
SHF_WRITE = 0x1
SHF_ALLOC = 0x2
SHF_EXECINSTR = 0x4
STB_LOCAL = 0
STB_GLOBAL = 1
STB_WEAK = 2
ABI_SYSTEMV = 0
ABI_ARM = 0x61
ARM_INFLOOP = "\x08\xf0\x4f\xe2"
TARGET_ARM = [ELFCLASS32, ELFDATA2LSB, ABI_ARM, EM_ARM]
TARGET_X86 = [ELFCLASS32, ELFDATA2LSB, ABI_SYSTEMV, EM_386]
TARGET_TTK91 = [ELFCLASS32, ELFDATA2LSB, ABI_SYSTEMV, EM_TTK91]
end
class ELF::Section
def initialize(name)
@name = name
end
attr_accessor :name, :index
def type
raise 'Reimplement #type'
end
def flags
0
end
def addr
0
end
def link
0
end
def info
0
end
def alignment
1
end
def ent_size
0
end
end
class ELF::StringTableSection < ELF::Section
def initialize(*args)
super
@string_data = "\x00"
@indices = {"" => 0}
end
def add_string(str)
return if @indices[str]
@indices[str] = @string_data.length
@string_data << str << "\x00"
end
def index_for(str)
@indices[str]
end
def write(io)
io << @string_data
end
def type
ELF::SHT_STRTAB
end
end
class ELF::NullSection < ELF::Section
def initialize
super('')
end
def write(io)
end
def type
ELF::SHT_NULL
end
def alignment
0
end
end
class ELF::TextSection < ELF::Section
attr_accessor :text
def write(io)
io << text
end
def type
ELF::SHT_PROGBITS
end
def flags
ELF::SHF_ALLOC | ELF::SHF_EXECINSTR
end
def alignment
4
end
end
class ELF::SymbolTableSection < ELF::Section
def initialize(name, strtab)
super(name)
@strtab = strtab
@symbols = []
end
def add_func_symbol(name, value, text_section, linkage)
@strtab.add_string name
arr = [name, value, text_section, linkage]
if (linkage == ELF::STB_LOCAL)
@symbols.unshift arr
else
@symbols.push arr
end
end
def index_for_name(name)
@symbols.each_with_index { |sym, idx|
if (sym[0] == name)
return idx
end
}
nil
end
def type
ELF::SHT_SYMTAB
end
def ent_size
16
end
def link
@strtab.index
end
def info
i = -1
@symbols.each_with_index { |sym, idx|
if (sym[4] == ELF::STB_LOCAL)
i = idx
end
}
i + 1
end
def write(io)
# write undefined symbol
io.write_uint32 0
io.write_uint32 0
io.write_uint32 0
io.write_uint8 ELF::STB_LOCAL << 4
io.write_uint8 0
io.write_uint16 0
# write other symbols
@symbols.each { |sym|
io.write_uint32 @strtab.index_for(sym[0])
io.write_uint32 sym[1]
io.write_uint32 0
io.write_uint8((sym[3] << 4) + 0)
io.write_uint8 0
if (sym[2])
io.write_uint16 sym[2].index
else
# undefined symbol
io.write_uint16 0
end
}
end
end
class ELF::RelocationTableSection < ELF::Section
def initialize(name, symtab, text_section)
super(name)
@symtab = symtab
@text_section = text_section
@relocs = []
end
def add_reloc(offset, name, type)
@relocs << [offset, name, type]
end
def type
ELF::SHT_REL
end
def ent_size
8
end
def link
@symtab.index
end
def info
@text_section.index
end
def write(io)
@relocs.each { |reloc|
name_idx = @symtab.index_for_name(reloc[1])
io.write_uint32 reloc[0]
# +1 because entry number 0 is und
io.write_uint32 reloc[2] | ((name_idx+1) << 8)
}
end
end
class ELF::ObjectFile
include ELF
def initialize(target)
@target = target
@sections = []
add_section NullSection.new
end
def add_section(section)
@sections << section
section.index = @sections.length - 1
end
def write(io)
io << "\x7fELF"
io.write_uint8 @target[0]
io.write_uint8 @target[1]
io.write_uint8 EV_CURRENT
io.write_uint8 @target[2]
io << "\x00" * 8 # pad
io.write_uint16 ET_REL
io.write_uint16 @target[3]
io.write_uint32 EV_CURRENT
io.write_uint32 0 # entry point
io.write_uint32 0 # no program header table
sh_offset_pos = io.tell
io.write_uint32 0 # section header table offset
io.write_uint32 0 # no flags
io.write_uint16 52 # header length
io.write_uint16 0 # program header length
io.write_uint16 0 # program header count
io.write_uint16 40 # section header length
shstrtab = StringTableSection.new(".shstrtab")
@sections << shstrtab
@sections.each { |section|
shstrtab.add_string section.name
}
io.write_uint16 @sections.length # section header count
io.write_uint16 @sections.length-1 # section name string table index
# write sections
section_data = []
@sections.each { |section|
offset = io.tell
section.write(io)
size = io.tell - offset
section_data << {:section => section, :offset => offset,
:size => size}
}
# write section headers
sh_offset = io.tell
section_data.each { |data|
section, offset, size = data[:section], data[:offset], data[:size]
# write header first
io.write_uint32 shstrtab.index_for(section.name)
io.write_uint32 section.type
io.write_uint32 section.flags
io.write_uint32 section.addr
if (section.type == SHT_NOBITS)
raise 'SHT_NOBITS not handled yet'
elsif (section.type == SHT_NULL)
io.write_uint32 0
io.write_uint32 0
else
io.write_uint32 offset
io.write_uint32 size
end
io.write_uint32 section.link
io.write_uint32 section.info
io.write_uint32 section.alignment
io.write_uint32 section.ent_size
}
io.seek sh_offset_pos
io.write_uint32 sh_offset
end
end
if (__FILE__ == $0)
obj = ELF::ObjectFile.new
sym_strtab = ELF::StringTableSection.new(".strtab")
obj.add_section sym_strtab
symtab = ELF::SymbolTableSection.new(".symtab", sym_strtab)
obj.add_section symtab
text_section = ELF::TextSection.new(".text")
obj.add_section text_section
symtab.add_func_symbol "_start", 0, text_section, ELF::STB_GLOBAL
fp = File.open("test.o", "wb")
obj.write fp
fp.close
end