1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2011 Amaury Pouly
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
26 * taken from elf.h linux header
27 * based on ELF specification
28 * based on ARM ELF specification
30 typedef uint16_t Elf32_Half
;
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
;
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 */
58 #define EI_MAG0 0 /* File identification byte 0 index */
59 #define ELFMAG0 0x7f /* Magic number byte 0 */
61 #define EI_MAG1 1 /* File identification byte 1 index */
62 #define ELFMAG1 'E' /* Magic number byte 1 */
64 #define EI_MAG2 2 /* File identification byte 2 index */
65 #define ELFMAG2 'L' /* Magic number byte 2 */
67 #define EI_MAG3 3 /* File identification byte 3 index */
68 #define ELFMAG3 'F' /* Magic number byte 3 */
70 #define EI_CLASS 4 /* File class byte index */
71 #define ELFCLASS32 1 /* 32-bit objects */
73 #define EI_DATA 5 /* Data encoding byte index */
74 #define ELFDATA2LSB 1 /* 2's complement, little endian */
76 #define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */
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 */
83 #define EI_ABIVERSION 8 /* ABI version */
85 #define EI_PAD 9 /* Byte index of padding bytes */
87 #define ET_EXEC 2 /* Executable file */
89 #define EM_ARM 40 /* ARM */
91 #define EV_CURRENT 1 /* Current version */
93 #define EF_ARM_HASENTRY 0x00000002
95 #define SHN_UNDEF 0 /* Undefined section */
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 */
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. */
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 */
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 */
148 #define PT_LOAD 1 /* Loadable program segment */
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 */
154 void elf_init(struct elf_params_t
*params
)
156 memset(params
, 0, sizeof(struct elf_params_t
));
159 extern void *xmalloc(size_t s
);
161 static struct elf_section_t
*elf_add_section(struct elf_params_t
*params
)
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
;
168 params
->last_section
->next
= sec
;
169 params
->last_section
= sec
;
176 static struct elf_segment_t
*elf_add_segment(struct elf_params_t
*params
)
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
;
183 params
->last_segment
->next
= seg
;
184 params
->last_segment
= seg
;
191 void elf_add_load_section(struct elf_params_t
*params
,
192 uint32_t load_addr
, uint32_t size
, const void *section
)
194 struct elf_section_t
*sec
= elf_add_section(params
);
196 sec
->type
= EST_LOAD
;
197 sec
->addr
= load_addr
;
199 sec
->section
= xmalloc(size
);
200 memcpy(sec
->section
, section
, size
);
203 void elf_add_fill_section(struct elf_params_t
*params
,
204 uint32_t fill_addr
, uint32_t size
, uint32_t pattern
)
208 printf("oops, non-zero filling, ignore fill section\n");
212 struct elf_section_t
*sec
= elf_add_section(params
);
214 sec
->type
= EST_FILL
;
215 sec
->addr
= fill_addr
;
217 sec
->pattern
= pattern
;
220 void elf_write_file(struct elf_params_t
*params
, elf_write_fn_t write
,
221 elf_printf_fn_t printf
, void *user
)
227 struct elf_section_t
*sec
= params
->first_section
;
231 memset(&ehdr
, 0, EI_NIDENT
);
235 if(sec
->type
== EST_LOAD
)
237 sec
->offset
= offset
;
249 uint32_t strtbl_offset
= offset
;
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
;
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
;
276 write(user
, 0, &ehdr
, sizeof ehdr
);
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));
285 strtbl_content
[0] = '\0';
286 strcpy(&strtbl_content
[1], ".shstrtab");
287 uint32_t strtbl_index
= 1 + strlen(".shstrtab") + 1;
289 uint32_t data_offset
= ehdr
.e_ehsize
+ ehdr
.e_phnum
* ehdr
.e_phentsize
+
290 ehdr
.e_shnum
* ehdr
.e_shentsize
;
292 sec
= params
->first_section
;
293 offset
= ehdr
.e_phoff
;
296 sec
->offset
+= data_offset
;
298 phdr
.p_type
= PT_LOAD
;
299 if(sec
->type
== EST_LOAD
)
300 phdr
.p_offset
= sec
->offset
;
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
;
310 phdr
.p_flags
= PF_X
| PF_W
| PF_R
;
313 write(user
, offset
, &phdr
, sizeof phdr
);
315 offset
+= sizeof(Elf32_Phdr
);
319 sec
= params
->first_section
;
320 offset
= ehdr
.e_shoff
;
324 shdr
.sh_type
= SHT_NULL
;
329 shdr
.sh_link
= SHN_UNDEF
;
331 shdr
.sh_addralign
= 0;
334 write(user
, offset
, &shdr
, sizeof shdr
);
336 offset
+= sizeof(Elf32_Shdr
);
339 uint32_t text_idx
= 0;
340 uint32_t bss_idx
= 0;
343 shdr
.sh_name
= strtbl_index
;
344 if(sec
->type
== EST_LOAD
)
346 strtbl_index
+= 1 + sprintf(&strtbl_content
[strtbl_index
], ".text%d", text_idx
++);
347 shdr
.sh_type
= SHT_PROGBITS
;
351 strtbl_index
+= 1 + sprintf(&strtbl_content
[strtbl_index
], ".bss%d", bss_idx
++);
352 shdr
.sh_type
= SHT_NOBITS
;
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
;
360 shdr
.sh_addralign
= 1;
363 write(user
, offset
, &shdr
, sizeof shdr
);
365 offset
+= sizeof(Elf32_Shdr
);
371 shdr
.sh_type
= SHT_STRTAB
;
374 shdr
.sh_offset
= strtbl_offset
+ data_offset
;
375 shdr
.sh_size
= strtbl_index
;
376 shdr
.sh_link
= SHN_UNDEF
;
378 shdr
.sh_addralign
= 1;
381 write(user
, offset
, &shdr
, sizeof shdr
);
383 offset
+= sizeof(Elf32_Shdr
);
386 sec
= params
->first_section
;
389 if(sec
->type
== EST_LOAD
)
390 write(user
, sec
->offset
, sec
->section
, sec
->size
);
394 write(user
, strtbl_offset
+ data_offset
, strtbl_content
, strtbl_index
);
395 free(strtbl_content
);
398 bool elf_read_file(struct elf_params_t
*params
, elf_read_fn_t read
,
399 elf_printf_fn_t printf
, void *user
)
401 #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;})
405 if(!read(user
, 0, &ehdr
, sizeof(ehdr
)))
407 printf(user
, true, "error reading elf header\n");
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
);
433 if(ehdr
.e_shstrndx
!= SHN_UNDEF
)
436 if(read(user
, ehdr
.e_shoff
+ ehdr
.e_shstrndx
* ehdr
.e_shentsize
,
437 &shstrtab
, sizeof(shstrtab
)))
439 strtab
= xmalloc(shstrtab
.sh_size
);
440 if(!read(user
, shstrtab
.sh_offset
, strtab
, shstrtab
.sh_size
))
447 /* run through sections */
448 printf(user
, false, "ELF file:\n");
449 for(int i
= 1; i
< ehdr
.e_shnum
; i
++)
451 uint32_t off
= ehdr
.e_shoff
+ i
* ehdr
.e_shentsize
;
453 memset(&shdr
, 0, sizeof(shdr
));
454 if(!read(user
, off
, &shdr
, sizeof(shdr
)))
455 error_printf("error reading elf section header");
457 if(shdr
.sh_type
== SHT_PROGBITS
&& shdr
.sh_flags
& SHF_ALLOC
)
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
);
466 printf(user
, false, "create load segment for %s\n", &strtab
[shdr
.sh_name
]);
468 else if(shdr
.sh_type
== SHT_NOBITS
&& shdr
.sh_flags
& SHF_ALLOC
)
470 elf_add_fill_section(params
, shdr
.sh_addr
, shdr
.sh_size
, 0);
472 printf(user
, false, "create fill segment for %s\n", &strtab
[shdr
.sh_name
]);
477 printf(user
, false, "filter out %s\n", &strtab
[shdr
.sh_name
], shdr
.sh_type
);
482 /* run through segments */
483 for(int i
= 1; i
< ehdr
.e_phnum
; i
++)
485 uint32_t off
= ehdr
.e_phoff
+ i
* ehdr
.e_phentsize
;
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
)
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
);
504 uint32_t elf_translate_virtual_address(struct elf_params_t
*params
, uint32_t addr
)
506 struct elf_segment_t
*seg
= params
->first_segment
;
509 if(seg
->vaddr
<= addr
&& addr
< seg
->vaddr
+ seg
->vsize
)
510 return addr
- seg
->vaddr
+ seg
->paddr
;
516 void elf_translate_addresses(struct elf_params_t
*params
)
518 struct elf_section_t
*sec
= params
->first_section
;
521 sec
->addr
= elf_translate_virtual_address(params
, sec
->addr
);
524 params
->start_addr
= elf_translate_virtual_address(params
, params
->start_addr
);
527 bool elf_is_empty(struct elf_params_t
*params
)
529 return params
->first_section
== NULL
;
532 void elf_set_start_addr(struct elf_params_t
*params
, uint32_t addr
)
534 params
->has_start_addr
= true;
535 params
->start_addr
= addr
;
538 bool elf_get_start_addr(struct elf_params_t
*params
, uint32_t *addr
)
540 if(params
->has_start_addr
&& addr
!= NULL
)
541 *addr
= params
->start_addr
;
542 return params
->has_start_addr
;
545 int elf_get_nr_sections(struct elf_params_t
*params
)
548 struct elf_section_t
*sec
= params
->first_section
;
557 void elf_release(struct elf_params_t
*params
)
559 struct elf_section_t
*sec
= params
->first_section
;
562 struct elf_section_t
*next_sec
= sec
->next
;
563 if(sec
->type
== EST_LOAD
)
568 struct elf_segment_t
*seg
= params
->first_segment
;
571 struct elf_segment_t
*next_seg
= seg
->next
;