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 /* sort by increasing type and then increasing address */
221 static int elf_simplify_compare(const void *a
, const void *b
)
223 const struct elf_section_t
*sa
= a
;
224 const struct elf_section_t
*sb
= b
;
225 if(sa
->type
!= sb
->type
)
226 return sa
->type
- sb
->type
;
227 return sa
->addr
- sb
->addr
;
230 void elf_simplify(struct elf_params_t
*params
)
232 /** find all sections of the same types which are contiguous and merge them */
236 struct elf_section_t
*cur_sec
= params
->first_section
;
240 cur_sec
= cur_sec
->next
;
243 /* put all sections in an array and free list */
244 struct elf_section_t
*sections
= malloc(sizeof(struct elf_section_t
) * nr_sections
);
245 cur_sec
= params
->first_section
;
246 for(int i
= 0; i
< nr_sections
; i
++)
248 memcpy(§ions
[i
], cur_sec
, sizeof(struct elf_section_t
));
249 struct elf_section_t
*old
= cur_sec
;
250 cur_sec
= cur_sec
->next
;
254 /* sort them by type and increasing addresses */
255 qsort(sections
, nr_sections
, sizeof(struct elf_section_t
), &elf_simplify_compare
);
258 cur_sec
= §ions
[0];
259 for(int i
= 1; i
< nr_sections
; i
++)
261 /* different type => no */
262 if(sections
[i
].type
!= cur_sec
->type
)
264 /* (for fill) different pattern => no */
265 if(sections
[i
].type
== EST_FILL
&& sections
[i
].pattern
!= cur_sec
->pattern
)
267 /* not contiguous => no */
268 if(sections
[i
].addr
!= cur_sec
->addr
+ cur_sec
->size
)
271 if(sections
[i
].type
== EST_FILL
)
273 cur_sec
->size
+= sections
[i
].size
;
274 sections
[i
].size
= 0; // will be ignored by rebuilding (see below)
276 else if(sections
[i
].type
== EST_LOAD
)
279 void *data
= malloc(cur_sec
->size
+ sections
[i
].size
);
280 memcpy(data
, cur_sec
->section
, cur_sec
->size
);
281 memcpy(data
+ cur_sec
->size
, sections
[i
].section
, sections
[i
].size
);
282 free(cur_sec
->section
);
283 free(sections
[i
].section
);
284 cur_sec
->section
= data
;
285 cur_sec
->size
+= sections
[i
].size
;
286 sections
[i
].size
= 0; // will be ignored by rebuilding (see below)
290 /* update current section to consider */
292 cur_sec
= §ions
[i
];
295 /* put back on a list and free array */
296 struct elf_section_t
**prev_ptr
= ¶ms
->first_section
;
297 struct elf_section_t
*prev_sec
= NULL
;
298 for(int i
= 0; i
< nr_sections
; i
++)
300 /* skip empty sections produced by simplification */
301 if(sections
[i
].size
== 0)
304 struct elf_section_t
*sec
= malloc(sizeof(struct elf_section_t
));
305 memcpy(sec
, §ions
[i
], sizeof(struct elf_section_t
));
307 prev_ptr
= &sec
->next
;
311 params
->last_section
= prev_sec
;
315 /* sort by increasing address */
316 static int elf_addr_compare(const void *a
, const void *b
)
318 const struct elf_section_t
*sa
= a
;
319 const struct elf_section_t
*sb
= b
;
320 return sa
->addr
- sb
->addr
;
323 void elf_sort_by_address(struct elf_params_t
*params
)
325 /** sort sections by address */
329 struct elf_section_t
*cur_sec
= params
->first_section
;
333 cur_sec
= cur_sec
->next
;
336 /* put all sections in an array and free list */
337 struct elf_section_t
*sections
= malloc(sizeof(struct elf_section_t
) * nr_sections
);
338 cur_sec
= params
->first_section
;
339 for(int i
= 0; i
< nr_sections
; i
++)
341 memcpy(§ions
[i
], cur_sec
, sizeof(struct elf_section_t
));
342 struct elf_section_t
*old
= cur_sec
;
343 cur_sec
= cur_sec
->next
;
347 /* sort them by type and increasing addresses */
348 qsort(sections
, nr_sections
, sizeof(struct elf_section_t
), &elf_addr_compare
);
350 /* put back on a list and free array */
351 struct elf_section_t
**prev_ptr
= ¶ms
->first_section
;
352 struct elf_section_t
*prev_sec
= NULL
;
353 for(int i
= 0; i
< nr_sections
; i
++)
355 /* skip empty sections produced by simplification */
356 if(sections
[i
].size
== 0)
359 struct elf_section_t
*sec
= malloc(sizeof(struct elf_section_t
));
360 memcpy(sec
, §ions
[i
], sizeof(struct elf_section_t
));
362 prev_ptr
= &sec
->next
;
366 params
->last_section
= prev_sec
;
370 void elf_write_file(struct elf_params_t
*params
, elf_write_fn_t write
,
371 elf_printf_fn_t printf
, void *user
)
377 struct elf_section_t
*sec
= params
->first_section
;
381 memset(&ehdr
, 0, EI_NIDENT
);
385 if(sec
->type
== EST_LOAD
)
387 sec
->offset
= offset
;
399 uint32_t strtbl_offset
= offset
;
401 ehdr
.e_ident
[EI_MAG0
] = ELFMAG0
;
402 ehdr
.e_ident
[EI_MAG1
] = ELFMAG1
;
403 ehdr
.e_ident
[EI_MAG2
] = ELFMAG2
;
404 ehdr
.e_ident
[EI_MAG3
] = ELFMAG3
;
405 ehdr
.e_ident
[EI_CLASS
] = ELFCLASS32
;
406 ehdr
.e_ident
[EI_DATA
] = ELFDATA2LSB
;
407 ehdr
.e_ident
[EI_VERSION
] = EV_CURRENT
;
408 ehdr
.e_ident
[EI_OSABI
] = ELFOSABI_NONE
;
409 ehdr
.e_ident
[EI_ABIVERSION
] = 0;
410 ehdr
.e_type
= ET_EXEC
;
411 ehdr
.e_machine
= EM_ARM
;
412 ehdr
.e_version
= EV_CURRENT
;
413 ehdr
.e_entry
= params
->start_addr
;
415 if(params
->has_start_addr
)
416 ehdr
.e_flags
|= EF_ARM_HASENTRY
;
417 ehdr
.e_ehsize
= sizeof ehdr
;
418 ehdr
.e_phentsize
= sizeof phdr
;
419 ehdr
.e_phnum
= phnum
;
420 ehdr
.e_shentsize
= sizeof shdr
;
421 ehdr
.e_shnum
= phnum
+ 2; /* one for section 0 and one for string table */
422 ehdr
.e_shstrndx
= ehdr
.e_shnum
- 1;
423 ehdr
.e_phoff
= ehdr
.e_ehsize
;
424 ehdr
.e_shoff
= ehdr
.e_ehsize
+ ehdr
.e_phnum
* ehdr
.e_phentsize
;
426 write(user
, 0, &ehdr
, sizeof ehdr
);
428 /* allocate enough size to hold any combinaison of .text/.bss in the string table:
429 * - one empty name ("\0")
430 * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0"
431 * - one name ".shstrtab\0" */
432 char *strtbl_content
= malloc(1 + strlen(".shstrtab") + 1 +
433 phnum
* (strlen(".textXXXX") + 1));
435 strtbl_content
[0] = '\0';
436 strcpy(&strtbl_content
[1], ".shstrtab");
437 uint32_t strtbl_index
= 1 + strlen(".shstrtab") + 1;
439 uint32_t data_offset
= ehdr
.e_ehsize
+ ehdr
.e_phnum
* ehdr
.e_phentsize
+
440 ehdr
.e_shnum
* ehdr
.e_shentsize
;
442 sec
= params
->first_section
;
443 offset
= ehdr
.e_phoff
;
446 sec
->offset
+= data_offset
;
448 phdr
.p_type
= PT_LOAD
;
449 if(sec
->type
== EST_LOAD
)
450 phdr
.p_offset
= sec
->offset
;
453 phdr
.p_paddr
= sec
->addr
;
454 phdr
.p_vaddr
= phdr
.p_paddr
; /* assume identity map ? */
455 phdr
.p_memsz
= sec
->size
;
456 if(sec
->type
== EST_LOAD
)
457 phdr
.p_filesz
= phdr
.p_memsz
;
460 phdr
.p_flags
= PF_X
| PF_W
| PF_R
;
463 write(user
, offset
, &phdr
, sizeof phdr
);
465 offset
+= sizeof(Elf32_Phdr
);
469 sec
= params
->first_section
;
470 offset
= ehdr
.e_shoff
;
474 shdr
.sh_type
= SHT_NULL
;
479 shdr
.sh_link
= SHN_UNDEF
;
481 shdr
.sh_addralign
= 0;
484 write(user
, offset
, &shdr
, sizeof shdr
);
486 offset
+= sizeof(Elf32_Shdr
);
489 uint32_t text_idx
= 0;
490 uint32_t bss_idx
= 0;
493 shdr
.sh_name
= strtbl_index
;
494 if(sec
->type
== EST_LOAD
)
496 strtbl_index
+= 1 + sprintf(&strtbl_content
[strtbl_index
], ".text%d", text_idx
++);
497 shdr
.sh_type
= SHT_PROGBITS
;
501 strtbl_index
+= 1 + sprintf(&strtbl_content
[strtbl_index
], ".bss%d", bss_idx
++);
502 shdr
.sh_type
= SHT_NOBITS
;
504 shdr
.sh_flags
= SHF_ALLOC
| SHF_EXECINSTR
;
505 shdr
.sh_addr
= sec
->addr
;
506 shdr
.sh_offset
= sec
->offset
;
507 shdr
.sh_size
= sec
->size
;
508 shdr
.sh_link
= SHN_UNDEF
;
510 shdr
.sh_addralign
= 1;
513 write(user
, offset
, &shdr
, sizeof shdr
);
515 offset
+= sizeof(Elf32_Shdr
);
521 shdr
.sh_type
= SHT_STRTAB
;
524 shdr
.sh_offset
= strtbl_offset
+ data_offset
;
525 shdr
.sh_size
= strtbl_index
;
526 shdr
.sh_link
= SHN_UNDEF
;
528 shdr
.sh_addralign
= 1;
531 write(user
, offset
, &shdr
, sizeof shdr
);
533 offset
+= sizeof(Elf32_Shdr
);
536 sec
= params
->first_section
;
539 if(sec
->type
== EST_LOAD
)
540 write(user
, sec
->offset
, sec
->section
, sec
->size
);
544 write(user
, strtbl_offset
+ data_offset
, strtbl_content
, strtbl_index
);
545 free(strtbl_content
);
548 bool elf_read_file(struct elf_params_t
*params
, elf_read_fn_t read
,
549 elf_printf_fn_t printf
, void *user
)
551 #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;})
555 if(!read(user
, 0, &ehdr
, sizeof(ehdr
)))
557 printf(user
, true, "error reading elf header\n");
561 if(ehdr
.e_ident
[EI_MAG0
] != ELFMAG0
|| ehdr
.e_ident
[EI_MAG1
] != ELFMAG1
||
562 ehdr
.e_ident
[EI_MAG2
] != ELFMAG2
|| ehdr
.e_ident
[EI_MAG3
] != ELFMAG3
)
563 error_printf("invalid elf header\n");
564 if(ehdr
.e_ident
[EI_CLASS
] != ELFCLASS32
)
565 error_printf("invalid elf class: must be a 32-bit object\n");
566 if(ehdr
.e_ident
[EI_DATA
] != ELFDATA2LSB
)
567 error_printf("invalid elf data encoding: must be 32-bit lsb\n");
568 if(ehdr
.e_ident
[EI_VERSION
] != EV_CURRENT
)
569 error_printf("invalid elf version\n");
570 if(ehdr
.e_type
!= ET_EXEC
)
571 error_printf("invalid elf file: must be an executable file\n");
572 if(ehdr
.e_machine
!= EM_ARM
)
573 error_printf("invalid elf file: must target an arm machine\n");
574 if(ehdr
.e_ehsize
!= sizeof(ehdr
))
575 error_printf("invalid elf file: size header mismatch\n");
576 if(ehdr
.e_phnum
> 0 && ehdr
.e_phentsize
!= sizeof(Elf32_Phdr
))
577 error_printf("invalid elf file: program header size mismatch\n");
578 if(ehdr
.e_shnum
> 0 && ehdr
.e_shentsize
!= sizeof(Elf32_Shdr
))
579 error_printf("invalid elf file: section header size mismatch\n");
580 elf_set_start_addr(params
, ehdr
.e_entry
);
583 if(ehdr
.e_shstrndx
!= SHN_UNDEF
)
586 if(read(user
, ehdr
.e_shoff
+ ehdr
.e_shstrndx
* ehdr
.e_shentsize
,
587 &shstrtab
, sizeof(shstrtab
)))
589 strtab
= xmalloc(shstrtab
.sh_size
);
590 if(!read(user
, shstrtab
.sh_offset
, strtab
, shstrtab
.sh_size
))
597 /* run through sections */
598 printf(user
, false, "ELF file:\n");
599 for(int i
= 1; i
< ehdr
.e_shnum
; i
++)
601 uint32_t off
= ehdr
.e_shoff
+ i
* ehdr
.e_shentsize
;
603 memset(&shdr
, 0, sizeof(shdr
));
604 if(!read(user
, off
, &shdr
, sizeof(shdr
)))
605 error_printf("error reading elf section header");
607 if(shdr
.sh_type
== SHT_PROGBITS
&& shdr
.sh_flags
& SHF_ALLOC
)
609 void *data
= xmalloc(shdr
.sh_size
);
610 if(!read(user
, shdr
.sh_offset
, data
, shdr
.sh_size
))
611 error_printf("error read self section data\n");
612 elf_add_load_section(params
, shdr
.sh_addr
, shdr
.sh_size
, data
);
616 printf(user
, false, "create load segment for %s\n", &strtab
[shdr
.sh_name
]);
618 else if(shdr
.sh_type
== SHT_NOBITS
&& shdr
.sh_flags
& SHF_ALLOC
)
620 elf_add_fill_section(params
, shdr
.sh_addr
, shdr
.sh_size
, 0);
622 printf(user
, false, "create fill segment for %s\n", &strtab
[shdr
.sh_name
]);
627 printf(user
, false, "filter out %s\n", &strtab
[shdr
.sh_name
], shdr
.sh_type
);
632 /* run through segments */
633 for(int i
= 1; i
< ehdr
.e_phnum
; i
++)
635 uint32_t off
= ehdr
.e_phoff
+ i
* ehdr
.e_phentsize
;
637 memset(&phdr
, 0, sizeof(phdr
));
638 if(!read(user
, off
, &phdr
, sizeof(phdr
)))
639 error_printf("error reading elf segment header");
640 if(phdr
.p_type
!= PT_LOAD
)
642 struct elf_segment_t
*seg
= elf_add_segment(params
);
643 seg
->vaddr
= phdr
.p_vaddr
;
644 seg
->paddr
= phdr
.p_paddr
;
645 seg
->vsize
= phdr
.p_memsz
;
646 seg
->psize
= phdr
.p_filesz
;
647 printf(user
, false, "create segment [%#x,+%#x[ -> [%#x,+%#x[\n",
648 seg
->vaddr
, seg
->vsize
, seg
->paddr
, seg
->psize
);
654 uint32_t elf_translate_virtual_address(struct elf_params_t
*params
, uint32_t addr
)
656 struct elf_segment_t
*seg
= params
->first_segment
;
659 if(seg
->vaddr
<= addr
&& addr
< seg
->vaddr
+ seg
->vsize
)
660 return addr
- seg
->vaddr
+ seg
->paddr
;
666 void elf_translate_addresses(struct elf_params_t
*params
)
668 struct elf_section_t
*sec
= params
->first_section
;
671 sec
->addr
= elf_translate_virtual_address(params
, sec
->addr
);
674 params
->start_addr
= elf_translate_virtual_address(params
, params
->start_addr
);
677 bool elf_is_empty(struct elf_params_t
*params
)
679 return params
->first_section
== NULL
;
682 void elf_set_start_addr(struct elf_params_t
*params
, uint32_t addr
)
684 params
->has_start_addr
= true;
685 params
->start_addr
= addr
;
688 bool elf_get_start_addr(struct elf_params_t
*params
, uint32_t *addr
)
690 if(params
->has_start_addr
&& addr
!= NULL
)
691 *addr
= params
->start_addr
;
692 return params
->has_start_addr
;
695 int elf_get_nr_sections(struct elf_params_t
*params
)
698 struct elf_section_t
*sec
= params
->first_section
;
707 void elf_release(struct elf_params_t
*params
)
709 struct elf_section_t
*sec
= params
->first_section
;
712 struct elf_section_t
*next_sec
= sec
->next
;
713 if(sec
->type
== EST_LOAD
)
718 struct elf_segment_t
*seg
= params
->first_segment
;
721 struct elf_segment_t
*next_seg
= seg
->next
;