1227569Sphilip/* 2301388Sarybchik * Copyright (c) 2000, Boris Popov 3284555Sarybchik * Copyright (c) 1998-2000 Doug Rabson 4227569Sphilip * Copyright (c) 2004 Peter Wemm 5227569Sphilip * All rights reserved. 6284555Sarybchik * 7227569Sphilip * Redistribution and use in source and binary forms, with or without 8284555Sarybchik * modification, are permitted provided that the following conditions 9284555Sarybchik * are met: 10284555Sarybchik * 1. Redistributions of source code must retain the above copyright 11284555Sarybchik * notice, this list of conditions and the following disclaimer. 12284555Sarybchik * 2. Redistributions in binary form must reproduce the above copyright 13228078Sphilip * notice, this list of conditions and the following disclaimer in the 14284555Sarybchik * documentation and/or other materials provided with the distribution. 15284555Sarybchik * 3. All advertising materials mentioning features or use of this software 16284555Sarybchik * must display the following acknowledgement: 17284555Sarybchik * This product includes software developed by Boris Popov. 18284555Sarybchik * 4. Neither the name of the author nor the names of any co-contributors 19284555Sarybchik * may be used to endorse or promote products derived from this software 20284555Sarybchik * without specific prior written permission. 21284555Sarybchik * 22284555Sarybchik * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23284555Sarybchik * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24284555Sarybchik * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25284555Sarybchik * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26284555Sarybchik * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27284555Sarybchik * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28284555Sarybchik * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29284555Sarybchik * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30228078Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32227569Sphilip * SUCH DAMAGE. 33227569Sphilip * 34227569Sphilip * $FreeBSD$ 35227569Sphilip */ 36227569Sphilip 37227569Sphilip#include <sys/param.h> 38284555Sarybchik#include <sys/linker.h> 39227569Sphilip#include <string.h> 40284555Sarybchik#include <stdio.h> 41284555Sarybchik#include <stdlib.h> 42284555Sarybchik#include <unistd.h> 43284555Sarybchik#include <errno.h> 44284555Sarybchik#include <fcntl.h> 45284555Sarybchik#include <machine/elf.h> 46227569Sphilip#define FREEBSD_ELF 47227569Sphilip 48227569Sphilip#include <err.h> 49227569Sphilip 50284555Sarybchik#include "ef.h" 51284555Sarybchik 52284555Sarybchiktypedef struct { 53284555Sarybchik void *addr; 54293980Sarybchik Elf_Off size; 55293980Sarybchik int flags; 56293980Sarybchik int sec; /* Original section */ 57293980Sarybchik char *name; 58293980Sarybchik} Elf_progent; 59293980Sarybchik 60293980Sarybchiktypedef struct { 61293980Sarybchik Elf_Rel *rel; 62227569Sphilip int nrel; 63227569Sphilip int sec; 64227569Sphilip} Elf_relent; 65227569Sphilip 66284555Sarybchiktypedef struct { 67284555Sarybchik Elf_Rela *rela; 68284555Sarybchik int nrela; 69284555Sarybchik int sec; 70284555Sarybchik} Elf_relaent; 71284555Sarybchik 72284555Sarybchikstruct ef_file { 73284555Sarybchik char *ef_name; 74284555Sarybchik int ef_fd; 75284555Sarybchik Elf_Ehdr ef_hdr; 76284555Sarybchik struct elf_file *ef_efile; 77284555Sarybchik 78301327Sarybchik caddr_t address; 79227569Sphilip Elf_Off size; 80301355Sarybchik Elf_Shdr *e_shdr; 81301355Sarybchik 82301355Sarybchik Elf_progent *progtab; 83227569Sphilip int nprogtab; 84227569Sphilip 85227569Sphilip Elf_relaent *relatab; 86227569Sphilip int nrela; 87284555Sarybchik 88294395Sarybchik Elf_relent *reltab; 89227569Sphilip int nrel; 90227569Sphilip 91227569Sphilip Elf_Sym *ddbsymtab; /* The symbol table we are using */ 92284555Sarybchik long ddbsymcnt; /* Number of symbols */ 93293927Sarybchik caddr_t ddbstrtab; /* String table */ 94284555Sarybchik long ddbstrcnt; /* number of bytes in string table */ 95293927Sarybchik 96284555Sarybchik caddr_t shstrtab; /* Section name string table */ 97311070Sarybchik long shstrcnt; /* number of bytes in string table */ 98284555Sarybchik 99293927Sarybchik int ef_verbose; 100284555Sarybchik}; 101293927Sarybchik 102284555Sarybchikstatic int ef_obj_get_type(elf_file_t ef); 103284555Sarybchikstatic int ef_obj_close(elf_file_t ef); 104284555Sarybchikstatic int ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest); 105284555Sarybchikstatic int ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, 106284555Sarybchik void **ptr); 107284555Sarybchikstatic int ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, 108293927Sarybchik void *dest); 109284555Sarybchikstatic int ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, 110293927Sarybchik void *dest); 111284555Sarybchikstatic int ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, 112284555Sarybchik void **ptr); 113284555Sarybchikstatic int ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, 114284555Sarybchik void **ptr); 115284555Sarybchikstatic Elf_Addr ef_obj_symaddr(elf_file_t ef, Elf_Size symidx); 116284555Sarybchikstatic int ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, 117293927Sarybchik long *stopp, long *countp); 118284555Sarybchikstatic int ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym); 119284555Sarybchik 120284555Sarybchikstatic struct elf_file_ops ef_obj_file_ops = { 121293927Sarybchik ef_obj_get_type, 122293927Sarybchik ef_obj_close, 123284555Sarybchik ef_obj_read, 124293927Sarybchik ef_obj_read_entry, 125284555Sarybchik ef_obj_seg_read, 126311063Sarybchik ef_obj_seg_read_rel, 127284555Sarybchik ef_obj_seg_read_entry, 128293927Sarybchik ef_obj_seg_read_entry_rel, 129284555Sarybchik ef_obj_symaddr, 130293927Sarybchik ef_obj_lookup_set, 131284555Sarybchik ef_obj_lookup_symbol 132284555Sarybchik}; 133284555Sarybchik 134284555Sarybchikstatic int 135284555Sarybchikef_obj_get_type(elf_file_t __unused ef) 136284555Sarybchik{ 137284555Sarybchik 138284555Sarybchik return (EFT_KLD); 139294381Sarybchik} 140294381Sarybchik 141294381Sarybchikstatic int 142284555Sarybchikef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym) 143284555Sarybchik{ 144342509Sarybchik Elf_Sym *symp; 145342509Sarybchik const char *strp; 146284555Sarybchik int i; 147284555Sarybchik 148284555Sarybchik for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 149284555Sarybchik strp = ef->ddbstrtab + symp->st_name; 150284555Sarybchik if (symp->st_shndx != SHN_UNDEF && strcmp(name, strp) == 0) { 151284555Sarybchik *sym = symp; 152284555Sarybchik return 0; 153293927Sarybchik } 154284555Sarybchik } 155284555Sarybchik return ENOENT; 156293927Sarybchik} 157284555Sarybchik 158284555Sarybchikstatic int 159293927Sarybchikef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp, 160284555Sarybchik long *countp) 161293927Sarybchik{ 162293927Sarybchik int i; 163284555Sarybchik 164294008Sarybchik for (i = 0; i < ef->nprogtab; i++) { 165294008Sarybchik if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) && 166294008Sarybchik strcmp(ef->progtab[i].name + 4, name) == 0) { 167294008Sarybchik *startp = (char *)ef->progtab[i].addr - ef->address; 168294008Sarybchik *stopp = (char *)ef->progtab[i].addr + 169284555Sarybchik ef->progtab[i].size - ef->address; 170284555Sarybchik *countp = (*stopp - *startp) / sizeof(void *); 171284555Sarybchik return (0); 172284555Sarybchik } 173293927Sarybchik } 174284555Sarybchik return (ESRCH); 175293927Sarybchik} 176284555Sarybchik 177284555Sarybchikstatic Elf_Addr 178284555Sarybchikef_obj_symaddr(elf_file_t ef, Elf_Size symidx) 179284555Sarybchik{ 180284555Sarybchik const Elf_Sym *sym; 181284555Sarybchik 182227569Sphilip if (symidx >= (size_t) ef->ddbsymcnt) 183293927Sarybchik return (0); 184293927Sarybchik sym = ef->ddbsymtab + symidx; 185293927Sarybchik 186294397Sarybchik if (sym->st_shndx != SHN_UNDEF) 187301380Sarybchik return (sym->st_value - (Elf_Addr)ef->address); 188293927Sarybchik return (0); 189293927Sarybchik} 190293927Sarybchik 191284555Sarybchikstatic int 192284555Sarybchikef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest) 193227569Sphilip{ 194293927Sarybchik ssize_t r; 195227569Sphilip 196227569Sphilip if (offset != (Elf_Off)-1) { 197227569Sphilip if (lseek(ef->ef_fd, offset, SEEK_SET) == -1) 198311080Sarybchik return EIO; 199293927Sarybchik } 200293927Sarybchik 201227569Sphilip r = read(ef->ef_fd, dest, len); 202293927Sarybchik if (r != -1 && (size_t)r == len) 203227569Sphilip return 0; 204227569Sphilip else 205227569Sphilip return EIO; 206227569Sphilip} 207227569Sphilip 208293927Sarybchikstatic int 209293927Sarybchikef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr) 210293927Sarybchik{ 211293927Sarybchik int error; 212293927Sarybchik 213227569Sphilip *ptr = malloc(len); 214293927Sarybchik if (*ptr == NULL) 215227569Sphilip return ENOMEM; 216227569Sphilip error = ef_obj_read(ef, offset, len, *ptr); 217284555Sarybchik if (error) 218293927Sarybchik free(*ptr); 219293927Sarybchik return error; 220293927Sarybchik} 221284555Sarybchik 222227569Sphilipstatic int 223284555Sarybchikef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest) 224284555Sarybchik{ 225227569Sphilip 226227569Sphilip if (offset + len > ef->size) { 227284555Sarybchik if (ef->ef_verbose) 228284555Sarybchik warnx("ef_seg_read_rel(%s): bad offset/len (%lx:%ld)", 229293927Sarybchik ef->ef_name, (long)offset, (long)len); 230293927Sarybchik return (EFAULT); 231293927Sarybchik } 232293927Sarybchik bcopy(ef->address + offset, dest, len); 233293927Sarybchik return (0); 234293927Sarybchik} 235311494Sarybchik 236311494Sarybchikstatic int 237293927Sarybchikef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest) 238284555Sarybchik{ 239301337Sarybchik char *memaddr; 240284555Sarybchik Elf_Rel *r; 241284555Sarybchik Elf_Rela *a; 242293927Sarybchik Elf_Off secbase, dataoff; 243284555Sarybchik int error, i, sec; 244284555Sarybchik 245284555Sarybchik if (offset + len > ef->size) { 246284555Sarybchik if (ef->ef_verbose) 247284555Sarybchik warnx("ef_seg_read_rel(%s): bad offset/len (%lx:%ld)", 248284555Sarybchik ef->ef_name, (long)offset, (long)len); 249284555Sarybchik return (EFAULT); 250284555Sarybchik } 251301337Sarybchik bcopy(ef->address + offset, dest, len); 252284555Sarybchik 253284555Sarybchik /* Find out which section contains the data. */ 254284555Sarybchik memaddr = ef->address + offset; 255284555Sarybchik sec = -1; 256227569Sphilip secbase = dataoff = 0; 257227569Sphilip for (i = 0; i < ef->nprogtab; i++) { 258311056Sarybchik if (ef->progtab[i].addr == NULL) 259227569Sphilip continue; 260227569Sphilip if (memaddr < (char *)ef->progtab[i].addr || memaddr + len > 261227569Sphilip (char *)ef->progtab[i].addr + ef->progtab[i].size) 262227569Sphilip continue; 263284555Sarybchik sec = ef->progtab[i].sec; 264284555Sarybchik /* We relocate to address 0. */ 265284555Sarybchik secbase = (char *)ef->progtab[i].addr - ef->address; 266227569Sphilip dataoff = memaddr - ef->address; 267227569Sphilip break; 268227569Sphilip } 269227569Sphilip 270284555Sarybchik if (sec == -1) 271284555Sarybchik return (EFAULT); 272284555Sarybchik 273227569Sphilip /* Now do the relocations. */ 274227569Sphilip for (i = 0; i < ef->nrel; i++) { 275227569Sphilip if (ef->reltab[i].sec != sec) 276227569Sphilip continue; 277227569Sphilip for (r = ef->reltab[i].rel; 278227569Sphilip r < &ef->reltab[i].rel[ef->reltab[i].nrel]; r++) { 279227569Sphilip error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, secbase, 280227569Sphilip dataoff, len, dest); 281227569Sphilip if (error != 0) 282227569Sphilip return (error); 283227569Sphilip } 284227569Sphilip } 285227569Sphilip for (i = 0; i < ef->nrela; i++) { 286227569Sphilip if (ef->relatab[i].sec != sec) 287227569Sphilip continue; 288227569Sphilip for (a = ef->relatab[i].rela; 289227569Sphilip a < &ef->relatab[i].rela[ef->relatab[i].nrela]; a++) { 290284555Sarybchik error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 291284555Sarybchik secbase, dataoff, len, dest); 292227569Sphilip if (error != 0) 293301340Sarybchik return (error); 294301340Sarybchik } 295227569Sphilip } 296227569Sphilip return (0); 297227569Sphilip} 298227569Sphilip 299293927Sarybchikstatic int 300293927Sarybchikef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr) 301227569Sphilip{ 302227569Sphilip int error; 303227569Sphilip 304227569Sphilip *ptr = malloc(len); 305301340Sarybchik if (*ptr == NULL) 306301340Sarybchik return ENOMEM; 307227569Sphilip error = ef_obj_seg_read(ef, offset, len, *ptr); 308227569Sphilip if (error) 309284555Sarybchik free(*ptr); 310293927Sarybchik return error; 311284555Sarybchik} 312284555Sarybchik 313284555Sarybchikstatic int 314293927Sarybchikef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, 315294001Sarybchik void **ptr) 316294001Sarybchik{ 317294001Sarybchik int error; 318294001Sarybchik 319284555Sarybchik *ptr = malloc(len); 320284555Sarybchik if (*ptr == NULL) 321284555Sarybchik return ENOMEM; 322227569Sphilip error = ef_obj_seg_read_rel(ef, offset, len, *ptr); 323301340Sarybchik if (error) 324301340Sarybchik free(*ptr); 325301340Sarybchik return error; 326301340Sarybchik} 327227569Sphilip 328227569Sphilipint 329227569Sphilipef_obj_open(const char *filename, struct elf_file *efile, int verbose) 330293927Sarybchik{ 331294377Sarybchik elf_file_t ef; 332293927Sarybchik Elf_Ehdr *hdr; 333293927Sarybchik Elf_Shdr *shdr; 334293927Sarybchik Elf_Sym *es; 335293927Sarybchik char *mapbase; 336293927Sarybchik void *vtmp; 337284555Sarybchik size_t mapsize, alignmask, max_addralign; 338227569Sphilip int error, fd, pb, ra, res, rl; 339293927Sarybchik int i, j, nbytes, nsym, shstrindex, symstrindex, symtabindex; 340227569Sphilip 341293927Sarybchik if (filename == NULL) 342293927Sarybchik return EFTYPE; 343227569Sphilip if ((fd = open(filename, O_RDONLY)) == -1) 344227569Sphilip return errno; 345280562Sarybchik 346284555Sarybchik ef = calloc(1, sizeof(*ef)); 347280562Sarybchik if (ef == NULL) { 348280562Sarybchik close(fd); 349284555Sarybchik return (ENOMEM); 350280562Sarybchik } 351280562Sarybchik 352284555Sarybchik efile->ef_ef = ef; 353280562Sarybchik efile->ef_ops = &ef_obj_file_ops; 354280562Sarybchik 355284555Sarybchik ef->ef_verbose = verbose; 356280562Sarybchik ef->ef_fd = fd; 357227569Sphilip ef->ef_name = strdup(filename); 358227569Sphilip ef->ef_efile = efile; 359227569Sphilip hdr = (Elf_Ehdr *)&ef->ef_hdr; 360301346Sarybchik 361301346Sarybchik res = read(fd, hdr, sizeof(*hdr)); 362301346Sarybchik error = EFTYPE; 363301346Sarybchik if (res != sizeof(*hdr)) 364301346Sarybchik goto out; 365301346Sarybchik if (!IS_ELF(*hdr)) 366227569Sphilip goto out; 367301346Sarybchik if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 368301346Sarybchik hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 369301346Sarybchik hdr->e_ident[EI_VERSION] != EV_CURRENT || 370301346Sarybchik hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH || 371301346Sarybchik hdr->e_type != ET_REL) 372301346Sarybchik goto out; 373301346Sarybchik 374284555Sarybchik nbytes = hdr->e_shnum * hdr->e_shentsize; 375301346Sarybchik if (nbytes == 0 || hdr->e_shoff == 0 || 376301346Sarybchik hdr->e_shentsize != sizeof(Elf_Shdr)) 377301346Sarybchik goto out; 378301346Sarybchik 379301346Sarybchik if (ef_obj_read_entry(ef, hdr->e_shoff, nbytes, &vtmp) != 0) { 380301346Sarybchik printf("ef_read_entry failed\n"); 381227569Sphilip goto out; 382301346Sarybchik } 383301346Sarybchik ef->e_shdr = shdr = vtmp; 384227569Sphilip 385301346Sarybchik /* Scan the section header for information and table sizing. */ 386301346Sarybchik nsym = 0; 387301346Sarybchik symtabindex = -1; 388301346Sarybchik symstrindex = -1; 389301346Sarybchik for (i = 0; i < hdr->e_shnum; i++) { 390301346Sarybchik switch (shdr[i].sh_type) { 391301346Sarybchik case SHT_PROGBITS: 392227569Sphilip case SHT_NOBITS: 393301346Sarybchik ef->nprogtab++; 394301346Sarybchik break; 395301346Sarybchik case SHT_SYMTAB: 396301346Sarybchik nsym++; 397301346Sarybchik symtabindex = i; 398301346Sarybchik symstrindex = shdr[i].sh_link; 399227569Sphilip break; 400301346Sarybchik case SHT_REL: 401301346Sarybchik ef->nrel++; 402301346Sarybchik break; 403301346Sarybchik case SHT_RELA: 404227569Sphilip ef->nrela++; 405227569Sphilip break; 406301324Sarybchik case SHT_STRTAB: 407301346Sarybchik break; 408301324Sarybchik } 409293996Sarybchik } 410293996Sarybchik 411293996Sarybchik if (ef->nprogtab == 0) { 412227569Sphilip warnx("%s: file has no contents", filename); 413227569Sphilip goto out; 414284555Sarybchik } 415301345Sarybchik if (nsym != 1) { 416227569Sphilip warnx("%s: file has no valid symbol table", filename); 417301346Sarybchik goto out; 418227569Sphilip } 419284555Sarybchik if (symstrindex < 0 || symstrindex > hdr->e_shnum || 420227569Sphilip shdr[symstrindex].sh_type != SHT_STRTAB) { 421284555Sarybchik warnx("%s: file has invalid symbol strings", filename); 422227569Sphilip goto out; 423284555Sarybchik } 424293927Sarybchik 425294378Sarybchik /* Allocate space for tracking the load chunks */ 426294378Sarybchik if (ef->nprogtab != 0) 427293927Sarybchik ef->progtab = calloc(ef->nprogtab, sizeof(*ef->progtab)); 428293972Sarybchik if (ef->nrel != 0) 429293972Sarybchik ef->reltab = calloc(ef->nrel, sizeof(*ef->reltab)); 430284555Sarybchik if (ef->nrela != 0) 431311496Sarybchik ef->relatab = calloc(ef->nrela, sizeof(*ef->relatab)); 432311496Sarybchik if ((ef->nprogtab != 0 && ef->progtab == NULL) || 433311496Sarybchik (ef->nrel != 0 && ef->reltab == NULL) || 434311496Sarybchik (ef->nrela != 0 && ef->relatab == NULL)) { 435284555Sarybchik printf("malloc failed\n"); 436227569Sphilip error = ENOMEM; 437284555Sarybchik goto out; 438301340Sarybchik } 439284555Sarybchik 440284555Sarybchik ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); 441284555Sarybchik if (ef_obj_read_entry(ef, shdr[symtabindex].sh_offset, 442227569Sphilip shdr[symtabindex].sh_size, (void**)&ef->ddbsymtab) != 0) { 443284555Sarybchik printf("ef_read_entry failed\n"); 444227569Sphilip goto out; 445227569Sphilip } 446227569Sphilip 447227569Sphilip ef->ddbstrcnt = shdr[symstrindex].sh_size; 448293927Sarybchik if (ef_obj_read_entry(ef, shdr[symstrindex].sh_offset, 449227569Sphilip shdr[symstrindex].sh_size, (void**)&ef->ddbstrtab) != 0) { 450294379Sarybchik printf("ef_read_entry failed\n"); 451294379Sarybchik goto out; 452294379Sarybchik } 453294379Sarybchik 454294379Sarybchik /* Do we have a string table for the section names? */ 455293927Sarybchik shstrindex = -1; 456294379Sarybchik if (hdr->e_shstrndx != 0 && 457294379Sarybchik shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { 458294379Sarybchik shstrindex = hdr->e_shstrndx; 459293927Sarybchik ef->shstrcnt = shdr[shstrindex].sh_size; 460311495Sarybchik if (ef_obj_read_entry(ef, shdr[shstrindex].sh_offset, 461294379Sarybchik shdr[shstrindex].sh_size, (void**)&ef->shstrtab) != 0) { 462294379Sarybchik printf("ef_read_entry failed\n"); 463294379Sarybchik goto out; 464293927Sarybchik } 465301321Sarybchik } 466301321Sarybchik 467227569Sphilip /* Size up code/data(progbits) and bss(nobits). */ 468227569Sphilip alignmask = 0; 469227569Sphilip max_addralign = 0; 470227569Sphilip mapsize = 0; 471227569Sphilip for (i = 0; i < hdr->e_shnum; i++) { 472293927Sarybchik switch (shdr[i].sh_type) { 473293927Sarybchik case SHT_PROGBITS: 474293927Sarybchik case SHT_NOBITS: 475293927Sarybchik alignmask = shdr[i].sh_addralign - 1; 476293927Sarybchik if (shdr[i].sh_addralign > max_addralign) 477293927Sarybchik max_addralign = shdr[i].sh_addralign; 478293927Sarybchik mapsize += alignmask; 479293927Sarybchik mapsize &= ~alignmask; 480293927Sarybchik mapsize += shdr[i].sh_size; 481293927Sarybchik break; 482293927Sarybchik } 483293927Sarybchik } 484293927Sarybchik 485227569Sphilip /* We know how much space we need for the text/data/bss/etc. */ 486227569Sphilip ef->size = mapsize; 487227569Sphilip if (posix_memalign((void **)&ef->address, max_addralign, mapsize)) { 488284555Sarybchik printf("posix_memalign failed\n"); 489284555Sarybchik goto out; 490293927Sarybchik } 491284555Sarybchik mapbase = ef->address; 492284555Sarybchik 493284555Sarybchik /* 494284555Sarybchik * Now load code/data(progbits), zero bss(nobits), allocate 495284555Sarybchik * space for and load relocs 496284555Sarybchik */ 497293927Sarybchik pb = 0; 498284555Sarybchik rl = 0; 499284555Sarybchik ra = 0; 500284555Sarybchik alignmask = 0; 501284555Sarybchik for (i = 0; i < hdr->e_shnum; i++) { 502284555Sarybchik switch (shdr[i].sh_type) { 503284555Sarybchik case SHT_PROGBITS: 504284555Sarybchik case SHT_NOBITS: 505284555Sarybchik alignmask = shdr[i].sh_addralign - 1; 506293927Sarybchik mapbase += alignmask; 507284555Sarybchik mapbase = (char *)((uintptr_t)mapbase & ~alignmask); 508284555Sarybchik ef->progtab[pb].addr = (void *)(uintptr_t)mapbase; 509284555Sarybchik if (shdr[i].sh_type == SHT_PROGBITS) { 510284555Sarybchik ef->progtab[pb].name = "<<PROGBITS>>"; 511284555Sarybchik if (ef_obj_read(ef, shdr[i].sh_offset, 512293944Sarybchik shdr[i].sh_size, 513293944Sarybchik ef->progtab[pb].addr) != 0) { 514284555Sarybchik printf("failed to read progbits\n"); 515293927Sarybchik goto out; 516284555Sarybchik } 517284555Sarybchik } else { 518284555Sarybchik ef->progtab[pb].name = "<<NOBITS>>"; 519284555Sarybchik bzero(ef->progtab[pb].addr, shdr[i].sh_size); 520293927Sarybchik } 521284555Sarybchik ef->progtab[pb].size = shdr[i].sh_size; 522284555Sarybchik ef->progtab[pb].sec = i; 523284555Sarybchik if (ef->shstrtab && shdr[i].sh_name != 0) 524284555Sarybchik ef->progtab[pb].name = 525284555Sarybchik ef->shstrtab + shdr[i].sh_name; 526294403Sarybchik 527294403Sarybchik /* Update all symbol values with the offset. */ 528284555Sarybchik for (j = 0; j < ef->ddbsymcnt; j++) { 529293927Sarybchik es = &ef->ddbsymtab[j]; 530284555Sarybchik if (es->st_shndx != i) 531284555Sarybchik continue; 532284555Sarybchik es->st_value += (Elf_Addr)ef->progtab[pb].addr; 533284555Sarybchik } 534284555Sarybchik mapbase += shdr[i].sh_size; 535284555Sarybchik pb++; 536293927Sarybchik break; 537284555Sarybchik case SHT_REL: 538284555Sarybchik ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); 539284555Sarybchik ef->reltab[rl].sec = shdr[i].sh_info; 540284555Sarybchik if (ef_obj_read_entry(ef, shdr[i].sh_offset, 541342512Sarybchik shdr[i].sh_size, (void**)&ef->reltab[rl].rel) != 542284555Sarybchik 0) { 543284555Sarybchik printf("ef_read_entry failed\n"); 544293927Sarybchik goto out; 545284555Sarybchik } 546284555Sarybchik rl++; 547284555Sarybchik break; 548311495Sarybchik case SHT_RELA: 549311495Sarybchik ef->relatab[ra].nrela = 550284555Sarybchik shdr[i].sh_size / sizeof(Elf_Rela); 551284555Sarybchik ef->relatab[ra].sec = shdr[i].sh_info; 552284555Sarybchik if (ef_obj_read_entry(ef, shdr[i].sh_offset, 553293927Sarybchik shdr[i].sh_size, (void**)&ef->relatab[ra].rela) != 554284555Sarybchik 0) { 555284555Sarybchik printf("ef_read_entry failed\n"); 556284555Sarybchik goto out; 557284555Sarybchik } 558284555Sarybchik ra++; 559284555Sarybchik break; 560284555Sarybchik } 561284555Sarybchik } 562294386Sarybchik error = 0; 563294386Sarybchikout: 564294386Sarybchik if (error) 565294386Sarybchik ef_obj_close(ef); 566294386Sarybchik return error; 567294386Sarybchik} 568294386Sarybchik 569294386Sarybchikstatic int 570301361Sarybchikef_obj_close(elf_file_t ef) 571301361Sarybchik{ 572301361Sarybchik int i; 573310842Sarybchik 574301361Sarybchik close(ef->ef_fd); 575301361Sarybchik if (ef->ef_name) 576301361Sarybchik free(ef->ef_name); 577301361Sarybchik if (ef->e_shdr != NULL) 578301361Sarybchik free(ef->e_shdr); 579301361Sarybchik if (ef->size != 0) 580301361Sarybchik free(ef->address); 581301361Sarybchik if (ef->nprogtab != 0) 582301361Sarybchik free(ef->progtab); 583301361Sarybchik if (ef->nrel != 0) { 584301361Sarybchik for (i = 0; i < ef->nrel; i++) 585301361Sarybchik if (ef->reltab[i].rel != NULL) 586301361Sarybchik free(ef->reltab[i].rel); 587301361Sarybchik free(ef->reltab); 588301361Sarybchik } 589301361Sarybchik if (ef->nrela != 0) { 590301361Sarybchik for (i = 0; i < ef->nrela; i++) 591294386Sarybchik if (ef->relatab[i].rela != NULL) 592294386Sarybchik free(ef->relatab[i].rela); 593294386Sarybchik free(ef->relatab); 594294386Sarybchik } 595284555Sarybchik if (ef->ddbsymtab != NULL) 596284555Sarybchik free(ef->ddbsymtab); 597284555Sarybchik if (ef->ddbstrtab != NULL) 598284555Sarybchik free(ef->ddbstrtab); 599284555Sarybchik if (ef->shstrtab != NULL) 600284555Sarybchik free(ef->shstrtab); 601284555Sarybchik ef->ef_efile->ef_ops = NULL; 602284555Sarybchik ef->ef_efile->ef_ef = NULL; 603227569Sphilip free(ef); 604227569Sphilip 605227569Sphilip return 0; 606227569Sphilip} 607227569Sphilip