Browse Source
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1831 c046a42c-6fe2-441c-8c8c-71466251a162stable-0.10
5 changed files with 439 additions and 36 deletions
@ -0,0 +1,197 @@ |
|||
static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr) |
|||
{ |
|||
bswap16s(&ehdr->e_type); /* Object file type */ |
|||
bswap16s(&ehdr->e_machine); /* Architecture */ |
|||
bswap32s(&ehdr->e_version); /* Object file version */ |
|||
bswapSZs(&ehdr->e_entry); /* Entry point virtual address */ |
|||
bswapSZs(&ehdr->e_phoff); /* Program header table file offset */ |
|||
bswapSZs(&ehdr->e_shoff); /* Section header table file offset */ |
|||
bswap32s(&ehdr->e_flags); /* Processor-specific flags */ |
|||
bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ |
|||
bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ |
|||
bswap16s(&ehdr->e_phnum); /* Program header table entry count */ |
|||
bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ |
|||
bswap16s(&ehdr->e_shnum); /* Section header table entry count */ |
|||
bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ |
|||
} |
|||
|
|||
static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr) |
|||
{ |
|||
bswap32s(&phdr->p_type); /* Segment type */ |
|||
bswapSZs(&phdr->p_offset); /* Segment file offset */ |
|||
bswapSZs(&phdr->p_vaddr); /* Segment virtual address */ |
|||
bswapSZs(&phdr->p_paddr); /* Segment physical address */ |
|||
bswapSZs(&phdr->p_filesz); /* Segment size in file */ |
|||
bswapSZs(&phdr->p_memsz); /* Segment size in memory */ |
|||
bswap32s(&phdr->p_flags); /* Segment flags */ |
|||
bswapSZs(&phdr->p_align); /* Segment alignment */ |
|||
} |
|||
|
|||
static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr) |
|||
{ |
|||
bswap32s(&shdr->sh_name); |
|||
bswap32s(&shdr->sh_type); |
|||
bswapSZs(&shdr->sh_flags); |
|||
bswapSZs(&shdr->sh_addr); |
|||
bswapSZs(&shdr->sh_offset); |
|||
bswapSZs(&shdr->sh_size); |
|||
bswap32s(&shdr->sh_link); |
|||
bswap32s(&shdr->sh_info); |
|||
bswapSZs(&shdr->sh_addralign); |
|||
bswapSZs(&shdr->sh_entsize); |
|||
} |
|||
|
|||
static void glue(bswap_sym, SZ)(struct elf_sym *sym) |
|||
{ |
|||
bswap32s(&sym->st_name); |
|||
bswapSZs(&sym->st_value); |
|||
bswapSZs(&sym->st_size); |
|||
bswap16s(&sym->st_shndx); |
|||
} |
|||
|
|||
static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, |
|||
int n, int type) |
|||
{ |
|||
int i; |
|||
for(i=0;i<n;i++) { |
|||
if (shdr_table[i].sh_type == type) |
|||
return shdr_table + i; |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) |
|||
{ |
|||
struct elf_shdr *symtab, *strtab, *shdr_table = NULL; |
|||
struct elf_sym *syms = NULL; |
|||
#if (SZ == 64) |
|||
struct elf32_sym *syms32 = NULL; |
|||
#endif |
|||
struct syminfo *s; |
|||
int nsyms, i; |
|||
char *str = NULL; |
|||
|
|||
shdr_table = load_at(fd, ehdr->e_shoff, |
|||
sizeof(struct elf_shdr) * ehdr->e_shnum); |
|||
if (!shdr_table) |
|||
return -1; |
|||
|
|||
if (must_swab) { |
|||
for (i = 0; i < ehdr->e_shnum; i++) { |
|||
glue(bswap_shdr, SZ)(shdr_table + i); |
|||
} |
|||
} |
|||
|
|||
symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB); |
|||
if (!symtab) |
|||
goto fail; |
|||
syms = load_at(fd, symtab->sh_offset, symtab->sh_size); |
|||
if (!syms) |
|||
goto fail; |
|||
|
|||
nsyms = symtab->sh_size / sizeof(struct elf_sym); |
|||
#if (SZ == 64) |
|||
syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym)); |
|||
#endif |
|||
for (i = 0; i < nsyms; i++) { |
|||
if (must_swab) |
|||
glue(bswap_sym, SZ)(&syms[i]); |
|||
#if (SZ == 64) |
|||
syms32[i].st_name = syms[i].st_name; |
|||
syms32[i].st_info = syms[i].st_info; |
|||
syms32[i].st_other = syms[i].st_other; |
|||
syms32[i].st_shndx = syms[i].st_shndx; |
|||
syms32[i].st_value = syms[i].st_value & 0xffffffff; |
|||
syms32[i].st_size = syms[i].st_size & 0xffffffff; |
|||
#endif |
|||
} |
|||
/* String table */ |
|||
if (symtab->sh_link >= ehdr->e_shnum) |
|||
goto fail; |
|||
strtab = &shdr_table[symtab->sh_link]; |
|||
|
|||
str = load_at(fd, strtab->sh_offset, strtab->sh_size); |
|||
if (!str) |
|||
goto fail; |
|||
|
|||
/* Commit */ |
|||
s = qemu_mallocz(sizeof(*s)); |
|||
#if (SZ == 64) |
|||
s->disas_symtab = syms32; |
|||
qemu_free(syms); |
|||
#else |
|||
s->disas_symtab = syms; |
|||
#endif |
|||
s->disas_num_syms = nsyms; |
|||
s->disas_strtab = str; |
|||
s->next = syminfos; |
|||
syminfos = s; |
|||
qemu_free(shdr_table); |
|||
return 0; |
|||
fail: |
|||
#if (SZ == 64) |
|||
qemu_free(syms32); |
|||
#endif |
|||
qemu_free(syms); |
|||
qemu_free(str); |
|||
qemu_free(shdr_table); |
|||
return -1; |
|||
} |
|||
|
|||
int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, int must_swab) |
|||
{ |
|||
struct elfhdr ehdr; |
|||
struct elf_phdr *phdr = NULL, *ph; |
|||
int size, i, total_size; |
|||
elf_word mem_size, addr; |
|||
uint8_t *data; |
|||
|
|||
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) |
|||
goto fail; |
|||
if (must_swab) { |
|||
glue(bswap_ehdr, SZ)(&ehdr); |
|||
} |
|||
|
|||
glue(load_symbols, SZ)(&ehdr, fd, must_swab); |
|||
|
|||
size = ehdr.e_phnum * sizeof(phdr[0]); |
|||
lseek(fd, ehdr.e_phoff, SEEK_SET); |
|||
phdr = qemu_mallocz(size); |
|||
if (!phdr) |
|||
goto fail; |
|||
if (read(fd, phdr, size) != size) |
|||
goto fail; |
|||
if (must_swab) { |
|||
for(i = 0; i < ehdr.e_phnum; i++) { |
|||
ph = &phdr[i]; |
|||
glue(bswap_phdr, SZ)(ph); |
|||
} |
|||
} |
|||
|
|||
total_size = 0; |
|||
for(i = 0; i < ehdr.e_phnum; i++) { |
|||
ph = &phdr[i]; |
|||
if (ph->p_type == PT_LOAD) { |
|||
mem_size = ph->p_memsz; |
|||
/* XXX: avoid allocating */ |
|||
data = qemu_mallocz(mem_size); |
|||
if (ph->p_filesz > 0) { |
|||
lseek(fd, ph->p_offset, SEEK_SET); |
|||
if (read(fd, data, ph->p_filesz) != ph->p_filesz) |
|||
goto fail; |
|||
} |
|||
addr = ph->p_vaddr + virt_to_phys_addend; |
|||
|
|||
cpu_physical_memory_write_rom(addr, data, mem_size); |
|||
|
|||
total_size += mem_size; |
|||
|
|||
qemu_free(data); |
|||
} |
|||
} |
|||
return total_size; |
|||
fail: |
|||
qemu_free(phdr); |
|||
return -1; |
|||
} |
|||
|
|||
@ -0,0 +1,234 @@ |
|||
/*
|
|||
* QEMU Executable loader |
|||
* |
|||
* Copyright (c) 2006 Fabrice Bellard |
|||
* |
|||
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
* of this software and associated documentation files (the "Software"), to deal |
|||
* in the Software without restriction, including without limitation the rights |
|||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
* copies of the Software, and to permit persons to whom the Software is |
|||
* furnished to do so, subject to the following conditions: |
|||
* |
|||
* The above copyright notice and this permission notice shall be included in |
|||
* all copies or substantial portions of the Software. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
* THE SOFTWARE. |
|||
*/ |
|||
#include "vl.h" |
|||
#include "disas.h" |
|||
|
|||
/* return the size or -1 if error */ |
|||
int get_image_size(const char *filename) |
|||
{ |
|||
int fd, size; |
|||
fd = open(filename, O_RDONLY | O_BINARY); |
|||
if (fd < 0) |
|||
return -1; |
|||
size = lseek(fd, 0, SEEK_END); |
|||
close(fd); |
|||
return size; |
|||
} |
|||
|
|||
/* return the size or -1 if error */ |
|||
int load_image(const char *filename, uint8_t *addr) |
|||
{ |
|||
int fd, size; |
|||
fd = open(filename, O_RDONLY | O_BINARY); |
|||
if (fd < 0) |
|||
return -1; |
|||
size = lseek(fd, 0, SEEK_END); |
|||
lseek(fd, 0, SEEK_SET); |
|||
if (read(fd, addr, size) != size) { |
|||
close(fd); |
|||
return -1; |
|||
} |
|||
close(fd); |
|||
return size; |
|||
} |
|||
|
|||
/* A.OUT loader */ |
|||
|
|||
struct exec |
|||
{ |
|||
uint32_t a_info; /* Use macros N_MAGIC, etc for access */ |
|||
uint32_t a_text; /* length of text, in bytes */ |
|||
uint32_t a_data; /* length of data, in bytes */ |
|||
uint32_t a_bss; /* length of uninitialized data area, in bytes */ |
|||
uint32_t a_syms; /* length of symbol table data in file, in bytes */ |
|||
uint32_t a_entry; /* start address */ |
|||
uint32_t a_trsize; /* length of relocation info for text, in bytes */ |
|||
uint32_t a_drsize; /* length of relocation info for data, in bytes */ |
|||
}; |
|||
|
|||
#ifdef BSWAP_NEEDED |
|||
static void bswap_ahdr(struct exec *e) |
|||
{ |
|||
bswap32s(&e->a_info); |
|||
bswap32s(&e->a_text); |
|||
bswap32s(&e->a_data); |
|||
bswap32s(&e->a_bss); |
|||
bswap32s(&e->a_syms); |
|||
bswap32s(&e->a_entry); |
|||
bswap32s(&e->a_trsize); |
|||
bswap32s(&e->a_drsize); |
|||
} |
|||
#else |
|||
#define bswap_ahdr(x) do { } while (0) |
|||
#endif |
|||
|
|||
#define N_MAGIC(exec) ((exec).a_info & 0xffff) |
|||
#define OMAGIC 0407 |
|||
#define NMAGIC 0410 |
|||
#define ZMAGIC 0413 |
|||
#define QMAGIC 0314 |
|||
#define _N_HDROFF(x) (1024 - sizeof (struct exec)) |
|||
#define N_TXTOFF(x) \ |
|||
(N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ |
|||
(N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) |
|||
#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0) |
|||
#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) |
|||
#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1)) |
|||
|
|||
#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) |
|||
|
|||
#define N_DATADDR(x) \ |
|||
(N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ |
|||
: (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) |
|||
|
|||
|
|||
int load_aout(const char *filename, uint8_t *addr) |
|||
{ |
|||
int fd, size, ret; |
|||
struct exec e; |
|||
uint32_t magic; |
|||
|
|||
fd = open(filename, O_RDONLY | O_BINARY); |
|||
if (fd < 0) |
|||
return -1; |
|||
|
|||
size = read(fd, &e, sizeof(e)); |
|||
if (size < 0) |
|||
goto fail; |
|||
|
|||
bswap_ahdr(&e); |
|||
|
|||
magic = N_MAGIC(e); |
|||
switch (magic) { |
|||
case ZMAGIC: |
|||
case QMAGIC: |
|||
case OMAGIC: |
|||
lseek(fd, N_TXTOFF(e), SEEK_SET); |
|||
size = read(fd, addr, e.a_text + e.a_data); |
|||
if (size < 0) |
|||
goto fail; |
|||
break; |
|||
case NMAGIC: |
|||
lseek(fd, N_TXTOFF(e), SEEK_SET); |
|||
size = read(fd, addr, e.a_text); |
|||
if (size < 0) |
|||
goto fail; |
|||
ret = read(fd, addr + N_DATADDR(e), e.a_data); |
|||
if (ret < 0) |
|||
goto fail; |
|||
size += ret; |
|||
break; |
|||
default: |
|||
goto fail; |
|||
} |
|||
close(fd); |
|||
return size; |
|||
fail: |
|||
close(fd); |
|||
return -1; |
|||
} |
|||
|
|||
/* ELF loader */ |
|||
|
|||
static void *load_at(int fd, int offset, int size) |
|||
{ |
|||
void *ptr; |
|||
if (lseek(fd, offset, SEEK_SET) < 0) |
|||
return NULL; |
|||
ptr = qemu_malloc(size); |
|||
if (!ptr) |
|||
return NULL; |
|||
if (read(fd, ptr, size) != size) { |
|||
qemu_free(ptr); |
|||
return NULL; |
|||
} |
|||
return ptr; |
|||
} |
|||
|
|||
|
|||
#define ELF_CLASS ELFCLASS32 |
|||
#include "elf.h" |
|||
|
|||
#define SZ 32 |
|||
#define elf_word uint32_t |
|||
#define bswapSZs bswap32s |
|||
#include "elf_ops.h" |
|||
|
|||
#undef elfhdr |
|||
#undef elf_phdr |
|||
#undef elf_shdr |
|||
#undef elf_sym |
|||
#undef elf_note |
|||
#undef elf_word |
|||
#undef bswapSZs |
|||
#undef SZ |
|||
#define elfhdr elf64_hdr |
|||
#define elf_phdr elf64_phdr |
|||
#define elf_note elf64_note |
|||
#define elf_shdr elf64_shdr |
|||
#define elf_sym elf64_sym |
|||
#define elf_word uint64_t |
|||
#define bswapSZs bswap64s |
|||
#define SZ 64 |
|||
#include "elf_ops.h" |
|||
|
|||
/* return < 0 if error, otherwise the number of bytes loaded in memory */ |
|||
int load_elf(const char *filename, int64_t virt_to_phys_addend) |
|||
{ |
|||
int fd, data_order, must_swab, ret; |
|||
uint8_t e_ident[EI_NIDENT]; |
|||
|
|||
fd = open(filename, O_RDONLY); |
|||
if (fd < 0) { |
|||
perror(filename); |
|||
return -1; |
|||
} |
|||
if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident)) |
|||
goto fail; |
|||
if (e_ident[0] != ELFMAG0 || |
|||
e_ident[1] != ELFMAG1 || |
|||
e_ident[2] != ELFMAG2 || |
|||
e_ident[3] != ELFMAG3) |
|||
goto fail; |
|||
#ifdef WORDS_BIGENDIAN |
|||
data_order = ELFDATA2MSB; |
|||
#else |
|||
data_order = ELFDATA2LSB; |
|||
#endif |
|||
must_swab = data_order != e_ident[EI_DATA]; |
|||
|
|||
lseek(fd, 0, SEEK_SET); |
|||
if (e_ident[EI_CLASS] == ELFCLASS64) { |
|||
ret = load_elf64(fd, virt_to_phys_addend, must_swab); |
|||
} else { |
|||
ret = load_elf32(fd, virt_to_phys_addend, must_swab); |
|||
} |
|||
|
|||
close(fd); |
|||
return ret; |
|||
|
|||
fail: |
|||
close(fd); |
|||
return -1; |
|||
} |
|||
Loading…
Reference in new issue