diff options
Diffstat (limited to 'utils/sbtools/elf.c')
-rw-r--r-- | utils/sbtools/elf.c | 240 |
1 files changed, 235 insertions, 5 deletions
diff --git a/utils/sbtools/elf.c b/utils/sbtools/elf.c index f146bcc111..4b95025d8f 100644 --- a/utils/sbtools/elf.c +++ b/utils/sbtools/elf.c | |||
@@ -1,5 +1,135 @@ | |||
1 | #include "elf.h" | 1 | #include "elf.h" |
2 | 2 | ||
3 | /** | ||
4 | * Definitions | ||
5 | * taken from elf.h linux header | ||
6 | * based on ELF specification | ||
7 | * based on ARM ELF specification | ||
8 | */ | ||
9 | typedef uint16_t Elf32_Half; | ||
10 | |||
11 | typedef uint32_t Elf32_Word; | ||
12 | typedef int32_t Elf32_Sword; | ||
13 | typedef uint32_t Elf32_Addr; | ||
14 | typedef uint32_t Elf32_Off; | ||
15 | typedef uint16_t Elf32_Section; | ||
16 | |||
17 | #define EI_NIDENT 16 | ||
18 | |||
19 | typedef struct | ||
20 | { | ||
21 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ | ||
22 | Elf32_Half e_type; /* Object file type */ | ||
23 | Elf32_Half e_machine; /* Architecture */ | ||
24 | Elf32_Word e_version; /* Object file version */ | ||
25 | Elf32_Addr e_entry; /* Entry point virtual address */ | ||
26 | Elf32_Off e_phoff; /* Program header table file offset */ | ||
27 | Elf32_Off e_shoff; /* Section header table file offset */ | ||
28 | Elf32_Word e_flags; /* Processor-specific flags */ | ||
29 | Elf32_Half e_ehsize; /* ELF header size in bytes */ | ||
30 | Elf32_Half e_phentsize; /* Program header table entry size */ | ||
31 | Elf32_Half e_phnum; /* Program header table entry count */ | ||
32 | Elf32_Half e_shentsize; /* Section header table entry size */ | ||
33 | Elf32_Half e_shnum; /* Section header table entry count */ | ||
34 | Elf32_Half e_shstrndx; /* Section header string table index */ | ||
35 | }Elf32_Ehdr; | ||
36 | |||
37 | #define EI_MAG0 0 /* File identification byte 0 index */ | ||
38 | #define ELFMAG0 0x7f /* Magic number byte 0 */ | ||
39 | |||
40 | #define EI_MAG1 1 /* File identification byte 1 index */ | ||
41 | #define ELFMAG1 'E' /* Magic number byte 1 */ | ||
42 | |||
43 | #define EI_MAG2 2 /* File identification byte 2 index */ | ||
44 | #define ELFMAG2 'L' /* Magic number byte 2 */ | ||
45 | |||
46 | #define EI_MAG3 3 /* File identification byte 3 index */ | ||
47 | #define ELFMAG3 'F' /* Magic number byte 3 */ | ||
48 | |||
49 | #define EI_CLASS 4 /* File class byte index */ | ||
50 | #define ELFCLASS32 1 /* 32-bit objects */ | ||
51 | |||
52 | #define EI_DATA 5 /* Data encoding byte index */ | ||
53 | #define ELFDATA2LSB 1 /* 2's complement, little endian */ | ||
54 | |||
55 | #define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */ | ||
56 | |||
57 | #define EI_OSABI 7 /* OS ABI identification */ | ||
58 | #define ELFOSABI_NONE 0 /* UNIX System V ABI */ | ||
59 | #define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ | ||
60 | #define ELFOSABI_ARM 97 /* ARM */ | ||
61 | |||
62 | #define EI_ABIVERSION 8 /* ABI version */ | ||
63 | |||
64 | #define EI_PAD 9 /* Byte index of padding bytes */ | ||
65 | |||
66 | #define ET_EXEC 2 /* Executable file */ | ||
67 | |||
68 | #define EM_ARM 40 /* ARM */ | ||
69 | |||
70 | #define EV_CURRENT 1 /* Current version */ | ||
71 | |||
72 | #define EF_ARM_HASENTRY 0x00000002 | ||
73 | |||
74 | #define SHN_UNDEF 0 /* Undefined section */ | ||
75 | |||
76 | typedef struct | ||
77 | { | ||
78 | Elf32_Word sh_name; /* Section name (string tbl index) */ | ||
79 | Elf32_Word sh_type; /* Section type */ | ||
80 | Elf32_Word sh_flags; /* Section flags */ | ||
81 | Elf32_Addr sh_addr; /* Section virtual addr at execution */ | ||
82 | Elf32_Off sh_offset; /* Section file offset */ | ||
83 | Elf32_Word sh_size; /* Section size in bytes */ | ||
84 | Elf32_Word sh_link; /* Link to another section */ | ||
85 | Elf32_Word sh_info; /* Additional section information */ | ||
86 | Elf32_Word sh_addralign; /* Section alignment */ | ||
87 | Elf32_Word sh_entsize; /* Entry size if section holds table */ | ||
88 | }Elf32_Shdr; | ||
89 | |||
90 | #define SHT_NULL 0 /* Section header table entry unused */ | ||
91 | #define SHT_PROGBITS 1 /* Program data */ | ||
92 | #define SHT_SYMTAB 2 /* Symbol table */ | ||
93 | #define SHT_STRTAB 3 /* String table */ | ||
94 | #define SHT_RELA 4 /* Relocation entries with addends */ | ||
95 | #define SHT_HASH 5 /* Symbol hash table */ | ||
96 | #define SHT_DYNAMIC 6 /* Dynamic linking information */ | ||
97 | #define SHT_NOTE 7 /* Notes */ | ||
98 | #define SHT_NOBITS 8 /* Program space with no data (bss) */ | ||
99 | #define SHT_REL 9 /* Relocation entries, no addends */ | ||
100 | #define SHT_SHLIB 10 /* Reserved */ | ||
101 | #define SHT_DYNSYM 11 /* Dynamic linker symbol table */ | ||
102 | #define SHT_INIT_ARRAY 14 /* Array of constructors */ | ||
103 | #define SHT_FINI_ARRAY 15 /* Array of destructors */ | ||
104 | #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ | ||
105 | #define SHT_GROUP 17 /* Section group */ | ||
106 | #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ | ||
107 | #define SHT_NUM 19 /* Number of defined types. */ | ||
108 | |||
109 | #define SHF_WRITE (1 << 0) /* Writable */ | ||
110 | #define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ | ||
111 | #define SHF_EXECINSTR (1 << 2) /* Executable */ | ||
112 | #define SHF_MERGE (1 << 4) /* Might be merged */ | ||
113 | #define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ | ||
114 | |||
115 | typedef struct | ||
116 | { | ||
117 | Elf32_Word p_type; /* Segment type */ | ||
118 | Elf32_Off p_offset; /* Segment file offset */ | ||
119 | Elf32_Addr p_vaddr; /* Segment virtual address */ | ||
120 | Elf32_Addr p_paddr; /* Segment physical address */ | ||
121 | Elf32_Word p_filesz; /* Segment size in file */ | ||
122 | Elf32_Word p_memsz; /* Segment size in memory */ | ||
123 | Elf32_Word p_flags; /* Segment flags */ | ||
124 | Elf32_Word p_align; /* Segment alignment */ | ||
125 | }Elf32_Phdr; | ||
126 | |||
127 | #define PT_LOAD 1 /* Loadable program segment */ | ||
128 | |||
129 | #define PF_X (1 << 0) /* Segment is executable */ | ||
130 | #define PF_W (1 << 1) /* Segment is writable */ | ||
131 | #define PF_R (1 << 2) /* Segment is readable */ | ||
132 | |||
3 | void elf_init(struct elf_params_t *params) | 133 | void elf_init(struct elf_params_t *params) |
4 | { | 134 | { |
5 | params->has_start_addr = false; | 135 | params->has_start_addr = false; |
@@ -54,7 +184,7 @@ void elf_add_fill_section(struct elf_params_t *params, | |||
54 | sec->pattern = pattern; | 184 | sec->pattern = pattern; |
55 | } | 185 | } |
56 | 186 | ||
57 | void elf_output(struct elf_params_t *params, elf_write_fn_t write, void *user) | 187 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, void *user) |
58 | { | 188 | { |
59 | Elf32_Ehdr ehdr; | 189 | Elf32_Ehdr ehdr; |
60 | uint32_t phnum = 0; | 190 | uint32_t phnum = 0; |
@@ -64,9 +194,11 @@ void elf_output(struct elf_params_t *params, elf_write_fn_t write, void *user) | |||
64 | Elf32_Shdr shdr; | 194 | Elf32_Shdr shdr; |
65 | memset(&ehdr, 0, EI_NIDENT); | 195 | memset(&ehdr, 0, EI_NIDENT); |
66 | 196 | ||
67 | uint32_t bss_strtbl = 0; | 197 | uint32_t bss_strtbl = 1; |
68 | uint32_t text_strtbl = bss_strtbl + strlen(".bss") + 1; | 198 | uint32_t text_strtbl = bss_strtbl + strlen(".bss") + 1; |
69 | uint32_t strtbl_size = text_strtbl + strlen(".text") + 1; | 199 | uint32_t shstrtab_strtbl = text_strtbl + strlen(".text") + 1; |
200 | uint32_t strtbl_size = shstrtab_strtbl + strlen(".shstrtab") + 1; | ||
201 | |||
70 | 202 | ||
71 | while(sec) | 203 | while(sec) |
72 | { | 204 | { |
@@ -182,7 +314,7 @@ void elf_output(struct elf_params_t *params, elf_write_fn_t write, void *user) | |||
182 | } | 314 | } |
183 | 315 | ||
184 | { | 316 | { |
185 | shdr.sh_name = bss_strtbl; | 317 | shdr.sh_name = shstrtab_strtbl; |
186 | shdr.sh_type = SHT_STRTAB; | 318 | shdr.sh_type = SHT_STRTAB; |
187 | shdr.sh_flags = 0; | 319 | shdr.sh_flags = 0; |
188 | shdr.sh_addr = 0; | 320 | shdr.sh_addr = 0; |
@@ -206,7 +338,86 @@ void elf_output(struct elf_params_t *params, elf_write_fn_t write, void *user) | |||
206 | sec = sec->next; | 338 | sec = sec->next; |
207 | } | 339 | } |
208 | 340 | ||
209 | write(user, strtbl_offset + data_offset, ".bss\0.text\0", strtbl_size); | 341 | write(user, strtbl_offset + data_offset, "\0.bss\0.text\0.shstrtab\0", strtbl_size); |
342 | } | ||
343 | |||
344 | bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, | ||
345 | elf_printf_fn_t printf, void *user) | ||
346 | { | ||
347 | #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) | ||
348 | /* read header */ | ||
349 | Elf32_Ehdr ehdr; | ||
350 | if(!read(user, 0, &ehdr, sizeof(ehdr))) | ||
351 | { | ||
352 | printf(user, true, "error reading elf header\n"); | ||
353 | return false; | ||
354 | } | ||
355 | /* basic checks */ | ||
356 | if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || | ||
357 | ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3) | ||
358 | error_printf("invalid elf header\n"); | ||
359 | if(ehdr.e_ident[EI_CLASS] != ELFCLASS32) | ||
360 | error_printf("invalid elf class: must be a 32-bit object\n"); | ||
361 | if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB) | ||
362 | error_printf("invalid elf data encoding: must be 32-bit lsb\n"); | ||
363 | if(ehdr.e_ident[EI_VERSION] != EV_CURRENT) | ||
364 | error_printf("invalid elf version"); | ||
365 | if(ehdr.e_type != ET_EXEC) | ||
366 | error_printf("invalid elf file: must be an executable file\n"); | ||
367 | if(ehdr.e_machine != EM_ARM) | ||
368 | error_printf("invalid elf file: must target an arm machine\n"); | ||
369 | if(ehdr.e_ehsize != sizeof(ehdr)) | ||
370 | error_printf("invalid elf file: size header mismatch\n"); | ||
371 | if(ehdr.e_phentsize != sizeof(Elf32_Phdr)) | ||
372 | error_printf("invalid elf file: program header size mismatch\n"); | ||
373 | if(ehdr.e_shentsize != sizeof(Elf32_Shdr)) | ||
374 | error_printf("invalid elf file: section header size mismatch\n"); | ||
375 | if(ehdr.e_flags & EF_ARM_HASENTRY) | ||
376 | elf_set_start_addr(params, ehdr.e_entry); | ||
377 | |||
378 | char *strtab = NULL; | ||
379 | { | ||
380 | Elf32_Shdr shstrtab; | ||
381 | if(read(user, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize, | ||
382 | &shstrtab, sizeof(shstrtab))) | ||
383 | { | ||
384 | strtab = xmalloc(shstrtab.sh_size); | ||
385 | if(!read(user, shstrtab.sh_offset, strtab, shstrtab.sh_size)) | ||
386 | { | ||
387 | free(strtab); | ||
388 | strtab = NULL; | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | /* run through sections */ | ||
393 | printf(user, false, "ELF file:\n"); | ||
394 | for(int i = 1; i< ehdr.e_shnum; i++) | ||
395 | { | ||
396 | uint32_t off = ehdr.e_shoff + i * ehdr.e_shentsize; | ||
397 | Elf32_Shdr shdr; | ||
398 | memset(&shdr, 0, sizeof(shdr)); | ||
399 | if(!read(user, off, &shdr, sizeof(shdr))) | ||
400 | error_printf("error reading elf section header"); | ||
401 | |||
402 | if(shdr.sh_type == SHT_PROGBITS && shdr.sh_flags & SHF_ALLOC) | ||
403 | { | ||
404 | void *data = xmalloc(shdr.sh_size); | ||
405 | if(!read(user, shdr.sh_offset, data, shdr.sh_size)) | ||
406 | error_printf("error read self section data"); | ||
407 | elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); | ||
408 | |||
409 | printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]); | ||
410 | } | ||
411 | else if(shdr.sh_type == SHT_NOBITS && shdr.sh_flags & SHF_ALLOC) | ||
412 | { | ||
413 | elf_add_fill_section(params, shdr.sh_addr, shdr.sh_size, 0); | ||
414 | printf(user, false, "create fill segment for %s\n", &strtab[shdr.sh_name]); | ||
415 | } | ||
416 | else | ||
417 | printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); | ||
418 | |||
419 | } | ||
420 | return true; | ||
210 | } | 421 | } |
211 | 422 | ||
212 | bool elf_is_empty(struct elf_params_t *params) | 423 | bool elf_is_empty(struct elf_params_t *params) |
@@ -220,6 +431,25 @@ void elf_set_start_addr(struct elf_params_t *params, uint32_t addr) | |||
220 | params->start_addr = addr; | 431 | params->start_addr = addr; |
221 | } | 432 | } |
222 | 433 | ||
434 | bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr) | ||
435 | { | ||
436 | if(params->has_start_addr && addr != NULL) | ||
437 | *addr = params->start_addr; | ||
438 | return params->has_start_addr; | ||
439 | } | ||
440 | |||
441 | int elf_get_nr_sections(struct elf_params_t *params) | ||
442 | { | ||
443 | int nr = 0; | ||
444 | struct elf_section_t *sec = params->first_section; | ||
445 | while(sec) | ||
446 | { | ||
447 | nr++; | ||
448 | sec = sec->next; | ||
449 | } | ||
450 | return nr; | ||
451 | } | ||
452 | |||
223 | void elf_release(struct elf_params_t *params) | 453 | void elf_release(struct elf_params_t *params) |
224 | { | 454 | { |
225 | struct elf_section_t *sec, *next_sec; | 455 | struct elf_section_t *sec, *next_sec; |