1134361Siedowse/* 2134361Siedowse * Copyright (c) 2000, Boris Popov 3134361Siedowse * Copyright (c) 1998-2000 Doug Rabson 4134361Siedowse * Copyright (c) 2004 Peter Wemm 5134361Siedowse * All rights reserved. 6134361Siedowse * 7134361Siedowse * Redistribution and use in source and binary forms, with or without 8134361Siedowse * modification, are permitted provided that the following conditions 9134361Siedowse * are met: 10134361Siedowse * 1. Redistributions of source code must retain the above copyright 11134361Siedowse * notice, this list of conditions and the following disclaimer. 12134361Siedowse * 2. Redistributions in binary form must reproduce the above copyright 13134361Siedowse * notice, this list of conditions and the following disclaimer in the 14134361Siedowse * documentation and/or other materials provided with the distribution. 15134361Siedowse * 3. All advertising materials mentioning features or use of this software 16134361Siedowse * must display the following acknowledgement: 17134361Siedowse * This product includes software developed by Boris Popov. 18134361Siedowse * 4. Neither the name of the author nor the names of any co-contributors 19134361Siedowse * may be used to endorse or promote products derived from this software 20134361Siedowse * without specific prior written permission. 21134361Siedowse * 22134361Siedowse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23134361Siedowse * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24134361Siedowse * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25134361Siedowse * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26134361Siedowse * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27134361Siedowse * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28134361Siedowse * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29134361Siedowse * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30134361Siedowse * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31134361Siedowse * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32134361Siedowse * SUCH DAMAGE. 33134361Siedowse * 34134361Siedowse * $FreeBSD$ 35134361Siedowse */ 36134361Siedowse 37134361Siedowse#include <sys/param.h> 38134361Siedowse#include <sys/linker.h> 39134361Siedowse#include <string.h> 40134361Siedowse#include <stdio.h> 41134361Siedowse#include <stdlib.h> 42134361Siedowse#include <unistd.h> 43134361Siedowse#include <errno.h> 44134361Siedowse#include <fcntl.h> 45134361Siedowse#include <machine/elf.h> 46134361Siedowse#define FREEBSD_ELF 47134361Siedowse 48134361Siedowse#include <err.h> 49134361Siedowse 50134361Siedowse#include "ef.h" 51134361Siedowse 52134361Siedowsetypedef struct { 53134361Siedowse void *addr; 54134361Siedowse Elf_Off size; 55134361Siedowse int flags; 56134361Siedowse int sec; /* Original section */ 57134361Siedowse char *name; 58134361Siedowse} Elf_progent; 59134361Siedowse 60134361Siedowsetypedef struct { 61134361Siedowse Elf_Rel *rel; 62134361Siedowse int nrel; 63134361Siedowse int sec; 64134361Siedowse} Elf_relent; 65134361Siedowse 66134361Siedowsetypedef struct { 67134361Siedowse Elf_Rela *rela; 68134361Siedowse int nrela; 69134361Siedowse int sec; 70134361Siedowse} Elf_relaent; 71134361Siedowse 72134361Siedowsestruct ef_file { 73134361Siedowse char *ef_name; 74134361Siedowse int ef_fd; 75134361Siedowse Elf_Ehdr ef_hdr; 76134361Siedowse struct elf_file *ef_efile; 77134361Siedowse 78134361Siedowse caddr_t address; 79134361Siedowse Elf_Off size; 80134361Siedowse Elf_Shdr *e_shdr; 81134361Siedowse 82134361Siedowse Elf_progent *progtab; 83134361Siedowse int nprogtab; 84134361Siedowse 85134361Siedowse Elf_relaent *relatab; 86134361Siedowse int nrela; 87134361Siedowse 88134361Siedowse Elf_relent *reltab; 89134361Siedowse int nrel; 90134361Siedowse 91134361Siedowse Elf_Sym *ddbsymtab; /* The symbol table we are using */ 92134361Siedowse long ddbsymcnt; /* Number of symbols */ 93134361Siedowse caddr_t ddbstrtab; /* String table */ 94134361Siedowse long ddbstrcnt; /* number of bytes in string table */ 95134361Siedowse 96134361Siedowse caddr_t shstrtab; /* Section name string table */ 97134361Siedowse long shstrcnt; /* number of bytes in string table */ 98134361Siedowse 99134361Siedowse int ef_verbose; 100134361Siedowse}; 101134361Siedowse 102134361Siedowsestatic int ef_obj_get_type(elf_file_t ef); 103134361Siedowsestatic int ef_obj_close(elf_file_t ef); 104134361Siedowsestatic int ef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void* dest); 105134361Siedowsestatic int ef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, 106134361Siedowse void **ptr); 107134361Siedowsestatic int ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, 108134361Siedowse void *dest); 109134361Siedowsestatic int ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, 110134361Siedowse void *dest); 111134361Siedowsestatic int ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, 112134361Siedowse void **ptr); 113134361Siedowsestatic int ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, 114134361Siedowse void **ptr); 115153504Smarcelstatic Elf_Addr ef_obj_symaddr(elf_file_t ef, Elf_Size symidx); 116134361Siedowsestatic int ef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, 117134361Siedowse long *stopp, long *countp); 118134361Siedowsestatic int ef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym); 119134361Siedowse 120134361Siedowsestatic struct elf_file_ops ef_obj_file_ops = { 121134361Siedowse ef_obj_get_type, 122134361Siedowse ef_obj_close, 123134361Siedowse ef_obj_read, 124134361Siedowse ef_obj_read_entry, 125134361Siedowse ef_obj_seg_read, 126134361Siedowse ef_obj_seg_read_rel, 127134361Siedowse ef_obj_seg_read_entry, 128134361Siedowse ef_obj_seg_read_entry_rel, 129134361Siedowse ef_obj_symaddr, 130134361Siedowse ef_obj_lookup_set, 131134361Siedowse ef_obj_lookup_symbol 132134361Siedowse}; 133134361Siedowse 134134361Siedowsestatic int 135186826Sluigief_obj_get_type(elf_file_t __unused ef) 136134361Siedowse{ 137134361Siedowse 138134361Siedowse return (EFT_KLD); 139134361Siedowse} 140134361Siedowse 141134361Siedowsestatic int 142134361Siedowseef_obj_lookup_symbol(elf_file_t ef, const char* name, Elf_Sym** sym) 143134361Siedowse{ 144134361Siedowse Elf_Sym *symp; 145134361Siedowse const char *strp; 146134361Siedowse int i; 147134361Siedowse 148134361Siedowse for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 149134361Siedowse strp = ef->ddbstrtab + symp->st_name; 150134361Siedowse if (symp->st_shndx != SHN_UNDEF && strcmp(name, strp) == 0) { 151134361Siedowse *sym = symp; 152134361Siedowse return 0; 153134361Siedowse } 154134361Siedowse } 155134361Siedowse return ENOENT; 156134361Siedowse} 157134361Siedowse 158134361Siedowsestatic int 159134361Siedowseef_obj_lookup_set(elf_file_t ef, const char *name, long *startp, long *stopp, 160134361Siedowse long *countp) 161134361Siedowse{ 162134361Siedowse int i; 163134361Siedowse 164134361Siedowse for (i = 0; i < ef->nprogtab; i++) { 165134361Siedowse if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) && 166134361Siedowse strcmp(ef->progtab[i].name + 4, name) == 0) { 167134361Siedowse *startp = (char *)ef->progtab[i].addr - ef->address; 168134361Siedowse *stopp = (char *)ef->progtab[i].addr + 169134361Siedowse ef->progtab[i].size - ef->address; 170134361Siedowse *countp = (*stopp - *startp) / sizeof(void *); 171134361Siedowse return (0); 172134361Siedowse } 173134361Siedowse } 174134361Siedowse return (ESRCH); 175134361Siedowse} 176134361Siedowse 177134361Siedowsestatic Elf_Addr 178153504Smarcelef_obj_symaddr(elf_file_t ef, Elf_Size symidx) 179134361Siedowse{ 180134361Siedowse const Elf_Sym *sym; 181134361Siedowse 182186826Sluigi if (symidx >= (size_t) ef->ddbsymcnt) 183134361Siedowse return (0); 184134361Siedowse sym = ef->ddbsymtab + symidx; 185134361Siedowse 186134361Siedowse if (sym->st_shndx != SHN_UNDEF) 187134361Siedowse return (sym->st_value - (Elf_Addr)ef->address); 188134361Siedowse return (0); 189134361Siedowse} 190134361Siedowse 191134361Siedowsestatic int 192134361Siedowseef_obj_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest) 193134361Siedowse{ 194134361Siedowse ssize_t r; 195134361Siedowse 196134361Siedowse if (offset != (Elf_Off)-1) { 197134361Siedowse if (lseek(ef->ef_fd, offset, SEEK_SET) == -1) 198134361Siedowse return EIO; 199134361Siedowse } 200134361Siedowse 201134361Siedowse r = read(ef->ef_fd, dest, len); 202134361Siedowse if (r != -1 && (size_t)r == len) 203134361Siedowse return 0; 204134361Siedowse else 205134361Siedowse return EIO; 206134361Siedowse} 207134361Siedowse 208134361Siedowsestatic int 209134361Siedowseef_obj_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr) 210134361Siedowse{ 211134361Siedowse int error; 212134361Siedowse 213134361Siedowse *ptr = malloc(len); 214134361Siedowse if (*ptr == NULL) 215134361Siedowse return ENOMEM; 216134361Siedowse error = ef_obj_read(ef, offset, len, *ptr); 217134361Siedowse if (error) 218134361Siedowse free(*ptr); 219134361Siedowse return error; 220134361Siedowse} 221134361Siedowse 222134361Siedowsestatic int 223134361Siedowseef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest) 224134361Siedowse{ 225134361Siedowse 226134361Siedowse if (offset + len > ef->size) { 227134361Siedowse if (ef->ef_verbose) 228134361Siedowse warnx("ef_seg_read_rel(%s): bad offset/len (%lx:%ld)", 229134361Siedowse ef->ef_name, (long)offset, (long)len); 230134361Siedowse return (EFAULT); 231134361Siedowse } 232134361Siedowse bcopy(ef->address + offset, dest, len); 233134361Siedowse return (0); 234134361Siedowse} 235134361Siedowse 236134361Siedowsestatic int 237134361Siedowseef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest) 238134361Siedowse{ 239134361Siedowse char *memaddr; 240134361Siedowse Elf_Rel *r; 241134361Siedowse Elf_Rela *a; 242134450Siedowse Elf_Off secbase, dataoff; 243134361Siedowse int error, i, sec; 244134450Siedowse 245134361Siedowse if (offset + len > ef->size) { 246134361Siedowse if (ef->ef_verbose) 247134361Siedowse warnx("ef_seg_read_rel(%s): bad offset/len (%lx:%ld)", 248134361Siedowse ef->ef_name, (long)offset, (long)len); 249134361Siedowse return (EFAULT); 250134361Siedowse } 251134361Siedowse bcopy(ef->address + offset, dest, len); 252134361Siedowse 253134361Siedowse /* Find out which section contains the data. */ 254134361Siedowse memaddr = ef->address + offset; 255134361Siedowse sec = -1; 256134450Siedowse secbase = dataoff = 0; 257134361Siedowse for (i = 0; i < ef->nprogtab; i++) { 258134361Siedowse if (ef->progtab[i].addr == NULL) 259134361Siedowse continue; 260134361Siedowse if (memaddr < (char *)ef->progtab[i].addr || memaddr + len > 261134361Siedowse (char *)ef->progtab[i].addr + ef->progtab[i].size) 262134361Siedowse continue; 263134361Siedowse sec = ef->progtab[i].sec; 264134450Siedowse /* We relocate to address 0. */ 265134450Siedowse secbase = (char *)ef->progtab[i].addr - ef->address; 266134450Siedowse dataoff = memaddr - ef->address; 267134361Siedowse break; 268134361Siedowse } 269134361Siedowse 270134361Siedowse if (sec == -1) 271134361Siedowse return (EFAULT); 272134361Siedowse 273134361Siedowse /* Now do the relocations. */ 274134361Siedowse for (i = 0; i < ef->nrel; i++) { 275134361Siedowse if (ef->reltab[i].sec != sec) 276134361Siedowse continue; 277134361Siedowse for (r = ef->reltab[i].rel; 278134361Siedowse r < &ef->reltab[i].rel[ef->reltab[i].nrel]; r++) { 279134450Siedowse error = ef_reloc(ef->ef_efile, r, EF_RELOC_REL, secbase, 280134450Siedowse dataoff, len, dest); 281134361Siedowse if (error != 0) 282134361Siedowse return (error); 283134361Siedowse } 284134361Siedowse } 285134361Siedowse for (i = 0; i < ef->nrela; i++) { 286134361Siedowse if (ef->relatab[i].sec != sec) 287134361Siedowse continue; 288134361Siedowse for (a = ef->relatab[i].rela; 289134361Siedowse a < &ef->relatab[i].rela[ef->relatab[i].nrela]; a++) { 290134450Siedowse error = ef_reloc(ef->ef_efile, a, EF_RELOC_RELA, 291134450Siedowse secbase, dataoff, len, dest); 292134361Siedowse if (error != 0) 293134361Siedowse return (error); 294134361Siedowse } 295134361Siedowse } 296134361Siedowse return (0); 297134361Siedowse} 298134361Siedowse 299134361Siedowsestatic int 300134361Siedowseef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr) 301134361Siedowse{ 302134361Siedowse int error; 303134361Siedowse 304134361Siedowse *ptr = malloc(len); 305134361Siedowse if (*ptr == NULL) 306134361Siedowse return ENOMEM; 307134361Siedowse error = ef_obj_seg_read(ef, offset, len, *ptr); 308134361Siedowse if (error) 309134361Siedowse free(*ptr); 310134361Siedowse return error; 311134361Siedowse} 312134361Siedowse 313134361Siedowsestatic int 314134361Siedowseef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len, 315134361Siedowse void **ptr) 316134361Siedowse{ 317134361Siedowse int error; 318134361Siedowse 319134361Siedowse *ptr = malloc(len); 320134361Siedowse if (*ptr == NULL) 321134361Siedowse return ENOMEM; 322134361Siedowse error = ef_obj_seg_read_rel(ef, offset, len, *ptr); 323134361Siedowse if (error) 324134361Siedowse free(*ptr); 325134361Siedowse return error; 326134361Siedowse} 327134361Siedowse 328134361Siedowseint 329134361Siedowseef_obj_open(const char *filename, struct elf_file *efile, int verbose) 330134361Siedowse{ 331134361Siedowse elf_file_t ef; 332134361Siedowse Elf_Ehdr *hdr; 333134361Siedowse Elf_Shdr *shdr; 334134361Siedowse Elf_Sym *es; 335134361Siedowse char *mapbase; 336134373Siedowse void *vtmp; 337154251Sjasone size_t mapsize, alignmask, max_addralign; 338154251Sjasone int error, fd, pb, ra, res, rl; 339134361Siedowse int i, j, nbytes, nsym, shstrindex, symstrindex, symtabindex; 340134361Siedowse 341134361Siedowse if (filename == NULL) 342134361Siedowse return EFTYPE; 343134361Siedowse if ((fd = open(filename, O_RDONLY)) == -1) 344134361Siedowse return errno; 345134361Siedowse 346251440Sdelphij ef = calloc(1, sizeof(*ef)); 347134361Siedowse if (ef == NULL) { 348134361Siedowse close(fd); 349134361Siedowse return (ENOMEM); 350134361Siedowse } 351134361Siedowse 352134361Siedowse efile->ef_ef = ef; 353134361Siedowse efile->ef_ops = &ef_obj_file_ops; 354134361Siedowse 355134361Siedowse ef->ef_verbose = verbose; 356134361Siedowse ef->ef_fd = fd; 357134361Siedowse ef->ef_name = strdup(filename); 358134361Siedowse ef->ef_efile = efile; 359134361Siedowse hdr = (Elf_Ehdr *)&ef->ef_hdr; 360134361Siedowse 361134361Siedowse res = read(fd, hdr, sizeof(*hdr)); 362134361Siedowse error = EFTYPE; 363134361Siedowse if (res != sizeof(*hdr)) 364134361Siedowse goto out; 365134361Siedowse if (!IS_ELF(*hdr)) 366134361Siedowse goto out; 367134361Siedowse if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 368134361Siedowse hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 369134361Siedowse hdr->e_ident[EI_VERSION] != EV_CURRENT || 370134361Siedowse hdr->e_version != EV_CURRENT || hdr->e_machine != ELF_TARG_MACH || 371134361Siedowse hdr->e_type != ET_REL) 372134361Siedowse goto out; 373134361Siedowse 374134361Siedowse nbytes = hdr->e_shnum * hdr->e_shentsize; 375134361Siedowse if (nbytes == 0 || hdr->e_shoff == 0 || 376134361Siedowse hdr->e_shentsize != sizeof(Elf_Shdr)) 377134361Siedowse goto out; 378134361Siedowse 379134373Siedowse if (ef_obj_read_entry(ef, hdr->e_shoff, nbytes, &vtmp) != 0) { 380134361Siedowse printf("ef_read_entry failed\n"); 381134361Siedowse goto out; 382134361Siedowse } 383134373Siedowse ef->e_shdr = shdr = vtmp; 384134361Siedowse 385134361Siedowse /* Scan the section header for information and table sizing. */ 386134361Siedowse nsym = 0; 387134361Siedowse symtabindex = -1; 388134361Siedowse symstrindex = -1; 389134361Siedowse for (i = 0; i < hdr->e_shnum; i++) { 390134361Siedowse switch (shdr[i].sh_type) { 391134361Siedowse case SHT_PROGBITS: 392134361Siedowse case SHT_NOBITS: 393134361Siedowse ef->nprogtab++; 394134361Siedowse break; 395134361Siedowse case SHT_SYMTAB: 396134361Siedowse nsym++; 397134361Siedowse symtabindex = i; 398134361Siedowse symstrindex = shdr[i].sh_link; 399134361Siedowse break; 400134361Siedowse case SHT_REL: 401134361Siedowse ef->nrel++; 402134361Siedowse break; 403134361Siedowse case SHT_RELA: 404134361Siedowse ef->nrela++; 405134361Siedowse break; 406134361Siedowse case SHT_STRTAB: 407134361Siedowse break; 408134361Siedowse } 409134361Siedowse } 410134361Siedowse 411134361Siedowse if (ef->nprogtab == 0) { 412134361Siedowse warnx("%s: file has no contents", filename); 413134361Siedowse goto out; 414134361Siedowse } 415134361Siedowse if (nsym != 1) { 416134361Siedowse warnx("%s: file has no valid symbol table", filename); 417134361Siedowse goto out; 418134361Siedowse } 419134361Siedowse if (symstrindex < 0 || symstrindex > hdr->e_shnum || 420134361Siedowse shdr[symstrindex].sh_type != SHT_STRTAB) { 421134361Siedowse warnx("%s: file has invalid symbol strings", filename); 422134361Siedowse goto out; 423134361Siedowse } 424134361Siedowse 425134361Siedowse /* Allocate space for tracking the load chunks */ 426134361Siedowse if (ef->nprogtab != 0) 427134361Siedowse ef->progtab = calloc(ef->nprogtab, sizeof(*ef->progtab)); 428134361Siedowse if (ef->nrel != 0) 429134361Siedowse ef->reltab = calloc(ef->nrel, sizeof(*ef->reltab)); 430134361Siedowse if (ef->nrela != 0) 431134361Siedowse ef->relatab = calloc(ef->nrela, sizeof(*ef->relatab)); 432134361Siedowse if ((ef->nprogtab != 0 && ef->progtab == NULL) || 433134361Siedowse (ef->nrel != 0 && ef->reltab == NULL) || 434134361Siedowse (ef->nrela != 0 && ef->relatab == NULL)) { 435134361Siedowse printf("malloc failed\n"); 436134361Siedowse error = ENOMEM; 437134361Siedowse goto out; 438134361Siedowse } 439134361Siedowse 440134361Siedowse ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); 441134361Siedowse if (ef_obj_read_entry(ef, shdr[symtabindex].sh_offset, 442134361Siedowse shdr[symtabindex].sh_size, (void**)&ef->ddbsymtab) != 0) { 443134361Siedowse printf("ef_read_entry failed\n"); 444134361Siedowse goto out; 445134361Siedowse } 446134361Siedowse 447134361Siedowse ef->ddbstrcnt = shdr[symstrindex].sh_size; 448134361Siedowse if (ef_obj_read_entry(ef, shdr[symstrindex].sh_offset, 449134361Siedowse shdr[symstrindex].sh_size, (void**)&ef->ddbstrtab) != 0) { 450134361Siedowse printf("ef_read_entry failed\n"); 451134361Siedowse goto out; 452134361Siedowse } 453134361Siedowse 454134361Siedowse /* Do we have a string table for the section names? */ 455134361Siedowse shstrindex = -1; 456134361Siedowse if (hdr->e_shstrndx != 0 && 457134361Siedowse shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { 458134361Siedowse shstrindex = hdr->e_shstrndx; 459134361Siedowse ef->shstrcnt = shdr[shstrindex].sh_size; 460134361Siedowse if (ef_obj_read_entry(ef, shdr[shstrindex].sh_offset, 461134361Siedowse shdr[shstrindex].sh_size, (void**)&ef->shstrtab) != 0) { 462134361Siedowse printf("ef_read_entry failed\n"); 463134361Siedowse goto out; 464134361Siedowse } 465134361Siedowse } 466134361Siedowse 467134361Siedowse /* Size up code/data(progbits) and bss(nobits). */ 468134361Siedowse alignmask = 0; 469154251Sjasone max_addralign = 0; 470134361Siedowse mapsize = 0; 471134361Siedowse for (i = 0; i < hdr->e_shnum; i++) { 472134361Siedowse switch (shdr[i].sh_type) { 473134361Siedowse case SHT_PROGBITS: 474134361Siedowse case SHT_NOBITS: 475134361Siedowse alignmask = shdr[i].sh_addralign - 1; 476154251Sjasone if (shdr[i].sh_addralign > max_addralign) 477154251Sjasone max_addralign = shdr[i].sh_addralign; 478134361Siedowse mapsize += alignmask; 479134361Siedowse mapsize &= ~alignmask; 480134361Siedowse mapsize += shdr[i].sh_size; 481134361Siedowse break; 482134361Siedowse } 483134361Siedowse } 484134361Siedowse 485134361Siedowse /* We know how much space we need for the text/data/bss/etc. */ 486134361Siedowse ef->size = mapsize; 487154251Sjasone if (posix_memalign((void **)&ef->address, max_addralign, mapsize)) { 488154251Sjasone printf("posix_memalign failed\n"); 489134361Siedowse goto out; 490134361Siedowse } 491134361Siedowse mapbase = ef->address; 492134361Siedowse 493134361Siedowse /* 494134361Siedowse * Now load code/data(progbits), zero bss(nobits), allocate 495134361Siedowse * space for and load relocs 496134361Siedowse */ 497134361Siedowse pb = 0; 498134361Siedowse rl = 0; 499134361Siedowse ra = 0; 500134361Siedowse alignmask = 0; 501134361Siedowse for (i = 0; i < hdr->e_shnum; i++) { 502134361Siedowse switch (shdr[i].sh_type) { 503134361Siedowse case SHT_PROGBITS: 504134361Siedowse case SHT_NOBITS: 505134361Siedowse alignmask = shdr[i].sh_addralign - 1; 506134361Siedowse mapbase += alignmask; 507134361Siedowse mapbase = (char *)((uintptr_t)mapbase & ~alignmask); 508134361Siedowse ef->progtab[pb].addr = (void *)(uintptr_t)mapbase; 509134361Siedowse if (shdr[i].sh_type == SHT_PROGBITS) { 510134361Siedowse ef->progtab[pb].name = "<<PROGBITS>>"; 511134361Siedowse if (ef_obj_read(ef, shdr[i].sh_offset, 512134361Siedowse shdr[i].sh_size, 513134361Siedowse ef->progtab[pb].addr) != 0) { 514134361Siedowse printf("failed to read progbits\n"); 515134361Siedowse goto out; 516134361Siedowse } 517134361Siedowse } else { 518134361Siedowse ef->progtab[pb].name = "<<NOBITS>>"; 519134361Siedowse bzero(ef->progtab[pb].addr, shdr[i].sh_size); 520134361Siedowse } 521134361Siedowse ef->progtab[pb].size = shdr[i].sh_size; 522134361Siedowse ef->progtab[pb].sec = i; 523134361Siedowse if (ef->shstrtab && shdr[i].sh_name != 0) 524134361Siedowse ef->progtab[pb].name = 525134361Siedowse ef->shstrtab + shdr[i].sh_name; 526134361Siedowse 527134361Siedowse /* Update all symbol values with the offset. */ 528134361Siedowse for (j = 0; j < ef->ddbsymcnt; j++) { 529134361Siedowse es = &ef->ddbsymtab[j]; 530134361Siedowse if (es->st_shndx != i) 531134361Siedowse continue; 532134361Siedowse es->st_value += (Elf_Addr)ef->progtab[pb].addr; 533134361Siedowse } 534134361Siedowse mapbase += shdr[i].sh_size; 535134361Siedowse pb++; 536134361Siedowse break; 537134361Siedowse case SHT_REL: 538134361Siedowse ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); 539134361Siedowse ef->reltab[rl].sec = shdr[i].sh_info; 540134361Siedowse if (ef_obj_read_entry(ef, shdr[i].sh_offset, 541134361Siedowse shdr[i].sh_size, (void**)&ef->reltab[rl].rel) != 542134361Siedowse 0) { 543134361Siedowse printf("ef_read_entry failed\n"); 544134361Siedowse goto out; 545134361Siedowse } 546134361Siedowse rl++; 547134361Siedowse break; 548134361Siedowse case SHT_RELA: 549134361Siedowse ef->relatab[ra].nrela = 550134361Siedowse shdr[i].sh_size / sizeof(Elf_Rela); 551134361Siedowse ef->relatab[ra].sec = shdr[i].sh_info; 552134361Siedowse if (ef_obj_read_entry(ef, shdr[i].sh_offset, 553134361Siedowse shdr[i].sh_size, (void**)&ef->relatab[ra].rela) != 554134361Siedowse 0) { 555134361Siedowse printf("ef_read_entry failed\n"); 556134361Siedowse goto out; 557134361Siedowse } 558134361Siedowse ra++; 559134361Siedowse break; 560134361Siedowse } 561134361Siedowse } 562134361Siedowse error = 0; 563134361Siedowseout: 564134361Siedowse if (error) 565134361Siedowse ef_obj_close(ef); 566134361Siedowse return error; 567134361Siedowse} 568134361Siedowse 569134361Siedowsestatic int 570134361Siedowseef_obj_close(elf_file_t ef) 571134361Siedowse{ 572134361Siedowse int i; 573134361Siedowse 574134361Siedowse close(ef->ef_fd); 575134361Siedowse if (ef->ef_name) 576134361Siedowse free(ef->ef_name); 577134361Siedowse if (ef->e_shdr != NULL) 578134361Siedowse free(ef->e_shdr); 579134361Siedowse if (ef->size != 0) 580134361Siedowse free(ef->address); 581134361Siedowse if (ef->nprogtab != 0) 582134361Siedowse free(ef->progtab); 583134361Siedowse if (ef->nrel != 0) { 584134361Siedowse for (i = 0; i < ef->nrel; i++) 585134361Siedowse if (ef->reltab[i].rel != NULL) 586134361Siedowse free(ef->reltab[i].rel); 587134361Siedowse free(ef->reltab); 588134361Siedowse } 589134361Siedowse if (ef->nrela != 0) { 590134361Siedowse for (i = 0; i < ef->nrela; i++) 591134361Siedowse if (ef->relatab[i].rela != NULL) 592134361Siedowse free(ef->relatab[i].rela); 593134361Siedowse free(ef->relatab); 594134361Siedowse } 595134361Siedowse if (ef->ddbsymtab != NULL) 596134361Siedowse free(ef->ddbsymtab); 597134361Siedowse if (ef->ddbstrtab != NULL) 598134361Siedowse free(ef->ddbstrtab); 599134361Siedowse if (ef->shstrtab != NULL) 600134361Siedowse free(ef->shstrtab); 601134361Siedowse ef->ef_efile->ef_ops = NULL; 602134361Siedowse ef->ef_efile->ef_ef = NULL; 603134361Siedowse free(ef); 604134361Siedowse 605134361Siedowse return 0; 606134361Siedowse} 607