diff options
Diffstat (limited to 'utils/imxtools/elf.c')
-rw-r--r-- | utils/imxtools/elf.c | 575 |
1 files changed, 575 insertions, 0 deletions
diff --git a/utils/imxtools/elf.c b/utils/imxtools/elf.c new file mode 100644 index 0000000000..481ab98dd6 --- /dev/null +++ b/utils/imxtools/elf.c | |||
@@ -0,0 +1,575 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "elf.h" | ||
22 | #include "misc.h" | ||
23 | |||
24 | /** | ||
25 | * Definitions | ||
26 | * taken from elf.h linux header | ||
27 | * based on ELF specification | ||
28 | * based on ARM ELF specification | ||
29 | */ | ||
30 | typedef uint16_t Elf32_Half; | ||
31 | |||
32 | typedef uint32_t Elf32_Word; | ||
33 | typedef int32_t Elf32_Sword; | ||
34 | typedef uint32_t Elf32_Addr; | ||
35 | typedef uint32_t Elf32_Off; | ||
36 | typedef uint16_t Elf32_Section; | ||
37 | |||
38 | #define EI_NIDENT 16 | ||
39 | |||
40 | typedef struct | ||
41 | { | ||
42 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ | ||
43 | Elf32_Half e_type; /* Object file type */ | ||
44 | Elf32_Half e_machine; /* Architecture */ | ||
45 | Elf32_Word e_version; /* Object file version */ | ||
46 | Elf32_Addr e_entry; /* Entry point virtual address */ | ||
47 | Elf32_Off e_phoff; /* Program header table file offset */ | ||
48 | Elf32_Off e_shoff; /* Section header table file offset */ | ||
49 | Elf32_Word e_flags; /* Processor-specific flags */ | ||
50 | Elf32_Half e_ehsize; /* ELF header size in bytes */ | ||
51 | Elf32_Half e_phentsize; /* Program header table entry size */ | ||
52 | Elf32_Half e_phnum; /* Program header table entry count */ | ||
53 | Elf32_Half e_shentsize; /* Section header table entry size */ | ||
54 | Elf32_Half e_shnum; /* Section header table entry count */ | ||
55 | Elf32_Half e_shstrndx; /* Section header string table index */ | ||
56 | }Elf32_Ehdr; | ||
57 | |||
58 | #define EI_MAG0 0 /* File identification byte 0 index */ | ||
59 | #define ELFMAG0 0x7f /* Magic number byte 0 */ | ||
60 | |||
61 | #define EI_MAG1 1 /* File identification byte 1 index */ | ||
62 | #define ELFMAG1 'E' /* Magic number byte 1 */ | ||
63 | |||
64 | #define EI_MAG2 2 /* File identification byte 2 index */ | ||
65 | #define ELFMAG2 'L' /* Magic number byte 2 */ | ||
66 | |||
67 | #define EI_MAG3 3 /* File identification byte 3 index */ | ||
68 | #define ELFMAG3 'F' /* Magic number byte 3 */ | ||
69 | |||
70 | #define EI_CLASS 4 /* File class byte index */ | ||
71 | #define ELFCLASS32 1 /* 32-bit objects */ | ||
72 | |||
73 | #define EI_DATA 5 /* Data encoding byte index */ | ||
74 | #define ELFDATA2LSB 1 /* 2's complement, little endian */ | ||
75 | |||
76 | #define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */ | ||
77 | |||
78 | #define EI_OSABI 7 /* OS ABI identification */ | ||
79 | #define ELFOSABI_NONE 0 /* UNIX System V ABI */ | ||
80 | #define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ | ||
81 | #define ELFOSABI_ARM 97 /* ARM */ | ||
82 | |||
83 | #define EI_ABIVERSION 8 /* ABI version */ | ||
84 | |||
85 | #define EI_PAD 9 /* Byte index of padding bytes */ | ||
86 | |||
87 | #define ET_EXEC 2 /* Executable file */ | ||
88 | |||
89 | #define EM_ARM 40 /* ARM */ | ||
90 | |||
91 | #define EV_CURRENT 1 /* Current version */ | ||
92 | |||
93 | #define EF_ARM_HASENTRY 0x00000002 | ||
94 | |||
95 | #define SHN_UNDEF 0 /* Undefined section */ | ||
96 | |||
97 | typedef struct | ||
98 | { | ||
99 | Elf32_Word sh_name; /* Section name (string tbl index) */ | ||
100 | Elf32_Word sh_type; /* Section type */ | ||
101 | Elf32_Word sh_flags; /* Section flags */ | ||
102 | Elf32_Addr sh_addr; /* Section virtual addr at execution */ | ||
103 | Elf32_Off sh_offset; /* Section file offset */ | ||
104 | Elf32_Word sh_size; /* Section size in bytes */ | ||
105 | Elf32_Word sh_link; /* Link to another section */ | ||
106 | Elf32_Word sh_info; /* Additional section information */ | ||
107 | Elf32_Word sh_addralign; /* Section alignment */ | ||
108 | Elf32_Word sh_entsize; /* Entry size if section holds table */ | ||
109 | }Elf32_Shdr; | ||
110 | |||
111 | #define SHT_NULL 0 /* Section header table entry unused */ | ||
112 | #define SHT_PROGBITS 1 /* Program data */ | ||
113 | #define SHT_SYMTAB 2 /* Symbol table */ | ||
114 | #define SHT_STRTAB 3 /* String table */ | ||
115 | #define SHT_RELA 4 /* Relocation entries with addends */ | ||
116 | #define SHT_HASH 5 /* Symbol hash table */ | ||
117 | #define SHT_DYNAMIC 6 /* Dynamic linking information */ | ||
118 | #define SHT_NOTE 7 /* Notes */ | ||
119 | #define SHT_NOBITS 8 /* Program space with no data (bss) */ | ||
120 | #define SHT_REL 9 /* Relocation entries, no addends */ | ||
121 | #define SHT_SHLIB 10 /* Reserved */ | ||
122 | #define SHT_DYNSYM 11 /* Dynamic linker symbol table */ | ||
123 | #define SHT_INIT_ARRAY 14 /* Array of constructors */ | ||
124 | #define SHT_FINI_ARRAY 15 /* Array of destructors */ | ||
125 | #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ | ||
126 | #define SHT_GROUP 17 /* Section group */ | ||
127 | #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ | ||
128 | #define SHT_NUM 19 /* Number of defined types. */ | ||
129 | |||
130 | #define SHF_WRITE (1 << 0) /* Writable */ | ||
131 | #define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ | ||
132 | #define SHF_EXECINSTR (1 << 2) /* Executable */ | ||
133 | #define SHF_MERGE (1 << 4) /* Might be merged */ | ||
134 | #define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ | ||
135 | |||
136 | typedef struct | ||
137 | { | ||
138 | Elf32_Word p_type; /* Segment type */ | ||
139 | Elf32_Off p_offset; /* Segment file offset */ | ||
140 | Elf32_Addr p_vaddr; /* Segment virtual address */ | ||
141 | Elf32_Addr p_paddr; /* Segment physical address */ | ||
142 | Elf32_Word p_filesz; /* Segment size in file */ | ||
143 | Elf32_Word p_memsz; /* Segment size in memory */ | ||
144 | Elf32_Word p_flags; /* Segment flags */ | ||
145 | Elf32_Word p_align; /* Segment alignment */ | ||
146 | }Elf32_Phdr; | ||
147 | |||
148 | #define PT_LOAD 1 /* Loadable program segment */ | ||
149 | |||
150 | #define PF_X (1 << 0) /* Segment is executable */ | ||
151 | #define PF_W (1 << 1) /* Segment is writable */ | ||
152 | #define PF_R (1 << 2) /* Segment is readable */ | ||
153 | |||
154 | void elf_init(struct elf_params_t *params) | ||
155 | { | ||
156 | memset(params, 0, sizeof(struct elf_params_t)); | ||
157 | } | ||
158 | |||
159 | extern void *xmalloc(size_t s); | ||
160 | |||
161 | static struct elf_section_t *elf_add_section(struct elf_params_t *params) | ||
162 | { | ||
163 | struct elf_section_t *sec = xmalloc(sizeof(struct elf_section_t)); | ||
164 | if(params->first_section == NULL) | ||
165 | params->first_section = params->last_section = sec; | ||
166 | else | ||
167 | { | ||
168 | params->last_section->next = sec; | ||
169 | params->last_section = sec; | ||
170 | } | ||
171 | sec->next = NULL; | ||
172 | |||
173 | return sec; | ||
174 | } | ||
175 | |||
176 | static struct elf_segment_t *elf_add_segment(struct elf_params_t *params) | ||
177 | { | ||
178 | struct elf_segment_t *seg = xmalloc(sizeof(struct elf_section_t)); | ||
179 | if(params->first_segment == NULL) | ||
180 | params->first_segment = params->last_segment = seg; | ||
181 | else | ||
182 | { | ||
183 | params->last_segment->next = seg; | ||
184 | params->last_segment = seg; | ||
185 | } | ||
186 | seg->next = NULL; | ||
187 | |||
188 | return seg; | ||
189 | } | ||
190 | |||
191 | void elf_add_load_section(struct elf_params_t *params, | ||
192 | uint32_t load_addr, uint32_t size, const void *section) | ||
193 | { | ||
194 | struct elf_section_t *sec = elf_add_section(params); | ||
195 | |||
196 | sec->type = EST_LOAD; | ||
197 | sec->addr = load_addr; | ||
198 | sec->size = size; | ||
199 | sec->section = xmalloc(size); | ||
200 | memcpy(sec->section, section, size); | ||
201 | } | ||
202 | |||
203 | void elf_add_fill_section(struct elf_params_t *params, | ||
204 | uint32_t fill_addr, uint32_t size, uint32_t pattern) | ||
205 | { | ||
206 | if(pattern != 0x00) | ||
207 | { | ||
208 | printf("oops, non-zero filling, ignore fill section\n"); | ||
209 | return; | ||
210 | } | ||
211 | |||
212 | struct elf_section_t *sec = elf_add_section(params); | ||
213 | |||
214 | sec->type = EST_FILL; | ||
215 | sec->addr = fill_addr; | ||
216 | sec->size = size; | ||
217 | sec->pattern = pattern; | ||
218 | } | ||
219 | |||
220 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | ||
221 | elf_printf_fn_t printf, void *user) | ||
222 | { | ||
223 | (void) printf; | ||
224 | |||
225 | Elf32_Ehdr ehdr; | ||
226 | uint32_t phnum = 0; | ||
227 | struct elf_section_t *sec = params->first_section; | ||
228 | uint32_t offset = 0; | ||
229 | Elf32_Phdr phdr; | ||
230 | Elf32_Shdr shdr; | ||
231 | memset(&ehdr, 0, EI_NIDENT); | ||
232 | |||
233 | while(sec) | ||
234 | { | ||
235 | if(sec->type == EST_LOAD) | ||
236 | { | ||
237 | sec->offset = offset; | ||
238 | offset += sec->size; | ||
239 | } | ||
240 | else | ||
241 | { | ||
242 | sec->offset = 0; | ||
243 | } | ||
244 | |||
245 | phnum++; | ||
246 | sec = sec->next; | ||
247 | } | ||
248 | |||
249 | uint32_t strtbl_offset = offset; | ||
250 | |||
251 | ehdr.e_ident[EI_MAG0] = ELFMAG0; | ||
252 | ehdr.e_ident[EI_MAG1] = ELFMAG1; | ||
253 | ehdr.e_ident[EI_MAG2] = ELFMAG2; | ||
254 | ehdr.e_ident[EI_MAG3] = ELFMAG3; | ||
255 | ehdr.e_ident[EI_CLASS] = ELFCLASS32; | ||
256 | ehdr.e_ident[EI_DATA] = ELFDATA2LSB; | ||
257 | ehdr.e_ident[EI_VERSION] = EV_CURRENT; | ||
258 | ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE; | ||
259 | ehdr.e_ident[EI_ABIVERSION] = 0; | ||
260 | ehdr.e_type = ET_EXEC; | ||
261 | ehdr.e_machine = EM_ARM; | ||
262 | ehdr.e_version = EV_CURRENT; | ||
263 | ehdr.e_entry = params->start_addr; | ||
264 | ehdr.e_flags = 0; | ||
265 | if(params->has_start_addr) | ||
266 | ehdr.e_flags |= EF_ARM_HASENTRY; | ||
267 | ehdr.e_ehsize = sizeof ehdr; | ||
268 | ehdr.e_phentsize = sizeof phdr; | ||
269 | ehdr.e_phnum = phnum; | ||
270 | ehdr.e_shentsize = sizeof shdr; | ||
271 | ehdr.e_shnum = phnum + 2; /* one for section 0 and one for string table */ | ||
272 | ehdr.e_shstrndx = ehdr.e_shnum - 1; | ||
273 | ehdr.e_phoff = ehdr.e_ehsize; | ||
274 | ehdr.e_shoff = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize; | ||
275 | |||
276 | write(user, 0, &ehdr, sizeof ehdr); | ||
277 | |||
278 | /* allocate enough size to hold any combinaison of .text/.bss in the string table: | ||
279 | * - one empty name ("\0") | ||
280 | * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0" | ||
281 | * - one name ".shstrtab\0" */ | ||
282 | char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 + | ||
283 | phnum * (strlen(".textXXXX") + 1)); | ||
284 | |||
285 | strtbl_content[0] = '\0'; | ||
286 | strcpy(&strtbl_content[1], ".shstrtab"); | ||
287 | uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1; | ||
288 | |||
289 | uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + | ||
290 | ehdr.e_shnum * ehdr.e_shentsize; | ||
291 | |||
292 | sec = params->first_section; | ||
293 | offset = ehdr.e_phoff; | ||
294 | while(sec) | ||
295 | { | ||
296 | sec->offset += data_offset; | ||
297 | |||
298 | phdr.p_type = PT_LOAD; | ||
299 | if(sec->type == EST_LOAD) | ||
300 | phdr.p_offset = sec->offset; | ||
301 | else | ||
302 | phdr.p_offset = 0; | ||
303 | phdr.p_paddr = sec->addr; | ||
304 | phdr.p_vaddr = phdr.p_paddr; /* assume identity map ? */ | ||
305 | phdr.p_memsz = sec->size; | ||
306 | if(sec->type == EST_LOAD) | ||
307 | phdr.p_filesz = phdr.p_memsz; | ||
308 | else | ||
309 | phdr.p_filesz = 0; | ||
310 | phdr.p_flags = PF_X | PF_W | PF_R; | ||
311 | phdr.p_align = 0; | ||
312 | |||
313 | write(user, offset, &phdr, sizeof phdr); | ||
314 | |||
315 | offset += sizeof(Elf32_Phdr); | ||
316 | sec = sec->next; | ||
317 | } | ||
318 | |||
319 | sec = params->first_section; | ||
320 | offset = ehdr.e_shoff; | ||
321 | |||
322 | { | ||
323 | shdr.sh_name = 0; | ||
324 | shdr.sh_type = SHT_NULL; | ||
325 | shdr.sh_flags = 0; | ||
326 | shdr.sh_addr = 0; | ||
327 | shdr.sh_offset = 0; | ||
328 | shdr.sh_size = 0; | ||
329 | shdr.sh_link = SHN_UNDEF; | ||
330 | shdr.sh_info = 0; | ||
331 | shdr.sh_addralign = 0; | ||
332 | shdr.sh_entsize = 0; | ||
333 | |||
334 | write(user, offset, &shdr, sizeof shdr); | ||
335 | |||
336 | offset += sizeof(Elf32_Shdr); | ||
337 | } | ||
338 | |||
339 | uint32_t text_idx = 0; | ||
340 | uint32_t bss_idx = 0; | ||
341 | while(sec) | ||
342 | { | ||
343 | shdr.sh_name = strtbl_index; | ||
344 | if(sec->type == EST_LOAD) | ||
345 | { | ||
346 | strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++); | ||
347 | shdr.sh_type = SHT_PROGBITS; | ||
348 | } | ||
349 | else | ||
350 | { | ||
351 | strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++); | ||
352 | shdr.sh_type = SHT_NOBITS; | ||
353 | } | ||
354 | shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; | ||
355 | shdr.sh_addr = sec->addr; | ||
356 | shdr.sh_offset = sec->offset; | ||
357 | shdr.sh_size = sec->size; | ||
358 | shdr.sh_link = SHN_UNDEF; | ||
359 | shdr.sh_info = 0; | ||
360 | shdr.sh_addralign = 1; | ||
361 | shdr.sh_entsize = 0; | ||
362 | |||
363 | write(user, offset, &shdr, sizeof shdr); | ||
364 | |||
365 | offset += sizeof(Elf32_Shdr); | ||
366 | sec = sec->next; | ||
367 | } | ||
368 | |||
369 | { | ||
370 | shdr.sh_name = 1; | ||
371 | shdr.sh_type = SHT_STRTAB; | ||
372 | shdr.sh_flags = 0; | ||
373 | shdr.sh_addr = 0; | ||
374 | shdr.sh_offset = strtbl_offset + data_offset; | ||
375 | shdr.sh_size = strtbl_index; | ||
376 | shdr.sh_link = SHN_UNDEF; | ||
377 | shdr.sh_info = 0; | ||
378 | shdr.sh_addralign = 1; | ||
379 | shdr.sh_entsize = 0; | ||
380 | |||
381 | write(user, offset, &shdr, sizeof shdr); | ||
382 | |||
383 | offset += sizeof(Elf32_Shdr); | ||
384 | } | ||
385 | |||
386 | sec = params->first_section; | ||
387 | while(sec) | ||
388 | { | ||
389 | if(sec->type == EST_LOAD) | ||
390 | write(user, sec->offset, sec->section, sec->size); | ||
391 | sec = sec->next; | ||
392 | } | ||
393 | |||
394 | write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index); | ||
395 | free(strtbl_content); | ||
396 | } | ||
397 | |||
398 | bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, | ||
399 | elf_printf_fn_t printf, void *user) | ||
400 | { | ||
401 | #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) | ||
402 | |||
403 | /* read header */ | ||
404 | Elf32_Ehdr ehdr; | ||
405 | if(!read(user, 0, &ehdr, sizeof(ehdr))) | ||
406 | { | ||
407 | printf(user, true, "error reading elf header\n"); | ||
408 | return false; | ||
409 | } | ||
410 | /* basic checks */ | ||
411 | if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || | ||
412 | ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3) | ||
413 | error_printf("invalid elf header\n"); | ||
414 | if(ehdr.e_ident[EI_CLASS] != ELFCLASS32) | ||
415 | error_printf("invalid elf class: must be a 32-bit object\n"); | ||
416 | if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB) | ||
417 | error_printf("invalid elf data encoding: must be 32-bit lsb\n"); | ||
418 | if(ehdr.e_ident[EI_VERSION] != EV_CURRENT) | ||
419 | error_printf("invalid elf version\n"); | ||
420 | if(ehdr.e_type != ET_EXEC) | ||
421 | error_printf("invalid elf file: must be an executable file\n"); | ||
422 | if(ehdr.e_machine != EM_ARM) | ||
423 | error_printf("invalid elf file: must target an arm machine\n"); | ||
424 | if(ehdr.e_ehsize != sizeof(ehdr)) | ||
425 | error_printf("invalid elf file: size header mismatch\n"); | ||
426 | if(ehdr.e_phnum > 0 && ehdr.e_phentsize != sizeof(Elf32_Phdr)) | ||
427 | error_printf("invalid elf file: program header size mismatch\n"); | ||
428 | if(ehdr.e_shnum > 0 && ehdr.e_shentsize != sizeof(Elf32_Shdr)) | ||
429 | error_printf("invalid elf file: section header size mismatch\n"); | ||
430 | elf_set_start_addr(params, ehdr.e_entry); | ||
431 | |||
432 | char *strtab = NULL; | ||
433 | if(ehdr.e_shstrndx != SHN_UNDEF) | ||
434 | { | ||
435 | Elf32_Shdr shstrtab; | ||
436 | if(read(user, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize, | ||
437 | &shstrtab, sizeof(shstrtab))) | ||
438 | { | ||
439 | strtab = xmalloc(shstrtab.sh_size); | ||
440 | if(!read(user, shstrtab.sh_offset, strtab, shstrtab.sh_size)) | ||
441 | { | ||
442 | free(strtab); | ||
443 | strtab = NULL; | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | /* run through sections */ | ||
448 | printf(user, false, "ELF file:\n"); | ||
449 | for(int i = 1; i < ehdr.e_shnum; i++) | ||
450 | { | ||
451 | uint32_t off = ehdr.e_shoff + i * ehdr.e_shentsize; | ||
452 | Elf32_Shdr shdr; | ||
453 | memset(&shdr, 0, sizeof(shdr)); | ||
454 | if(!read(user, off, &shdr, sizeof(shdr))) | ||
455 | error_printf("error reading elf section header"); | ||
456 | |||
457 | if(shdr.sh_type == SHT_PROGBITS && shdr.sh_flags & SHF_ALLOC) | ||
458 | { | ||
459 | void *data = xmalloc(shdr.sh_size); | ||
460 | if(!read(user, shdr.sh_offset, data, shdr.sh_size)) | ||
461 | error_printf("error read self section data\n"); | ||
462 | elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); | ||
463 | free(data); | ||
464 | |||
465 | if(strtab) | ||
466 | printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]); | ||
467 | } | ||
468 | else if(shdr.sh_type == SHT_NOBITS && shdr.sh_flags & SHF_ALLOC) | ||
469 | { | ||
470 | elf_add_fill_section(params, shdr.sh_addr, shdr.sh_size, 0); | ||
471 | if(strtab) | ||
472 | printf(user, false, "create fill segment for %s\n", &strtab[shdr.sh_name]); | ||
473 | } | ||
474 | else | ||
475 | { | ||
476 | if(strtab) | ||
477 | printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); | ||
478 | } | ||
479 | |||
480 | } | ||
481 | free(strtab); | ||
482 | /* run through segments */ | ||
483 | for(int i = 1; i < ehdr.e_phnum; i++) | ||
484 | { | ||
485 | uint32_t off = ehdr.e_phoff + i * ehdr.e_phentsize; | ||
486 | Elf32_Phdr phdr; | ||
487 | memset(&phdr, 0, sizeof(phdr)); | ||
488 | if(!read(user, off, &phdr, sizeof(phdr))) | ||
489 | error_printf("error reading elf segment header"); | ||
490 | if(phdr.p_type != PT_LOAD) | ||
491 | continue; | ||
492 | struct elf_segment_t *seg = elf_add_segment(params); | ||
493 | seg->vaddr = phdr.p_vaddr; | ||
494 | seg->paddr = phdr.p_paddr; | ||
495 | seg->vsize = phdr.p_memsz; | ||
496 | seg->psize = phdr.p_filesz; | ||
497 | printf(user, false, "create segment [%#x,+%#x[ -> [%#x,+%#x[\n", | ||
498 | seg->vaddr, seg->vsize, seg->paddr, seg->psize); | ||
499 | } | ||
500 | |||
501 | return true; | ||
502 | } | ||
503 | |||
504 | uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr) | ||
505 | { | ||
506 | struct elf_segment_t *seg = params->first_segment; | ||
507 | while(seg) | ||
508 | { | ||
509 | if(seg->vaddr <= addr && addr < seg->vaddr + seg->vsize) | ||
510 | return addr - seg->vaddr + seg->paddr; | ||
511 | seg = seg->next; | ||
512 | } | ||
513 | return addr; | ||
514 | } | ||
515 | |||
516 | void elf_translate_addresses(struct elf_params_t *params) | ||
517 | { | ||
518 | struct elf_section_t *sec = params->first_section; | ||
519 | while(sec) | ||
520 | { | ||
521 | sec->addr = elf_translate_virtual_address(params, sec->addr); | ||
522 | sec = sec->next; | ||
523 | } | ||
524 | params->start_addr = elf_translate_virtual_address(params, params->start_addr); | ||
525 | } | ||
526 | |||
527 | bool elf_is_empty(struct elf_params_t *params) | ||
528 | { | ||
529 | return params->first_section == NULL; | ||
530 | } | ||
531 | |||
532 | void elf_set_start_addr(struct elf_params_t *params, uint32_t addr) | ||
533 | { | ||
534 | params->has_start_addr = true; | ||
535 | params->start_addr = addr; | ||
536 | } | ||
537 | |||
538 | bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr) | ||
539 | { | ||
540 | if(params->has_start_addr && addr != NULL) | ||
541 | *addr = params->start_addr; | ||
542 | return params->has_start_addr; | ||
543 | } | ||
544 | |||
545 | int elf_get_nr_sections(struct elf_params_t *params) | ||
546 | { | ||
547 | int nr = 0; | ||
548 | struct elf_section_t *sec = params->first_section; | ||
549 | while(sec) | ||
550 | { | ||
551 | nr++; | ||
552 | sec = sec->next; | ||
553 | } | ||
554 | return nr; | ||
555 | } | ||
556 | |||
557 | void elf_release(struct elf_params_t *params) | ||
558 | { | ||
559 | struct elf_section_t *sec = params->first_section; | ||
560 | while(sec) | ||
561 | { | ||
562 | struct elf_section_t *next_sec = sec->next; | ||
563 | if(sec->type == EST_LOAD) | ||
564 | free(sec->section); | ||
565 | free(sec); | ||
566 | sec = next_sec; | ||
567 | } | ||
568 | struct elf_segment_t *seg = params->first_segment; | ||
569 | while(seg) | ||
570 | { | ||
571 | struct elf_segment_t *next_seg = seg->next; | ||
572 | free(seg); | ||
573 | seg = next_seg; | ||
574 | } | ||
575 | } | ||