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 void glue(load_symbols
, SZ
)(struct elfhdr
*ehdr
, int fd
, int must_swab
,
108 int clear_lsb
, symbol_fn_t sym_cb
)
110 struct elf_shdr
*symtab
, *strtab
;
111 g_autofree
struct elf_shdr
*shdr_table
= NULL
;
112 g_autofree
struct elf_sym
*syms
= NULL
;
113 g_autofree
char *str
= NULL
;
117 shdr_table
= load_at(fd
, ehdr
->e_shoff
,
118 sizeof(struct elf_shdr
) * ehdr
->e_shnum
);
124 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
125 glue(bswap_shdr
, SZ
)(shdr_table
+ i
);
129 symtab
= glue(find_section
, SZ
)(shdr_table
, ehdr
->e_shnum
, SHT_SYMTAB
);
133 syms
= load_at(fd
, symtab
->sh_offset
, symtab
->sh_size
);
138 nsyms
= symtab
->sh_size
/ sizeof(struct elf_sym
);
141 if (symtab
->sh_link
>= ehdr
->e_shnum
) {
144 strtab
= &shdr_table
[symtab
->sh_link
];
146 str
= load_at(fd
, strtab
->sh_offset
, strtab
->sh_size
);
154 glue(bswap_sym
, SZ
)(&syms
[i
]);
157 sym_cb(str
+ syms
[i
].st_name
, syms
[i
].st_info
,
158 syms
[i
].st_value
, syms
[i
].st_size
);
160 /* We are only interested in function symbols.
161 Throw everything else away. */
162 if (syms
[i
].st_shndx
== SHN_UNDEF
||
163 syms
[i
].st_shndx
>= SHN_LORESERVE
||
164 ELF_ST_TYPE(syms
[i
].st_info
) != STT_FUNC
) {
167 syms
[i
] = syms
[nsyms
];
172 /* The bottom address bit marks a Thumb or MIPS16 symbol. */
173 syms
[i
].st_value
&= ~(glue(glue(Elf
, SZ
), _Addr
))1;
178 /* check we have symbols left */
183 syms
= g_realloc(syms
, nsyms
* sizeof(*syms
));
184 qsort(syms
, nsyms
, sizeof(*syms
), glue(symcmp
, SZ
));
185 for (i
= 0; i
< nsyms
- 1; i
++) {
186 if (syms
[i
].st_size
== 0) {
187 syms
[i
].st_size
= syms
[i
+ 1].st_value
- syms
[i
].st_value
;
192 s
= g_malloc0(sizeof(*s
));
193 s
->lookup_symbol
= glue(lookup_symbol
, SZ
);
194 glue(s
->disas_symtab
.elf
, SZ
) = g_steal_pointer(&syms
);
195 s
->disas_num_syms
= nsyms
;
196 s
->disas_strtab
= g_steal_pointer(&str
);
201 static int glue(elf_reloc
, SZ
)(struct elfhdr
*ehdr
, int fd
, int must_swab
,
202 uint64_t (*translate_fn
)(void *, uint64_t),
203 void *translate_opaque
, uint8_t *data
,
204 struct elf_phdr
*ph
, int elf_machine
)
206 struct elf_shdr
*reltab
, *shdr_table
= NULL
;
207 struct elf_rela
*rels
= NULL
;
208 int nrels
, i
, ret
= -1;
212 shdr_table
= load_at(fd
, ehdr
->e_shoff
,
213 sizeof(struct elf_shdr
) * ehdr
->e_shnum
);
218 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
219 glue(bswap_shdr
, SZ
)(&shdr_table
[i
]);
223 reltab
= glue(find_section
, SZ
)(shdr_table
, ehdr
->e_shnum
, SHT_RELA
);
227 rels
= load_at(fd
, reltab
->sh_offset
, reltab
->sh_size
);
231 nrels
= reltab
->sh_size
/ sizeof(struct elf_rela
);
233 for (i
= 0; i
< nrels
; i
++) {
235 glue(bswap_rela
, SZ
)(&rels
[i
]);
237 if (rels
[i
].r_offset
< ph
->p_vaddr
||
238 rels
[i
].r_offset
>= ph
->p_vaddr
+ ph
->p_filesz
) {
241 addr
= &data
[rels
[i
].r_offset
- ph
->p_vaddr
];
242 switch (elf_machine
) {
244 switch (rels
[i
].r_info
) {
246 wordval
= *(elf_word
*)addr
;
250 wordval
= translate_fn(translate_opaque
, wordval
);
254 *(elf_word
*)addr
= wordval
;
257 fprintf(stderr
, "Unsupported relocation type %i!\n",
258 (int)rels
[i
].r_info
);
271 * Given 'nhdr', a pointer to a range of ELF Notes, search through them
272 * for a note matching type 'elf_note_type' and return a pointer to
273 * the matching ELF note.
275 static struct elf_note
*glue(get_elf_note_type
, SZ
)(struct elf_note
*nhdr
,
278 elf_word elf_note_type
)
280 elf_word nhdr_size
= sizeof(struct elf_note
);
281 elf_word elf_note_entry_offset
= 0;
283 elf_word nhdr_namesz
;
284 elf_word nhdr_descsz
;
290 note_type
= nhdr
->n_type
;
291 while (note_type
!= elf_note_type
) {
292 nhdr_namesz
= nhdr
->n_namesz
;
293 nhdr_descsz
= nhdr
->n_descsz
;
295 elf_note_entry_offset
= nhdr_size
+
296 QEMU_ALIGN_UP(nhdr_namesz
, phdr_align
) +
297 QEMU_ALIGN_UP(nhdr_descsz
, phdr_align
);
300 * If the offset calculated in this iteration exceeds the
301 * supplied size, we are done and no matching note was found.
303 if (elf_note_entry_offset
> note_size
) {
307 /* skip to the next ELF Note entry */
308 nhdr
= (void *)nhdr
+ elf_note_entry_offset
;
309 note_type
= nhdr
->n_type
;
315 static ssize_t
glue(load_elf
, SZ
)(const char *name
, int fd
,
316 uint64_t (*elf_note_fn
)(void *, void *, bool),
317 uint64_t (*translate_fn
)(void *, uint64_t),
318 void *translate_opaque
,
319 int must_swab
, uint64_t *pentry
,
320 uint64_t *lowaddr
, uint64_t *highaddr
,
321 uint32_t *pflags
, int elf_machine
,
322 int clear_lsb
, int data_swab
,
323 AddressSpace
*as
, bool load_rom
,
327 struct elf_phdr
*phdr
= NULL
, *ph
;
330 elf_word mem_size
, file_size
, data_offset
;
331 uint64_t addr
, low
= (uint64_t)-1, high
= 0;
332 GMappedFile
*mapped_file
= NULL
;
333 uint8_t *data
= NULL
;
334 ssize_t ret
= ELF_LOAD_FAILED
;
336 if (read(fd
, &ehdr
, sizeof(ehdr
)) != sizeof(ehdr
))
339 glue(bswap_ehdr
, SZ
)(&ehdr
);
342 if (elf_machine
<= EM_NONE
) {
343 /* The caller didn't specify an ARCH, we can figure it out */
344 elf_machine
= ehdr
.e_machine
;
347 switch (elf_machine
) {
349 if (ehdr
.e_machine
!= EM_PPC64
) {
350 if (ehdr
.e_machine
!= EM_PPC
) {
351 ret
= ELF_LOAD_WRONG_ARCH
;
357 if (ehdr
.e_machine
!= EM_X86_64
) {
358 if (ehdr
.e_machine
!= EM_386
) {
359 ret
= ELF_LOAD_WRONG_ARCH
;
365 if (ehdr
.e_machine
!= EM_MICROBLAZE
) {
366 if (ehdr
.e_machine
!= EM_MICROBLAZE_OLD
) {
367 ret
= ELF_LOAD_WRONG_ARCH
;
374 if ((ehdr
.e_machine
!= EM_MIPS
) &&
375 (ehdr
.e_machine
!= EM_NANOMIPS
)) {
376 ret
= ELF_LOAD_WRONG_ARCH
;
381 if (elf_machine
!= ehdr
.e_machine
) {
382 ret
= ELF_LOAD_WRONG_ARCH
;
388 *pflags
= (elf_word
)ehdr
.e_flags
;
391 *pentry
= (uint64_t)(elf_sword
)ehdr
.e_entry
;
393 glue(load_symbols
, SZ
)(&ehdr
, fd
, must_swab
, clear_lsb
, sym_cb
);
395 size
= ehdr
.e_phnum
* sizeof(phdr
[0]);
396 if (lseek(fd
, ehdr
.e_phoff
, SEEK_SET
) != ehdr
.e_phoff
) {
399 phdr
= g_malloc0(size
);
402 if (read(fd
, phdr
, size
) != size
)
405 for(i
= 0; i
< ehdr
.e_phnum
; i
++) {
407 glue(bswap_phdr
, SZ
)(ph
);
412 * Since we want to be able to modify the mapped buffer, we set the
413 * 'writable' parameter to 'true'. Modifications to the buffer are not
414 * written back to the file.
416 mapped_file
= g_mapped_file_new_from_fd(fd
, true, NULL
);
422 for(i
= 0; i
< ehdr
.e_phnum
; i
++) {
424 if (ph
->p_type
== PT_LOAD
) {
425 mem_size
= ph
->p_memsz
; /* Size of the ROM */
426 file_size
= ph
->p_filesz
; /* Size of the allocated data */
427 data_offset
= ph
->p_offset
; /* Offset where the data is located */
430 if (g_mapped_file_get_length(mapped_file
) <
431 file_size
+ data_offset
) {
435 data
= (uint8_t *)g_mapped_file_get_contents(mapped_file
);
439 /* The ELF spec is somewhat vague about the purpose of the
440 * physical address field. One common use in the embedded world
441 * is that physical address field specifies the load address
442 * and the virtual address field specifies the execution address.
443 * Segments are packed into ROM or flash, and the relocation
444 * and zero-initialization of data is done at runtime. This
445 * means that the memsz header represents the runtime size of the
446 * segment, but the filesz represents the loadtime size. If
447 * we try to honour the memsz value for an ELF file like this
448 * we will end up with overlapping segments (which the
449 * loader.c code will later reject).
450 * We support ELF files using this scheme by by checking whether
451 * paddr + memsz for this segment would overlap with any other
452 * segment. If so, then we assume it's using this scheme and
453 * truncate the loaded segment to the filesz size.
454 * If the segment considered as being memsz size doesn't overlap
455 * then we use memsz for the segment length, to handle ELF files
456 * which assume that the loader will do the zero-initialization.
458 if (mem_size
> file_size
) {
459 /* If this segment's zero-init portion overlaps another
460 * segment's data or zero-init portion, then truncate this one.
461 * Invalid ELF files where the segments overlap even when
462 * only file_size bytes are loaded will be rejected by
463 * the ROM overlap check in loader.c, so we don't try to
464 * explicitly detect those here.
467 elf_word zero_start
= ph
->p_paddr
+ file_size
;
468 elf_word zero_end
= ph
->p_paddr
+ mem_size
;
470 for (j
= 0; j
< ehdr
.e_phnum
; j
++) {
471 struct elf_phdr
*jph
= &phdr
[j
];
473 if (i
!= j
&& jph
->p_type
== PT_LOAD
) {
474 elf_word other_start
= jph
->p_paddr
;
475 elf_word other_end
= jph
->p_paddr
+ jph
->p_memsz
;
477 if (!(other_start
>= zero_end
||
478 zero_start
>= other_end
)) {
479 mem_size
= file_size
;
486 if (mem_size
> SSIZE_MAX
- total_size
) {
487 ret
= ELF_LOAD_TOO_BIG
;
491 /* address_offset is hack for kernel images that are
492 linked at the wrong physical address. */
494 addr
= translate_fn(translate_opaque
, ph
->p_paddr
);
495 glue(elf_reloc
, SZ
)(&ehdr
, fd
, must_swab
, translate_fn
,
496 translate_opaque
, data
, ph
, elf_machine
);
503 for (j
= 0; j
< file_size
; j
+= (1 << data_swab
)) {
504 uint8_t *dp
= data
+ j
;
507 *(uint16_t *)dp
= bswap16(*(uint16_t *)dp
);
510 *(uint32_t *)dp
= bswap32(*(uint32_t *)dp
);
513 *(uint64_t *)dp
= bswap64(*(uint64_t *)dp
);
516 g_assert_not_reached();
521 /* the entry pointer in the ELF header is a virtual
522 * address, if the text segments paddr and vaddr differ
523 * we need to adjust the entry */
524 if (pentry
&& !translate_fn
&&
525 ph
->p_vaddr
!= ph
->p_paddr
&&
526 ehdr
.e_entry
>= ph
->p_vaddr
&&
527 ehdr
.e_entry
< ph
->p_vaddr
+ ph
->p_filesz
&&
528 ph
->p_flags
& PF_X
) {
529 *pentry
= ehdr
.e_entry
- ph
->p_vaddr
+ ph
->p_paddr
;
532 /* Some ELF files really do have segments of zero size;
533 * just ignore them rather than trying to create empty
534 * ROM blobs, because the zero-length blob can falsely
535 * trigger the overlapping-ROM-blobs check.
539 g_autofree
char *label
=
540 g_strdup_printf("%s ELF program header segment %d",
544 * rom_add_elf_program() takes its own reference to
547 rom_add_elf_program(label
, mapped_file
, data
, file_size
,
552 res
= address_space_write(as
? as
: &address_space_memory
,
553 addr
, MEMTXATTRS_UNSPECIFIED
,
555 if (res
!= MEMTX_OK
) {
559 * We need to zero'ify the space that is not copied
562 if (file_size
< mem_size
) {
563 res
= address_space_set(as
? as
: &address_space_memory
,
565 mem_size
- file_size
,
566 MEMTXATTRS_UNSPECIFIED
);
567 if (res
!= MEMTX_OK
) {
574 total_size
+= mem_size
;
577 if ((addr
+ mem_size
) > high
)
578 high
= addr
+ mem_size
;
582 } else if (ph
->p_type
== PT_NOTE
&& elf_note_fn
) {
583 struct elf_note
*nhdr
= NULL
;
585 file_size
= ph
->p_filesz
; /* Size of the range of ELF notes */
586 data_offset
= ph
->p_offset
; /* Offset where the notes are located */
589 if (g_mapped_file_get_length(mapped_file
) <
590 file_size
+ data_offset
) {
594 data
= (uint8_t *)g_mapped_file_get_contents(mapped_file
);
599 * Search the ELF notes to find one with a type matching the
600 * value passed in via 'translate_opaque'
602 nhdr
= (struct elf_note
*)data
;
603 assert(translate_opaque
!= NULL
);
604 nhdr
= glue(get_elf_note_type
, SZ
)(nhdr
, file_size
, ph
->p_align
,
605 *(uint64_t *)translate_opaque
);
607 elf_note_fn((void *)nhdr
, (void *)&ph
->p_align
, SZ
== 64);
614 *lowaddr
= (uint64_t)(elf_sword
)low
;
616 *highaddr
= (uint64_t)(elf_sword
)high
;
620 g_mapped_file_unref(mapped_file
);