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
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
|
open import Basic_classes
open import Bool
open import Function
open import List
open import Maybe
open import Num
open import String
open import Elf_types
open import Endianness
open import String_table
open import Bitstring
open import Error
open import Missing_pervasives
open import Show
(** Special section indices. *)
(** [shn_undef]: marks an undefined, missing or irrelevant section reference.
*)
let shn_undef : nat = 0
(** [shn_loreserve]: this specifies the lower bound of the range of reserved
* indices.
*)
let shn_loreserve : nat = 65280 (* 0xff00 *)
(** [shn_loproc]: start of the range reserved for processor-specific semantics.
*)
let shn_loproc : nat = 65280 (* 0xff00 *)
(** [shn_hiproc]: end of the range reserved for processor-specific semantics.
*)
let shn_hiproc : nat = 65311 (* 0xff1f *)
(** [shn_loos]: start of the range reserved for operating system-specific
* semantics.
*)
let shn_loos : nat = 65312 (* 0xff20 *)
(** [shn_hios]: end of the range reserved for operating system-specific
* semantics.
*)
let shn_hios : nat = 65343 (* 0xff3f *)
(** [shn_abs]: specifies the absolute values for the corresponding reference.
* Symbols defined relative to section number [shn_abs] have absolute values
* and are not affected by relocation.
*)
let shn_abs : nat = 65521 (* 0xfff1 *)
(** [shn_common]: symbols defined relative to this index are common symbols,
* such as unallocated C external variables.
*)
let shn_common : nat = 65522 (* 0xfff2 *)
(** [shn_xindex]: an escape value. It indicates the actual section header index
* is too large to fit in the containing field and is located in another
* location (specific to the structure where it appears).
*)
let shn_xindex : nat = 65535 (* 0xffff *)
(** [shn_hireserve]: specifies the upper-bound of reserved values.
*)
let shn_hireserve : nat = 65535 (* 0xffff *)
val string_of_special_section_index : nat -> string
let string_of_special_section_index i =
if i = shn_undef then
"SHN_UNDEF"
else if i = shn_loreserve then
"SHN_LORESERVE"
else if i >= shn_loproc && i <= shn_hiproc then
"SHN_PROCESSOR_SPECIFIC"
else if i >= shn_loos && i <= shn_hios then
"SHN_OS_SPECIFIC"
else if i = shn_abs then
"SHN_ABS"
else if i = shn_common then
"SHN_COMMON"
else if i = shn_xindex then
"SHN_XINDEX"
else if i = shn_hireserve then
"SHN_HIRESERVE"
else
"SHN UNDEFINED"
(** Section types. *)
(** Marks the section header as being inactive. *)
let sht_null : nat = 0
(** Section holds information defined by the program. *)
let sht_progbits : nat = 1
(** The following two section types hold a symbol table. An object file may only
* have one symbol table of each of the respective types. The symtab provides
* a place for link editing, whereas the dynsym section holds a minimal set of
* dynamic linking symbols
*)
let sht_symtab : nat = 2
let sht_dynsym : nat = 11
(** Section holds a string table *)
let sht_strtab : nat = 3
(** Section holds relocation entries with explicit addends. An object file may
* have multiple section of this type.
*)
let sht_rela : nat = 4
(** Section holds a symbol hash table. An object file may only have a single
* hash table.
*)
let sht_hash : nat = 5
(** Section holds information for dynamic linking. An object file may only have
* a single dynamic section.
*)
let sht_dynamic : nat = 6
(** Section holds information that marks the file in some way. *)
let sht_note : nat = 7
(** Section occupies no space in the file but otherwise resembles a progbits
* section.
*)
let sht_nobits : nat = 8
(** Section holds relocation entries without explicit addends. An object file
* may have multiple section of this type.
*)
let sht_rel : nat = 9
(** Section type is reserved but has an unspecified meaning. *)
let sht_shlib : nat = 10
(** Section contains an array of pointers to initialisation functions. Each
* pointer is taken as a parameterless function with a void return type.
*)
let sht_init_array : nat = 14
(** Section contains an array of pointers to termination functions. Each
* pointer is taken as a parameterless function with a void return type.
*)
let sht_fini_array : nat = 15
(** Section contains an array of pointers to initialisation functions that are
* invoked before all other initialisation functions. Each
* pointer is taken as a parameterless function with a void return type.
*)
let sht_preinit_array : nat = 16
(** Section defines a section group, i.e. a set of sections that are related and
* must be treated especially by the linker. May only appear in relocatable
* objects.
*)
let sht_group : nat = 17
(** Section is associated with sections of type SHT_SYMTAB and is required if
* any of the section header indices referenced by that symbol table contains
* the escape value SHN_XINDEX.
*
* FIXME: Lem bug as [int] type used throughout Lem codebase, rather than
* [BigInt.t], so Lem chokes on these large constants below, hence the weird
* way in which they are written.
*)
let sht_symtab_shndx : nat = 18
let sht_loos : nat = 3 * 1024 * 1024 * 512 (* 1610612736 (* 0x60000000 *) *)
let sht_hios : nat = (469762047 * 4) + 3 (* 1879048191 (* 0x6fffffff *) *)
let sht_loproc : nat = (469762048 * 4) (* 1879048192 (* 0x70000000 *) *)
let sht_hiproc : nat = (536870911 * 4) + 3 (* 2147483647 (* 0x7fffffff *) *)
let sht_louser : nat = (536870912 * 4) (* 2147483648 (* 0x80000000 *) *)
let sht_hiuser : nat = (603979775 * 4) + 3 (* 2415919103 (* 0x8fffffff *) *)
val string_of_section_type : (nat -> string) -> (nat -> string) ->
(nat -> string) -> nat -> string
let string_of_section_type os proc user i =
if i = sht_null then
"SHT_NULL"
else if i = sht_progbits then
"SHT_PROGBITS"
else if i = sht_symtab then
"SHT_SYMTAB"
else if i = sht_strtab then
"SHT_STRTAB"
else if i = sht_rela then
"SHT_RELA"
else if i = sht_hash then
"SHT_HASH"
else if i = sht_dynamic then
"SHT_DYNAMIC"
else if i = sht_note then
"SHT_NOTE"
else if i = sht_nobits then
"SHT_NOBITS"
else if i = sht_rel then
"SHT_REL"
else if i = sht_shlib then
"SHT_SHLIB"
else if i = sht_dynsym then
"SHT_DYNSYM"
else if i = sht_init_array then
"SHT_INIT_ARRAY"
else if i = sht_fini_array then
"SHT_FINI_ARRAY"
else if i = sht_preinit_array then
"SHT_PREINIT_ARRAY"
else if i = sht_group then
"SHT_GROUP"
else if i = sht_symtab_shndx then
"SHT_SYMTAB_SHNDX"
else if i >= sht_loos && i <= sht_hios then
os i
else if i >= sht_loproc && i <= sht_hiproc then
proc i
else if i >= sht_louser && i <= sht_hiuser then
user i
else
"Undefined or invalid section type"
(** Section header table entry type. *)
(** [elf32_section_header_table_entry] is the type of entries in the section
* header table in 32-bit ELF files. Each entry in the table details a section
* in the body of the ELF file.
*)
type elf32_section_header_table_entry =
<| elf32_sh_name : elf32_word (** Name of the section *)
; elf32_sh_type : elf32_word (** Type of the section and its semantics *)
; elf32_sh_flags : elf32_word (** Flags associated with the section *)
; elf32_sh_addr : elf32_addr (** Address of first byte of section in memory image *)
; elf32_sh_offset : elf32_off (** Offset from beginning of file of first byte of section *)
; elf32_sh_size : elf32_word (** Section size in bytes *)
; elf32_sh_link : elf32_word (** Section header table index link *)
; elf32_sh_info : elf32_word (** Extra information, contents depends on type of section *)
; elf32_sh_addralign : elf32_word (** Alignment constraints for section *)
; elf32_sh_entsize : elf32_word (** Size of each entry in table, if section is one *)
|>
(** [elf64_section_header_table_entry] is the type of entries in the section
* header table in 64-bit ELF files. Each entry in the table details a section
* in the body of the ELF file.
*)
type elf64_section_header_table_entry =
<| elf64_sh_name : elf64_word (** Name of the section *)
; elf64_sh_type : elf64_word (** Type of the section and its semantics *)
; elf64_sh_flags : elf64_xword (** Flags associated with the section *)
; elf64_sh_addr : elf64_addr (** Address of first byte of section in memory image *)
; elf64_sh_offset : elf64_off (** Offset from beginning of file of first byte of section *)
; elf64_sh_size : elf64_xword (** Section size in bytes *)
; elf64_sh_link : elf64_word (** Section header table index link *)
; elf64_sh_info : elf64_word (** Extra information, contents depends on type of section *)
; elf64_sh_addralign : elf64_xword (** Alignment constraints for section *)
; elf64_sh_entsize : elf64_xword (** Size of each entry in table, if section is one *)
|>
val read_elf32_section_header_table_entry : endianness -> bitstring -> error (elf32_section_header_table_entry * bitstring)
let read_elf32_section_header_table_entry endian bs =
read_elf32_word endian bs >>= fun (sh_name, bs) ->
read_elf32_word endian bs >>= fun (sh_type, bs) ->
read_elf32_word endian bs >>= fun (sh_flags, bs) ->
read_elf32_addr endian bs >>= fun (sh_addr, bs) ->
read_elf32_off endian bs >>= fun (sh_offset, bs) ->
read_elf32_word endian bs >>= fun (sh_size, bs) ->
read_elf32_word endian bs >>= fun (sh_link, bs) ->
read_elf32_word endian bs >>= fun (sh_info, bs) ->
read_elf32_word endian bs >>= fun (sh_addralign, bs) ->
read_elf32_word endian bs >>= fun (sh_entsize, bs) ->
return (<| elf32_sh_name = sh_name; elf32_sh_type = sh_type;
elf32_sh_flags = sh_flags; elf32_sh_addr = sh_addr;
elf32_sh_offset = sh_offset; elf32_sh_size = sh_size;
elf32_sh_link = sh_link; elf32_sh_info = sh_info;
elf32_sh_addralign = sh_addralign; elf32_sh_entsize = sh_entsize |>, bs)
val read_elf64_section_header_table_entry : endianness -> bitstring -> error (elf64_section_header_table_entry * bitstring)
let read_elf64_section_header_table_entry endian bs =
read_elf64_word endian bs >>= fun (sh_name, bs) ->
read_elf64_word endian bs >>= fun (sh_type, bs) ->
read_elf64_xword endian bs >>= fun (sh_flags, bs) ->
read_elf64_addr endian bs >>= fun (sh_addr, bs) ->
read_elf64_off endian bs >>= fun (sh_offset, bs) ->
read_elf64_xword endian bs >>= fun (sh_size, bs) ->
read_elf64_word endian bs >>= fun (sh_link, bs) ->
read_elf64_word endian bs >>= fun (sh_info, bs) ->
read_elf64_xword endian bs >>= fun (sh_addralign, bs) ->
read_elf64_xword endian bs >>= fun (sh_entsize, bs) ->
return (<| elf64_sh_name = sh_name; elf64_sh_type = sh_type;
elf64_sh_flags = sh_flags; elf64_sh_addr = sh_addr;
elf64_sh_offset = sh_offset; elf64_sh_size = sh_size;
elf64_sh_link = sh_link; elf64_sh_info = sh_info;
elf64_sh_addralign = sh_addralign; elf64_sh_entsize = sh_entsize |>, bs)
(** The [sht_print_bundle] type is used to tidy up other type signatures. Some of the
* top-level string_of_ functions require six or more functions passed to them,
* which quickly gets out of hand. This type is used to reduce that complexity.
* The first component of the type is an OS specific print function, the second is
* a processor specific print function.
*)
type sht_print_bundle = (nat -> string) * (nat -> string) * (nat -> string)
val string_of_elf32_section_header_table_entry : sht_print_bundle -> elf32_section_header_table_entry -> string
let string_of_elf32_section_header_table_entry (os, proc, user) entry =
unlines [
"\t" ^ "Name: " ^ show entry.elf32_sh_name
; "\t" ^ "Type: " ^ string_of_section_type os proc user (nat_of_elf32_word entry.elf32_sh_type)
; "\t" ^ "Flags: " ^ show entry.elf32_sh_flags
; "\t" ^ "Address: " ^ show entry.elf32_sh_addr
; "\t" ^ "Size: " ^ show entry.elf32_sh_size
]
val string_of_elf64_section_header_table_entry : sht_print_bundle -> elf64_section_header_table_entry -> string
let string_of_elf64_section_header_table_entry (os, proc, user) entry =
unlines [
"\t" ^ "Name: " ^ show entry.elf64_sh_name
; "\t" ^ "Type: " ^ string_of_section_type os proc user (nat_of_elf64_word entry.elf64_sh_type)
; "\t" ^ "Flags: " ^ show entry.elf64_sh_flags
; "\t" ^ "Address: " ^ show entry.elf64_sh_addr
; "\t" ^ "Size: " ^ show entry.elf64_sh_size
]
val string_of_elf32_section_header_table_entry' : sht_print_bundle -> string_table -> elf32_section_header_table_entry -> string
let string_of_elf32_section_header_table_entry' (os, proc, user) stbl entry =
let name =
match get_string_at (nat_of_elf32_word entry.elf32_sh_name) stbl with
| Fail _ -> "Invalid index into string table"
| Success i -> i
end
in
unlines [
"\t" ^ "Name: " ^ name
; "\t" ^ "Type: " ^ string_of_section_type os proc user (nat_of_elf32_word entry.elf32_sh_type)
; "\t" ^ "Flags: " ^ show entry.elf32_sh_flags
; "\t" ^ "Address: " ^ show entry.elf32_sh_addr
; "\t" ^ "Size: " ^ show entry.elf32_sh_size
]
val string_of_elf64_section_header_table_entry' : sht_print_bundle -> string_table -> elf64_section_header_table_entry -> string
let string_of_elf64_section_header_table_entry' (os, proc, user) stbl entry =
let name =
match get_string_at (nat_of_elf64_word entry.elf64_sh_name) stbl with
| Fail _ -> "Invalid index into string table"
| Success i -> i
end
in
unlines [
"\t" ^ "Name: " ^ name
; "\t" ^ "Type: " ^ string_of_section_type os proc user (nat_of_elf64_word entry.elf64_sh_type)
; "\t" ^ "Flags: " ^ show entry.elf64_sh_flags
; "\t" ^ "Address: " ^ show entry.elf64_sh_addr
; "\t" ^ "Size: " ^ show entry.elf64_sh_size
]
let string_of_elf32_section_header_table_entry_default =
string_of_elf32_section_header_table_entry
((const "*Default OS specific print*"),
(const "*Default processor specific print*"),
(const "*Default user specific print*"))
instance (Show elf32_section_header_table_entry)
let show = string_of_elf32_section_header_table_entry_default
end
let string_of_elf64_section_header_table_entry_default =
string_of_elf64_section_header_table_entry
((const "*Default OS specific print*"),
(const "*Default processor specific print*"),
(const "*Default user specific print*"))
instance (Show elf64_section_header_table_entry)
let show = string_of_elf64_section_header_table_entry_default
end
(** Section header table type. *)
(** Type [elf32_section_header_table] represents a section header table for 32-bit
* ELF files. A section header table is an array (implemented as a list, here)
* of section header table entries.
*)
type elf32_section_header_table =
list elf32_section_header_table_entry
class (HasElf32SectionHeaderTable 'a)
val get_elf32_section_header_table : 'a -> maybe elf32_section_header_table
end
(** Type [elf64_section_header_table] represents a section header table for 64-bit
* ELF files. A section header table is an array (implemented as a list, here)
* of section header table entries.
*)
type elf64_section_header_table =
list elf64_section_header_table_entry
class (HasElf64SectionHeaderTable 'a)
val get_elf64_section_header_table : 'a -> maybe elf64_section_header_table
end
let rec read_elf32_section_header_table' endian bs0 =
if length bs0 = 0 then
return []
else
read_elf32_section_header_table_entry endian bs0 >>= fun (entry, bs1) ->
read_elf32_section_header_table' endian bs1 >>= fun tail ->
return (entry::tail)
val read_elf32_section_header_table : nat -> endianness -> bitstring -> error (elf32_section_header_table * bitstring)
let read_elf32_section_header_table table_size endian bs0 =
let (eat, rest) = partition table_size bs0 in
read_elf32_section_header_table' endian eat >>= fun entries ->
return (entries, rest)
;;
let rec read_elf64_section_header_table' endian bs0 =
if length bs0 = 0 then
return []
else
read_elf64_section_header_table_entry endian bs0 >>= fun (entry, bs1) ->
read_elf64_section_header_table' endian bs1 >>= fun tail ->
return (entry::tail)
val read_elf64_section_header_table : nat -> endianness -> bitstring -> error (elf64_section_header_table * bitstring)
let read_elf64_section_header_table table_size endian bs0 =
let (eat, rest) = partition table_size bs0 in
read_elf64_section_header_table' endian eat >>= fun entries ->
return (entries, rest)
;;
val elf32_size_correct : elf32_section_header_table_entry -> elf32_section_header_table -> bool
let elf32_size_correct hdr tbl =
match nat_of_elf32_word hdr.elf32_sh_size with
| 0 -> true
| m -> m = List.length tbl
end
;;
val is_valid_elf32_section_header_table : elf32_section_header_table -> bool
let is_valid_elf32_section_header_table tbl =
match tbl with
| [] -> false
| x::xs ->
nat_of_elf32_word x.elf32_sh_name = 0 &&
nat_of_elf32_word x.elf32_sh_type = sht_null &&
nat_of_elf32_word x.elf32_sh_flags = 0 &&
nat_of_elf32_addr x.elf32_sh_addr = 0 &&
nat_of_elf32_off x.elf32_sh_offset = 0 &&
nat_of_elf32_word x.elf32_sh_info = 0 &&
nat_of_elf32_word x.elf32_sh_addralign = 0 &&
nat_of_elf32_word x.elf32_sh_entsize = 0 &&
elf32_size_correct x tbl
(* XXX: more correctness criteria in time *)
end
val string_of_elf32_section_header_table : sht_print_bundle -> elf32_section_header_table -> string
let string_of_elf32_section_header_table sht_bdl tbl =
unlines (List.map (string_of_elf32_section_header_table_entry sht_bdl) tbl)
val string_of_elf32_section_header_table' : sht_print_bundle -> string_table -> elf32_section_header_table -> string
let string_of_elf32_section_header_table' sht_bdl stbl tbl =
unlines (List.map (string_of_elf32_section_header_table_entry' sht_bdl stbl) tbl)
val string_of_elf64_section_header_table : sht_print_bundle -> elf64_section_header_table -> string
let string_of_elf64_section_header_table sht_bdl tbl =
unlines (List.map (string_of_elf64_section_header_table_entry sht_bdl) tbl)
val string_of_elf64_section_header_table' : sht_print_bundle -> string_table -> elf64_section_header_table -> string
let string_of_elf64_section_header_table' sht_bdl stbl tbl =
unlines (List.map (string_of_elf64_section_header_table_entry' sht_bdl stbl) tbl)
|