5 * taken from elf.h linux header
6 * based on ELF specification
7 * based on ARM ELF specification
9 typedef uint16_t Elf32_Half
;
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
;
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 */
37 #define EI_MAG0 0 /* File identification byte 0 index */
38 #define ELFMAG0 0x7f /* Magic number byte 0 */
40 #define EI_MAG1 1 /* File identification byte 1 index */
41 #define ELFMAG1 'E' /* Magic number byte 1 */
43 #define EI_MAG2 2 /* File identification byte 2 index */
44 #define ELFMAG2 'L' /* Magic number byte 2 */
46 #define EI_MAG3 3 /* File identification byte 3 index */
47 #define ELFMAG3 'F' /* Magic number byte 3 */
49 #define EI_CLASS 4 /* File class byte index */
50 #define ELFCLASS32 1 /* 32-bit objects */
52 #define EI_DATA 5 /* Data encoding byte index */
53 #define ELFDATA2LSB 1 /* 2's complement, little endian */
55 #define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */
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 */
62 #define EI_ABIVERSION 8 /* ABI version */
64 #define EI_PAD 9 /* Byte index of padding bytes */
66 #define ET_EXEC 2 /* Executable file */
68 #define EM_ARM 40 /* ARM */
70 #define EV_CURRENT 1 /* Current version */
72 #define EF_ARM_HASENTRY 0x00000002
74 #define SHN_UNDEF 0 /* Undefined section */
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 */
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. */
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 */
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 */
127 #define PT_LOAD 1 /* Loadable program segment */
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 */
133 void elf_init(struct elf_params_t
*params
)
135 params
->has_start_addr
= false;
136 params
->start_addr
= 0;
137 params
->first_section
= NULL
;
138 params
->last_section
= NULL
;
141 extern void *xmalloc(size_t s
);
143 static struct elf_section_t
*elf_add_section(struct elf_params_t
*params
)
145 struct elf_section_t
*sec
= xmalloc(sizeof(struct elf_section_t
));
146 if(params
->first_section
== NULL
)
147 params
->first_section
= params
->last_section
= sec
;
150 params
->last_section
->next
= sec
;
151 params
->last_section
= sec
;
158 void elf_add_load_section(struct elf_params_t
*params
,
159 uint32_t load_addr
, uint32_t size
, const void *section
)
161 struct elf_section_t
*sec
= elf_add_section(params
);
163 sec
->type
= EST_LOAD
;
164 sec
->addr
= load_addr
;
166 sec
->section
= xmalloc(size
);
167 memcpy(sec
->section
, section
, size
);
170 void elf_add_fill_section(struct elf_params_t
*params
,
171 uint32_t fill_addr
, uint32_t size
, uint32_t pattern
)
175 printf("oops, non-zero filling, ignore fill section\n");
179 struct elf_section_t
*sec
= elf_add_section(params
);
181 sec
->type
= EST_FILL
;
182 sec
->addr
= fill_addr
;
184 sec
->pattern
= pattern
;
187 void elf_write_file(struct elf_params_t
*params
, elf_write_fn_t write
, void *user
)
191 struct elf_section_t
*sec
= params
->first_section
;
195 memset(&ehdr
, 0, EI_NIDENT
);
199 if(sec
->type
== EST_LOAD
)
201 sec
->offset
= offset
;
209 uint32_t strtbl_offset
= offset
;
211 ehdr
.e_ident
[EI_MAG0
] = ELFMAG0
;
212 ehdr
.e_ident
[EI_MAG1
] = ELFMAG1
;
213 ehdr
.e_ident
[EI_MAG2
] = ELFMAG2
;
214 ehdr
.e_ident
[EI_MAG3
] = ELFMAG3
;
215 ehdr
.e_ident
[EI_CLASS
] = ELFCLASS32
;
216 ehdr
.e_ident
[EI_DATA
] = ELFDATA2LSB
;
217 ehdr
.e_ident
[EI_VERSION
] = EV_CURRENT
;
218 ehdr
.e_ident
[EI_OSABI
] = ELFOSABI_NONE
;
219 ehdr
.e_ident
[EI_ABIVERSION
] = 0;
220 ehdr
.e_type
= ET_EXEC
;
221 ehdr
.e_machine
= EM_ARM
;
222 ehdr
.e_version
= EV_CURRENT
;
223 ehdr
.e_entry
= params
->start_addr
;
225 if(params
->has_start_addr
)
226 ehdr
.e_flags
|= EF_ARM_HASENTRY
;
227 ehdr
.e_ehsize
= sizeof ehdr
;
228 ehdr
.e_phentsize
= sizeof phdr
;
229 ehdr
.e_phnum
= phnum
;
230 ehdr
.e_shentsize
= sizeof shdr
;
231 ehdr
.e_shnum
= phnum
+ 2; /* one for section 0 and one for string table */
232 ehdr
.e_shstrndx
= ehdr
.e_shnum
- 1;
233 ehdr
.e_phoff
= ehdr
.e_ehsize
;
234 ehdr
.e_shoff
= ehdr
.e_ehsize
+ ehdr
.e_phnum
* ehdr
.e_phentsize
;
236 write(user
, 0, &ehdr
, sizeof ehdr
);
238 /* allocate enough size to hold any combinaison of .text/.bss in the string table:
239 * - one empty name ("\0")
240 * - at most N names of the form ".textXX\0" or ".bssXX\0"
241 * - one name ".shstrtab\0" */
242 char *strtbl_content
= malloc(1 + strlen(".shstrtab") + 1 +
243 phnum
* (strlen(".textXX") + 1));
245 strtbl_content
[0] = '\0';
246 strcpy(&strtbl_content
[1], ".shstrtab");
247 uint32_t strtbl_index
= 1 + strlen(".shstrtab") + 1;
249 uint32_t data_offset
= ehdr
.e_ehsize
+ ehdr
.e_phnum
* ehdr
.e_phentsize
+
250 ehdr
.e_shnum
* ehdr
.e_shentsize
;
252 sec
= params
->first_section
;
253 offset
= ehdr
.e_phoff
;
256 sec
->offset
+= data_offset
;
258 phdr
.p_type
= PT_LOAD
;
259 if(sec
->type
== EST_LOAD
)
260 phdr
.p_offset
= sec
->offset
;
263 phdr
.p_paddr
= sec
->addr
;
264 phdr
.p_vaddr
= phdr
.p_paddr
; /* assume identity map ? */
265 phdr
.p_memsz
= sec
->size
;
266 if(sec
->type
== EST_LOAD
)
267 phdr
.p_filesz
= phdr
.p_memsz
;
270 phdr
.p_flags
= PF_X
| PF_W
| PF_R
;
273 write(user
, offset
, &phdr
, sizeof phdr
);
275 offset
+= sizeof(Elf32_Phdr
);
279 sec
= params
->first_section
;
280 offset
= ehdr
.e_shoff
;
284 shdr
.sh_type
= SHT_NULL
;
289 shdr
.sh_link
= SHN_UNDEF
;
291 shdr
.sh_addralign
= 0;
294 write(user
, offset
, &shdr
, sizeof shdr
);
296 offset
+= sizeof(Elf32_Shdr
);
299 uint32_t text_idx
= 0;
300 uint32_t bss_idx
= 0;
303 shdr
.sh_name
= strtbl_index
;
304 if(sec
->type
== EST_LOAD
)
306 strtbl_index
+= 1 + sprintf(&strtbl_content
[strtbl_index
], ".text%d", text_idx
++);
307 shdr
.sh_type
= SHT_PROGBITS
;
311 strtbl_index
+= 1 + sprintf(&strtbl_content
[strtbl_index
], ".bss%d", bss_idx
++);
312 shdr
.sh_type
= SHT_NOBITS
;
314 shdr
.sh_flags
= SHF_ALLOC
| SHF_EXECINSTR
;
315 shdr
.sh_addr
= sec
->addr
;
316 shdr
.sh_offset
= sec
->offset
;
317 shdr
.sh_size
= sec
->size
;
318 shdr
.sh_link
= SHN_UNDEF
;
320 shdr
.sh_addralign
= 1;
323 write(user
, offset
, &shdr
, sizeof shdr
);
325 offset
+= sizeof(Elf32_Shdr
);
331 shdr
.sh_type
= SHT_STRTAB
;
334 shdr
.sh_offset
= strtbl_offset
+ data_offset
;
335 shdr
.sh_size
= strtbl_index
;
336 shdr
.sh_link
= SHN_UNDEF
;
338 shdr
.sh_addralign
= 1;
341 write(user
, offset
, &shdr
, sizeof shdr
);
343 offset
+= sizeof(Elf32_Shdr
);
346 sec
= params
->first_section
;
349 if(sec
->type
== EST_LOAD
)
350 write(user
, sec
->offset
, sec
->section
, sec
->size
);
354 write(user
, strtbl_offset
+ data_offset
, strtbl_content
, strtbl_index
);
355 free(strtbl_content
);
358 bool elf_read_file(struct elf_params_t
*params
, elf_read_fn_t read
,
359 elf_printf_fn_t printf
, void *user
)
361 #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;})
365 if(!read(user
, 0, &ehdr
, sizeof(ehdr
)))
367 printf(user
, true, "error reading elf header\n");
371 if(ehdr
.e_ident
[EI_MAG0
] != ELFMAG0
|| ehdr
.e_ident
[EI_MAG1
] != ELFMAG1
||
372 ehdr
.e_ident
[EI_MAG2
] != ELFMAG2
|| ehdr
.e_ident
[EI_MAG3
] != ELFMAG3
)
373 error_printf("invalid elf header\n");
374 if(ehdr
.e_ident
[EI_CLASS
] != ELFCLASS32
)
375 error_printf("invalid elf class: must be a 32-bit object\n");
376 if(ehdr
.e_ident
[EI_DATA
] != ELFDATA2LSB
)
377 error_printf("invalid elf data encoding: must be 32-bit lsb\n");
378 if(ehdr
.e_ident
[EI_VERSION
] != EV_CURRENT
)
379 error_printf("invalid elf version\n");
380 if(ehdr
.e_type
!= ET_EXEC
)
381 error_printf("invalid elf file: must be an executable file\n");
382 if(ehdr
.e_machine
!= EM_ARM
)
383 error_printf("invalid elf file: must target an arm machine\n");
384 if(ehdr
.e_ehsize
!= sizeof(ehdr
))
385 error_printf("invalid elf file: size header mismatch\n");
386 if(ehdr
.e_phnum
> 0 && ehdr
.e_phentsize
!= sizeof(Elf32_Phdr
))
387 error_printf("invalid elf file: program header size mismatch\n");
388 if(ehdr
.e_shnum
> 0 && ehdr
.e_shentsize
!= sizeof(Elf32_Shdr
))
389 error_printf("invalid elf file: section header size mismatch\n");
390 elf_set_start_addr(params
, ehdr
.e_entry
);
393 if(ehdr
.e_shstrndx
!= SHN_UNDEF
)
396 if(read(user
, ehdr
.e_shoff
+ ehdr
.e_shstrndx
* ehdr
.e_shentsize
,
397 &shstrtab
, sizeof(shstrtab
)))
399 strtab
= xmalloc(shstrtab
.sh_size
);
400 if(!read(user
, shstrtab
.sh_offset
, strtab
, shstrtab
.sh_size
))
407 /* run through sections */
408 printf(user
, false, "ELF file:\n");
409 for(int i
= 1; i
< ehdr
.e_shnum
; i
++)
411 uint32_t off
= ehdr
.e_shoff
+ i
* ehdr
.e_shentsize
;
413 memset(&shdr
, 0, sizeof(shdr
));
414 if(!read(user
, off
, &shdr
, sizeof(shdr
)))
415 error_printf("error reading elf section header");
417 if(shdr
.sh_type
== SHT_PROGBITS
&& shdr
.sh_flags
& SHF_ALLOC
)
419 void *data
= xmalloc(shdr
.sh_size
);
420 if(!read(user
, shdr
.sh_offset
, data
, shdr
.sh_size
))
421 error_printf("error read self section data\n");
422 elf_add_load_section(params
, shdr
.sh_addr
, shdr
.sh_size
, data
);
425 printf(user
, false, "create load segment for %s\n", &strtab
[shdr
.sh_name
]);
427 else if(shdr
.sh_type
== SHT_NOBITS
&& shdr
.sh_flags
& SHF_ALLOC
)
429 elf_add_fill_section(params
, shdr
.sh_addr
, shdr
.sh_size
, 0);
431 printf(user
, false, "create fill segment for %s\n", &strtab
[shdr
.sh_name
]);
436 printf(user
, false, "filter out %s\n", &strtab
[shdr
.sh_name
], shdr
.sh_type
);
443 bool elf_is_empty(struct elf_params_t
*params
)
445 return params
->first_section
== NULL
;
448 void elf_set_start_addr(struct elf_params_t
*params
, uint32_t addr
)
450 params
->has_start_addr
= true;
451 params
->start_addr
= addr
;
454 bool elf_get_start_addr(struct elf_params_t
*params
, uint32_t *addr
)
456 if(params
->has_start_addr
&& addr
!= NULL
)
457 *addr
= params
->start_addr
;
458 return params
->has_start_addr
;
461 int elf_get_nr_sections(struct elf_params_t
*params
)
464 struct elf_section_t
*sec
= params
->first_section
;
473 void elf_release(struct elf_params_t
*params
)
475 struct elf_section_t
*sec
, *next_sec
;
476 sec
= params
->first_section
;
479 next_sec
= sec
->next
;
480 if(sec
->type
== EST_LOAD
)
485 params
->first_section
= NULL
;
486 params
->last_section
= NULL
;