1 static void glue(bswap_ehdr
, SZ
)(struct elfhdr
*ehdr
)
3 bswap16s(&ehdr
->e_type
); /* Object file type */
4 bswap16s(&ehdr
->e_machine
); /* Architecture */
5 bswap32s(&ehdr
->e_version
); /* Object file version */
6 bswapSZs(&ehdr
->e_entry
); /* Entry point virtual address */
7 bswapSZs(&ehdr
->e_phoff
); /* Program header table file offset */
8 bswapSZs(&ehdr
->e_shoff
); /* Section header table file offset */
9 bswap32s(&ehdr
->e_flags
); /* Processor-specific flags */
10 bswap16s(&ehdr
->e_ehsize
); /* ELF header size in bytes */
11 bswap16s(&ehdr
->e_phentsize
); /* Program header table entry size */
12 bswap16s(&ehdr
->e_phnum
); /* Program header table entry count */
13 bswap16s(&ehdr
->e_shentsize
); /* Section header table entry size */
14 bswap16s(&ehdr
->e_shnum
); /* Section header table entry count */
15 bswap16s(&ehdr
->e_shstrndx
); /* Section header string table index */
18 static void glue(bswap_phdr
, SZ
)(struct elf_phdr
*phdr
)
20 bswap32s(&phdr
->p_type
); /* Segment type */
21 bswapSZs(&phdr
->p_offset
); /* Segment file offset */
22 bswapSZs(&phdr
->p_vaddr
); /* Segment virtual address */
23 bswapSZs(&phdr
->p_paddr
); /* Segment physical address */
24 bswapSZs(&phdr
->p_filesz
); /* Segment size in file */
25 bswapSZs(&phdr
->p_memsz
); /* Segment size in memory */
26 bswap32s(&phdr
->p_flags
); /* Segment flags */
27 bswapSZs(&phdr
->p_align
); /* Segment alignment */
30 static void glue(bswap_shdr
, SZ
)(struct elf_shdr
*shdr
)
32 bswap32s(&shdr
->sh_name
);
33 bswap32s(&shdr
->sh_type
);
34 bswapSZs(&shdr
->sh_flags
);
35 bswapSZs(&shdr
->sh_addr
);
36 bswapSZs(&shdr
->sh_offset
);
37 bswapSZs(&shdr
->sh_size
);
38 bswap32s(&shdr
->sh_link
);
39 bswap32s(&shdr
->sh_info
);
40 bswapSZs(&shdr
->sh_addralign
);
41 bswapSZs(&shdr
->sh_entsize
);
44 static void glue(bswap_sym
, SZ
)(struct elf_sym
*sym
)
46 bswap32s(&sym
->st_name
);
47 bswapSZs(&sym
->st_value
);
48 bswapSZs(&sym
->st_size
);
49 bswap16s(&sym
->st_shndx
);
52 static void glue(bswap_rela
, SZ
)(struct elf_rela
*rela
)
54 bswapSZs(&rela
->r_offset
);
55 bswapSZs(&rela
->r_info
);
56 bswapSZs((elf_word
*)&rela
->r_addend
);
59 static struct elf_shdr
*glue(find_section
, SZ
)(struct elf_shdr
*shdr_table
,
64 if (shdr_table
[i
].sh_type
== type
)
65 return shdr_table
+ i
;
70 static int glue(symfind
, SZ
)(const void *s0
, const void *s1
)
72 hwaddr addr
= *(hwaddr
*)s0
;
73 struct elf_sym
*sym
= (struct elf_sym
*)s1
;
75 if (addr
< sym
->st_value
) {
77 } else if (addr
>= sym
->st_value
+ sym
->st_size
) {
83 static const char *glue(lookup_symbol
, SZ
)(struct syminfo
*s
,
86 struct elf_sym
*syms
= glue(s
->disas_symtab
.elf
, SZ
);
89 sym
= bsearch(&orig_addr
, syms
, s
->disas_num_syms
, sizeof(*syms
),
92 return s
->disas_strtab
+ sym
->st_name
;
98 static int glue(symcmp
, SZ
)(const void *s0
, const void *s1
)
100 struct elf_sym
*sym0
= (struct elf_sym
*)s0
;
101 struct elf_sym
*sym1
= (struct elf_sym
*)s1
;
102 return (sym0
->st_value
< sym1
->st_value
)
104 : ((sym0
->st_value
> sym1
->st_value
) ? 1 : 0);
107 static int glue(load_symbols
, SZ
)(struct elfhdr
*ehdr
, int fd
, int must_swab
,
110 struct elf_shdr
*symtab
, *strtab
, *shdr_table
= NULL
;
111 struct elf_sym
*syms
= NULL
;
116 shdr_table
= load_at(fd
, ehdr
->e_shoff
,
117 sizeof(struct elf_shdr
) * ehdr
->e_shnum
);
122 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
123 glue(bswap_shdr
, SZ
)(shdr_table
+ i
);
127 symtab
= glue(find_section
, SZ
)(shdr_table
, ehdr
->e_shnum
, SHT_SYMTAB
);
130 syms
= load_at(fd
, symtab
->sh_offset
, symtab
->sh_size
);
134 nsyms
= symtab
->sh_size
/ sizeof(struct elf_sym
);
139 glue(bswap_sym
, SZ
)(&syms
[i
]);
140 /* We are only interested in function symbols.
141 Throw everything else away. */
142 if (syms
[i
].st_shndx
== SHN_UNDEF
||
143 syms
[i
].st_shndx
>= SHN_LORESERVE
||
144 ELF_ST_TYPE(syms
[i
].st_info
) != STT_FUNC
) {
147 syms
[i
] = syms
[nsyms
];
152 /* The bottom address bit marks a Thumb or MIPS16 symbol. */
153 syms
[i
].st_value
&= ~(glue(glue(Elf
, SZ
), _Addr
))1;
157 syms
= g_realloc(syms
, nsyms
* sizeof(*syms
));
159 qsort(syms
, nsyms
, sizeof(*syms
), glue(symcmp
, SZ
));
160 for (i
= 0; i
< nsyms
- 1; i
++) {
161 if (syms
[i
].st_size
== 0) {
162 syms
[i
].st_size
= syms
[i
+ 1].st_value
- syms
[i
].st_value
;
167 if (symtab
->sh_link
>= ehdr
->e_shnum
)
169 strtab
= &shdr_table
[symtab
->sh_link
];
171 str
= load_at(fd
, strtab
->sh_offset
, strtab
->sh_size
);
176 s
= g_malloc0(sizeof(*s
));
177 s
->lookup_symbol
= glue(lookup_symbol
, SZ
);
178 glue(s
->disas_symtab
.elf
, SZ
) = syms
;
179 s
->disas_num_syms
= nsyms
;
180 s
->disas_strtab
= str
;
192 static int glue(elf_reloc
, SZ
)(struct elfhdr
*ehdr
, int fd
, int must_swab
,
193 uint64_t (*translate_fn
)(void *, uint64_t),
194 void *translate_opaque
, uint8_t *data
,
195 struct elf_phdr
*ph
, int elf_machine
)
197 struct elf_shdr
*reltab
, *shdr_table
= NULL
;
198 struct elf_rela
*rels
= NULL
;
199 int nrels
, i
, ret
= -1;
203 shdr_table
= load_at(fd
, ehdr
->e_shoff
,
204 sizeof(struct elf_shdr
) * ehdr
->e_shnum
);
209 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
210 glue(bswap_shdr
, SZ
)(&shdr_table
[i
]);
214 reltab
= glue(find_section
, SZ
)(shdr_table
, ehdr
->e_shnum
, SHT_RELA
);
218 rels
= load_at(fd
, reltab
->sh_offset
, reltab
->sh_size
);
222 nrels
= reltab
->sh_size
/ sizeof(struct elf_rela
);
224 for (i
= 0; i
< nrels
; i
++) {
226 glue(bswap_rela
, SZ
)(&rels
[i
]);
228 if (rels
[i
].r_offset
< ph
->p_vaddr
||
229 rels
[i
].r_offset
>= ph
->p_vaddr
+ ph
->p_filesz
) {
232 addr
= &data
[rels
[i
].r_offset
- ph
->p_vaddr
];
233 switch (elf_machine
) {
235 switch (rels
[i
].r_info
) {
237 wordval
= *(elf_word
*)addr
;
241 wordval
= translate_fn(translate_opaque
, wordval
);
245 *(elf_word
*)addr
= wordval
;
248 fprintf(stderr
, "Unsupported relocation type %i!\n",
249 (int)rels
[i
].r_info
);
261 static int glue(load_elf
, SZ
)(const char *name
, int fd
,
262 uint64_t (*translate_fn
)(void *, uint64_t),
263 void *translate_opaque
,
264 int must_swab
, uint64_t *pentry
,
265 uint64_t *lowaddr
, uint64_t *highaddr
,
266 int elf_machine
, int clear_lsb
)
269 struct elf_phdr
*phdr
= NULL
, *ph
;
270 int size
, i
, total_size
;
271 elf_word mem_size
, file_size
;
272 uint64_t addr
, low
= (uint64_t)-1, high
= 0;
273 uint8_t *data
= NULL
;
275 int ret
= ELF_LOAD_FAILED
;
277 if (read(fd
, &ehdr
, sizeof(ehdr
)) != sizeof(ehdr
))
280 glue(bswap_ehdr
, SZ
)(&ehdr
);
283 switch (elf_machine
) {
285 if (ehdr
.e_machine
!= EM_PPC64
) {
286 if (ehdr
.e_machine
!= EM_PPC
) {
287 ret
= ELF_LOAD_WRONG_ARCH
;
293 if (ehdr
.e_machine
!= EM_X86_64
) {
294 if (ehdr
.e_machine
!= EM_386
) {
295 ret
= ELF_LOAD_WRONG_ARCH
;
301 if (ehdr
.e_machine
!= EM_MICROBLAZE
) {
302 if (ehdr
.e_machine
!= EM_MICROBLAZE_OLD
) {
303 ret
= ELF_LOAD_WRONG_ARCH
;
309 if (ehdr
.e_machine
!= EM_MOXIE
) {
310 if (ehdr
.e_machine
!= EM_MOXIE_OLD
) {
311 ret
= ELF_LOAD_WRONG_ARCH
;
317 if (elf_machine
!= ehdr
.e_machine
) {
318 ret
= ELF_LOAD_WRONG_ARCH
;
324 *pentry
= (uint64_t)(elf_sword
)ehdr
.e_entry
;
326 glue(load_symbols
, SZ
)(&ehdr
, fd
, must_swab
, clear_lsb
);
328 size
= ehdr
.e_phnum
* sizeof(phdr
[0]);
329 if (lseek(fd
, ehdr
.e_phoff
, SEEK_SET
) != ehdr
.e_phoff
) {
332 phdr
= g_malloc0(size
);
335 if (read(fd
, phdr
, size
) != size
)
338 for(i
= 0; i
< ehdr
.e_phnum
; i
++) {
340 glue(bswap_phdr
, SZ
)(ph
);
345 for(i
= 0; i
< ehdr
.e_phnum
; i
++) {
347 if (ph
->p_type
== PT_LOAD
) {
348 mem_size
= ph
->p_memsz
; /* Size of the ROM */
349 file_size
= ph
->p_filesz
; /* Size of the allocated data */
350 data
= g_malloc0(file_size
);
351 if (ph
->p_filesz
> 0) {
352 if (lseek(fd
, ph
->p_offset
, SEEK_SET
) < 0) {
355 if (read(fd
, data
, file_size
) != file_size
) {
359 /* address_offset is hack for kernel images that are
360 linked at the wrong physical address. */
362 addr
= translate_fn(translate_opaque
, ph
->p_paddr
);
363 glue(elf_reloc
, SZ
)(&ehdr
, fd
, must_swab
, translate_fn
,
364 translate_opaque
, data
, ph
, elf_machine
);
369 /* the entry pointer in the ELF header is a virtual
370 * address, if the text segments paddr and vaddr differ
371 * we need to adjust the entry */
372 if (pentry
&& !translate_fn
&&
373 ph
->p_vaddr
!= ph
->p_paddr
&&
374 ehdr
.e_entry
>= ph
->p_vaddr
&&
375 ehdr
.e_entry
< ph
->p_vaddr
+ ph
->p_filesz
&&
376 ph
->p_flags
& PF_X
) {
377 *pentry
= ehdr
.e_entry
- ph
->p_vaddr
+ ph
->p_paddr
;
380 snprintf(label
, sizeof(label
), "phdr #%d: %s", i
, name
);
382 /* rom_add_elf_program() seize the ownership of 'data' */
383 rom_add_elf_program(label
, data
, file_size
, mem_size
, addr
);
385 total_size
+= mem_size
;
388 if ((addr
+ mem_size
) > high
)
389 high
= addr
+ mem_size
;
396 *lowaddr
= (uint64_t)(elf_sword
)low
;
398 *highaddr
= (uint64_t)(elf_sword
)high
;