elf_ops.h 6.2 KB
Newer Older
B
bellard 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
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;
}

B
bellard 已提交
141
int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
T
ths 已提交
142 143
                       int must_swab, uint64_t *pentry,
                       uint64_t *lowaddr, uint64_t *highaddr)
B
bellard 已提交
144 145 146 147
{
    struct elfhdr ehdr;
    struct elf_phdr *phdr = NULL, *ph;
    int size, i, total_size;
T
ths 已提交
148
    elf_word low = 0, high = 0;
B
bellard 已提交
149
    elf_word mem_size, addr;
B
bellard 已提交
150
    uint8_t *data = NULL;
B
bellard 已提交
151 152 153 154 155 156 157

    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
        goto fail;
    if (must_swab) {
        glue(bswap_ehdr, SZ)(&ehdr);
    }

158 159 160
    if (ELF_MACHINE != ehdr.e_machine)
        goto fail;

B
bellard 已提交
161 162 163
    if (pentry)
   	*pentry = (uint64_t)ehdr.e_entry;

B
bellard 已提交
164 165 166 167 168 169 170 171
    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)
T
ths 已提交
172
        goto fail;
B
bellard 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
    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) {
B
bellard 已提交
188
                if (lseek(fd, ph->p_offset, SEEK_SET) < 0)
T
ths 已提交
189
                    goto fail;
B
bellard 已提交
190
                if (read(fd, data, ph->p_filesz) != ph->p_filesz)
T
ths 已提交
191
                    goto fail;
B
bellard 已提交
192 193 194 195 196 197
            }
            addr = ph->p_vaddr + virt_to_phys_addend;

            cpu_physical_memory_write_rom(addr, data, mem_size);

            total_size += mem_size;
T
ths 已提交
198 199 200 201
            if (!low || addr < low)
                low = addr;
            if (!high || (addr + mem_size) > high)
                high = addr + mem_size;
B
bellard 已提交
202 203

            qemu_free(data);
B
bellard 已提交
204
            data = NULL;
B
bellard 已提交
205 206
        }
    }
B
bellard 已提交
207
    qemu_free(phdr);
T
ths 已提交
208 209 210 211
    if (lowaddr)
        *lowaddr = (uint64_t)low;
    if (highaddr)
        *highaddr = (uint64_t)high;
B
bellard 已提交
212
    return total_size;
T
ths 已提交
213
 fail:
B
bellard 已提交
214
    qemu_free(data);
B
bellard 已提交
215 216 217
    qemu_free(phdr);
    return -1;
}