link_elf.c revision 133397
1249259Sdim/*- 2249259Sdim * Copyright (c) 1998-2000 Doug Rabson 3249259Sdim * All rights reserved. 4249259Sdim * 5249259Sdim * Redistribution and use in source and binary forms, with or without 6249259Sdim * modification, are permitted provided that the following conditions 7249259Sdim * are met: 8249259Sdim * 1. Redistributions of source code must retain the above copyright 9249259Sdim * notice, this list of conditions and the following disclaimer. 10249259Sdim * 2. Redistributions in binary form must reproduce the above copyright 11249259Sdim * notice, this list of conditions and the following disclaimer in the 12249259Sdim * documentation and/or other materials provided with the distribution. 13249259Sdim * 14249259Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15249259Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16249259Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17249259Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18249259Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19249259Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20249259Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21249259Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22249259Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23249259Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24249259Sdim * SUCH DAMAGE. 25249259Sdim */ 26249259Sdim 27249259Sdim#include <sys/cdefs.h> 28249259Sdim__FBSDID("$FreeBSD: head/sys/kern/link_elf.c 133397 2004-08-09 18:46:13Z green $"); 29249259Sdim 30249259Sdim#include "opt_gdb.h" 31249259Sdim#include "opt_mac.h" 32249259Sdim 33249259Sdim#include <sys/param.h> 34249259Sdim#include <sys/systm.h> 35249259Sdim#ifdef GPROF 36249259Sdim#include <sys/gmon.h> 37249259Sdim#endif 38249259Sdim#include <sys/kernel.h> 39249259Sdim#include <sys/lock.h> 40249259Sdim#include <sys/mac.h> 41249259Sdim#include <sys/malloc.h> 42249259Sdim#include <sys/mutex.h> 43249259Sdim#include <sys/proc.h> 44249259Sdim#include <sys/namei.h> 45249259Sdim#include <sys/fcntl.h> 46249259Sdim#include <sys/vnode.h> 47249259Sdim#include <sys/linker.h> 48249259Sdim 49249259Sdim#include <machine/elf.h> 50249259Sdim 51249259Sdim#include <vm/vm.h> 52249259Sdim#include <vm/vm_param.h> 53249259Sdim#ifdef SPARSE_MAPPING 54249259Sdim#include <vm/vm_object.h> 55249259Sdim#include <vm/vm_kern.h> 56249259Sdim#include <vm/vm_extern.h> 57249259Sdim#endif 58249259Sdim#include <vm/pmap.h> 59249259Sdim#include <vm/vm_map.h> 60249259Sdim 61249259Sdim#include <sys/link_elf.h> 62249259Sdim 63249259Sdim#include "linker_if.h" 64249259Sdim 65249259Sdimtypedef struct elf_file { 66249259Sdim struct linker_file lf; /* Common fields */ 67249259Sdim int preloaded; /* Was file pre-loaded */ 68249259Sdim caddr_t address; /* Relocation address */ 69249259Sdim#ifdef SPARSE_MAPPING 70249259Sdim vm_object_t object; /* VM object to hold file pages */ 71249259Sdim#endif 72249259Sdim Elf_Dyn* dynamic; /* Symbol table etc. */ 73249259Sdim Elf_Hashelt nbuckets; /* DT_HASH info */ 74249259Sdim Elf_Hashelt nchains; 75249259Sdim const Elf_Hashelt* buckets; 76249259Sdim const Elf_Hashelt* chains; 77249259Sdim caddr_t hash; 78249259Sdim caddr_t strtab; /* DT_STRTAB */ 79249259Sdim int strsz; /* DT_STRSZ */ 80249259Sdim const Elf_Sym* symtab; /* DT_SYMTAB */ 81249259Sdim Elf_Addr* got; /* DT_PLTGOT */ 82249259Sdim const Elf_Rel* pltrel; /* DT_JMPREL */ 83249259Sdim int pltrelsize; /* DT_PLTRELSZ */ 84249259Sdim const Elf_Rela* pltrela; /* DT_JMPREL */ 85249259Sdim int pltrelasize; /* DT_PLTRELSZ */ 86249259Sdim const Elf_Rel* rel; /* DT_REL */ 87249259Sdim int relsize; /* DT_RELSZ */ 88249259Sdim const Elf_Rela* rela; /* DT_RELA */ 89249259Sdim int relasize; /* DT_RELASZ */ 90249259Sdim caddr_t modptr; 91249259Sdim const Elf_Sym* ddbsymtab; /* The symbol table we are using */ 92249259Sdim long ddbsymcnt; /* Number of symbols */ 93249259Sdim caddr_t ddbstrtab; /* String table */ 94249259Sdim long ddbstrcnt; /* number of bytes in string table */ 95249259Sdim caddr_t symbase; /* malloc'ed symbold base */ 96249259Sdim caddr_t strbase; /* malloc'ed string base */ 97249259Sdim#ifdef GDB 98249259Sdim struct link_map gdb; /* hooks for gdb */ 99249259Sdim#endif 100249259Sdim} *elf_file_t; 101249259Sdim 102249259Sdimstatic int link_elf_link_common_finish(linker_file_t); 103249259Sdimstatic int link_elf_link_preload(linker_class_t cls, 104249259Sdim const char*, linker_file_t*); 105249259Sdimstatic int link_elf_link_preload_finish(linker_file_t); 106249259Sdimstatic int link_elf_load_file(linker_class_t, const char*, linker_file_t*); 107249259Sdimstatic int link_elf_lookup_symbol(linker_file_t, const char*, 108249259Sdim c_linker_sym_t*); 109249259Sdimstatic int link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*); 110249259Sdimstatic int link_elf_search_symbol(linker_file_t, caddr_t value, 111249259Sdim c_linker_sym_t* sym, long* diffp); 112249259Sdim 113249259Sdimstatic void link_elf_unload_file(linker_file_t); 114249259Sdimstatic void link_elf_unload_preload(linker_file_t); 115249259Sdimstatic int link_elf_lookup_set(linker_file_t, const char *, 116249259Sdim void ***, void ***, int *); 117249259Sdimstatic int link_elf_each_function_name(linker_file_t, 118249259Sdim int (*)(const char *, void *), 119249259Sdim void *); 120249259Sdimstatic void link_elf_reloc_local(linker_file_t); 121249259Sdimstatic Elf_Addr elf_lookup(linker_file_t lf, Elf_Word symidx, int deps); 122249259Sdim 123249259Sdimstatic kobj_method_t link_elf_methods[] = { 124249259Sdim KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), 125249259Sdim KOBJMETHOD(linker_symbol_values, link_elf_symbol_values), 126249259Sdim KOBJMETHOD(linker_search_symbol, link_elf_search_symbol), 127249259Sdim KOBJMETHOD(linker_unload, link_elf_unload_file), 128249259Sdim KOBJMETHOD(linker_load_file, link_elf_load_file), 129249259Sdim KOBJMETHOD(linker_link_preload, link_elf_link_preload), 130249259Sdim KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), 131249259Sdim KOBJMETHOD(linker_lookup_set, link_elf_lookup_set), 132249259Sdim KOBJMETHOD(linker_each_function_name, link_elf_each_function_name), 133249259Sdim { 0, 0 } 134249259Sdim}; 135249259Sdim 136249259Sdimstatic struct linker_class link_elf_class = { 137249259Sdim#if ELF_TARG_CLASS == ELFCLASS32 138249259Sdim "elf32", 139249259Sdim#else 140249259Sdim "elf64", 141249259Sdim#endif 142249259Sdim link_elf_methods, sizeof(struct elf_file) 143249259Sdim}; 144249259Sdim 145249259Sdimstatic int parse_dynamic(elf_file_t ef); 146249259Sdimstatic int relocate_file(elf_file_t ef); 147249259Sdimstatic int link_elf_preload_parse_symbols(elf_file_t ef); 148249259Sdim 149249259Sdim#ifdef GDB 150249259Sdimstatic void r_debug_state(struct r_debug *dummy_one, 151249259Sdim struct link_map *dummy_two); 152249259Sdim 153249259Sdim/* 154249259Sdim * A list of loaded modules for GDB to use for loading symbols. 155249259Sdim */ 156249259Sdimstruct r_debug r_debug; 157249259Sdim 158249259Sdim#define GDB_STATE(s) r_debug.r_state = s; r_debug_state(NULL, NULL); 159249259Sdim 160249259Sdim/* 161249259Sdim * Function for the debugger to set a breakpoint on to gain control. 162249259Sdim */ 163249259Sdimstatic void 164249259Sdimr_debug_state(struct r_debug *dummy_one __unused, 165249259Sdim struct link_map *dummy_two __unused) 166249259Sdim{ 167249259Sdim} 168249259Sdim 169249259Sdimstatic void 170249259Sdimlink_elf_add_gdb(struct link_map *l) 171249259Sdim{ 172249259Sdim struct link_map *prev; 173249259Sdim 174249259Sdim l->l_next = NULL; 175249259Sdim 176249259Sdim if (r_debug.r_map == NULL) { 177249259Sdim /* Add first. */ 178249259Sdim l->l_prev = NULL; 179249259Sdim r_debug.r_map = l; 180249259Sdim } else { 181249259Sdim /* Append to list. */ 182249259Sdim for (prev = r_debug.r_map; prev->l_next != NULL; prev = prev->l_next) 183249259Sdim ; 184249259Sdim l->l_prev = prev; 185249259Sdim prev->l_next = l; 186249259Sdim } 187249259Sdim} 188249259Sdim 189249259Sdimstatic void 190249259Sdimlink_elf_delete_gdb(struct link_map *l) 191249259Sdim{ 192249259Sdim if (l->l_prev == NULL) { 193249259Sdim /* Remove first. */ 194249259Sdim if ((r_debug.r_map = l->l_next) != NULL) 195249259Sdim l->l_next->l_prev = NULL; 196249259Sdim } else { 197249259Sdim /* Remove any but first. */ 198249259Sdim if ((l->l_prev->l_next = l->l_next) != NULL) 199249259Sdim l->l_next->l_prev = l->l_prev; 200249259Sdim } 201249259Sdim} 202249259Sdim#endif /* GDB */ 203249259Sdim 204249259Sdim#ifdef __ia64__ 205249259SdimElf_Addr link_elf_get_gp(linker_file_t); 206249259Sdim#endif 207249259Sdim 208249259Sdim/* 209249259Sdim * The kernel symbol table starts here. 210249259Sdim */ 211249259Sdimextern struct _dynamic _DYNAMIC; 212249259Sdim 213249259Sdimstatic void 214249259Sdimlink_elf_error(const char *s) 215249259Sdim{ 216249259Sdim printf("kldload: %s\n", s); 217249259Sdim} 218249259Sdim 219249259Sdim/* 220249259Sdim * Actions performed after linking/loading both the preloaded kernel and any 221249259Sdim * modules; whether preloaded or dynamicly loaded. 222249259Sdim */ 223249259Sdimstatic int 224249259Sdimlink_elf_link_common_finish(linker_file_t lf) 225249259Sdim{ 226249259Sdim#ifdef GDB 227249259Sdim elf_file_t ef = (elf_file_t)lf; 228249259Sdim char *newfilename; 229249259Sdim#endif 230249259Sdim int error; 231249259Sdim 232249259Sdim /* Notify MD code that a module is being loaded. */ 233249259Sdim error = elf_cpu_load_file(lf); 234249259Sdim if (error) 235249259Sdim return (error); 236249259Sdim 237249259Sdim#ifdef GDB 238249259Sdim GDB_STATE(RT_ADD); 239249259Sdim ef->gdb.l_addr = lf->address; 240249259Sdim newfilename = malloc(strlen(lf->filename) + 1, M_LINKER, M_WAITOK); 241249259Sdim strcpy(newfilename, lf->filename); 242249259Sdim ef->gdb.l_name = newfilename; 243249259Sdim ef->gdb.l_ld = ef->dynamic; 244249259Sdim link_elf_add_gdb(&ef->gdb); 245249259Sdim GDB_STATE(RT_CONSISTENT); 246249259Sdim#endif 247249259Sdim 248249259Sdim return (0); 249249259Sdim} 250249259Sdim 251249259Sdimstatic void 252249259Sdimlink_elf_init(void* arg) 253249259Sdim{ 254249259Sdim Elf_Dyn *dp; 255249259Sdim caddr_t modptr, baseptr, sizeptr; 256249259Sdim elf_file_t ef; 257249259Sdim char *modname; 258249259Sdim 259249259Sdim linker_add_class(&link_elf_class); 260249259Sdim 261249259Sdim dp = (Elf_Dyn*) &_DYNAMIC; 262249259Sdim modname = NULL; 263249259Sdim modptr = preload_search_by_type("elf" __XSTRING(__ELF_WORD_SIZE) " kernel"); 264249259Sdim if (modptr == NULL) 265249259Sdim modptr = preload_search_by_type("elf kernel"); 266249259Sdim if (modptr) 267249259Sdim modname = (char *)preload_search_info(modptr, MODINFO_NAME); 268249259Sdim if (modname == NULL) 269249259Sdim modname = "kernel"; 270249259Sdim linker_kernel_file = linker_make_file(modname, &link_elf_class); 271249259Sdim if (linker_kernel_file == NULL) 272249259Sdim panic("link_elf_init: Can't create linker structures for kernel"); 273249259Sdim 274249259Sdim ef = (elf_file_t) linker_kernel_file; 275249259Sdim ef->preloaded = 1; 276249259Sdim ef->address = 0; 277249259Sdim#ifdef SPARSE_MAPPING 278249259Sdim ef->object = 0; 279249259Sdim#endif 280249259Sdim ef->dynamic = dp; 281249259Sdim 282249259Sdim if (dp) 283249259Sdim parse_dynamic(ef); 284249259Sdim linker_kernel_file->address = (caddr_t) KERNBASE; 285249259Sdim linker_kernel_file->size = -(intptr_t)linker_kernel_file->address; 286249259Sdim 287249259Sdim if (modptr) { 288249259Sdim ef->modptr = modptr; 289249259Sdim baseptr = preload_search_info(modptr, MODINFO_ADDR); 290249259Sdim if (baseptr) 291249259Sdim linker_kernel_file->address = *(caddr_t *)baseptr; 292249259Sdim sizeptr = preload_search_info(modptr, MODINFO_SIZE); 293249259Sdim if (sizeptr) 294249259Sdim linker_kernel_file->size = *(size_t *)sizeptr; 295249259Sdim } 296249259Sdim (void)link_elf_preload_parse_symbols(ef); 297249259Sdim 298249259Sdim#ifdef GDB 299249259Sdim r_debug.r_map = NULL; 300249259Sdim r_debug.r_brk = r_debug_state; 301249259Sdim r_debug.r_state = RT_CONSISTENT; 302249259Sdim#endif 303249259Sdim 304249259Sdim (void)link_elf_link_common_finish(linker_kernel_file); 305249259Sdim} 306249259Sdim 307249259SdimSYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); 308249259Sdim 309249259Sdimstatic int 310249259Sdimlink_elf_preload_parse_symbols(elf_file_t ef) 311249259Sdim{ 312249259Sdim caddr_t pointer; 313249259Sdim caddr_t ssym, esym, base; 314249259Sdim caddr_t strtab; 315249259Sdim int strcnt; 316249259Sdim Elf_Sym* symtab; 317249259Sdim int symcnt; 318249259Sdim 319249259Sdim if (ef->modptr == NULL) 320249259Sdim return 0; 321249259Sdim pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM); 322249259Sdim if (pointer == NULL) 323249259Sdim return 0; 324249259Sdim ssym = *(caddr_t *)pointer; 325249259Sdim pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM); 326249259Sdim if (pointer == NULL) 327249259Sdim return 0; 328249259Sdim esym = *(caddr_t *)pointer; 329249259Sdim 330249259Sdim base = ssym; 331249259Sdim 332249259Sdim symcnt = *(long *)base; 333249259Sdim base += sizeof(long); 334249259Sdim symtab = (Elf_Sym *)base; 335249259Sdim base += roundup(symcnt, sizeof(long)); 336249259Sdim 337249259Sdim if (base > esym || base < ssym) { 338249259Sdim printf("Symbols are corrupt!\n"); 339249259Sdim return EINVAL; 340249259Sdim } 341249259Sdim 342249259Sdim strcnt = *(long *)base; 343249259Sdim base += sizeof(long); 344249259Sdim strtab = base; 345249259Sdim base += roundup(strcnt, sizeof(long)); 346249259Sdim 347249259Sdim if (base > esym || base < ssym) { 348249259Sdim printf("Symbols are corrupt!\n"); 349249259Sdim return EINVAL; 350249259Sdim } 351249259Sdim 352249259Sdim ef->ddbsymtab = symtab; 353249259Sdim ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 354249259Sdim ef->ddbstrtab = strtab; 355249259Sdim ef->ddbstrcnt = strcnt; 356249259Sdim 357249259Sdim return 0; 358249259Sdim} 359249259Sdim 360249259Sdimstatic int 361249259Sdimparse_dynamic(elf_file_t ef) 362249259Sdim{ 363249259Sdim Elf_Dyn *dp; 364249259Sdim int plttype = DT_REL; 365249259Sdim 366249259Sdim for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 367249259Sdim switch (dp->d_tag) { 368249259Sdim case DT_HASH: 369249259Sdim { 370249259Sdim /* From src/libexec/rtld-elf/rtld.c */ 371249259Sdim const Elf_Hashelt *hashtab = (const Elf_Hashelt *) 372249259Sdim (ef->address + dp->d_un.d_ptr); 373249259Sdim ef->nbuckets = hashtab[0]; 374249259Sdim ef->nchains = hashtab[1]; 375249259Sdim ef->buckets = hashtab + 2; 376249259Sdim ef->chains = ef->buckets + ef->nbuckets; 377249259Sdim break; 378249259Sdim } 379249259Sdim case DT_STRTAB: 380249259Sdim ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); 381249259Sdim break; 382249259Sdim case DT_STRSZ: 383249259Sdim ef->strsz = dp->d_un.d_val; 384249259Sdim break; 385249259Sdim case DT_SYMTAB: 386249259Sdim ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); 387249259Sdim break; 388249259Sdim case DT_SYMENT: 389249259Sdim if (dp->d_un.d_val != sizeof(Elf_Sym)) 390249259Sdim return ENOEXEC; 391249259Sdim break; 392249259Sdim case DT_PLTGOT: 393249259Sdim ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); 394249259Sdim break; 395249259Sdim case DT_REL: 396249259Sdim ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 397249259Sdim break; 398249259Sdim case DT_RELSZ: 399249259Sdim ef->relsize = dp->d_un.d_val; 400249259Sdim break; 401249259Sdim case DT_RELENT: 402249259Sdim if (dp->d_un.d_val != sizeof(Elf_Rel)) 403249259Sdim return ENOEXEC; 404249259Sdim break; 405249259Sdim case DT_JMPREL: 406249259Sdim ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); 407249259Sdim break; 408249259Sdim case DT_PLTRELSZ: 409249259Sdim ef->pltrelsize = dp->d_un.d_val; 410249259Sdim break; 411249259Sdim case DT_RELA: 412249259Sdim ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); 413249259Sdim break; 414249259Sdim case DT_RELASZ: 415249259Sdim ef->relasize = dp->d_un.d_val; 416249259Sdim break; 417249259Sdim case DT_RELAENT: 418249259Sdim if (dp->d_un.d_val != sizeof(Elf_Rela)) 419249259Sdim return ENOEXEC; 420249259Sdim break; 421249259Sdim case DT_PLTREL: 422249259Sdim plttype = dp->d_un.d_val; 423249259Sdim if (plttype != DT_REL && plttype != DT_RELA) 424249259Sdim return ENOEXEC; 425249259Sdim break; 426249259Sdim#ifdef GDB 427249259Sdim case DT_DEBUG: 428249259Sdim dp->d_un.d_ptr = (Elf_Addr) &r_debug; 429249259Sdim break; 430249259Sdim#endif 431249259Sdim } 432249259Sdim } 433249259Sdim 434249259Sdim if (plttype == DT_RELA) { 435249259Sdim ef->pltrela = (const Elf_Rela *) ef->pltrel; 436249259Sdim ef->pltrel = NULL; 437249259Sdim ef->pltrelasize = ef->pltrelsize; 438249259Sdim ef->pltrelsize = 0; 439249259Sdim } 440249259Sdim 441249259Sdim ef->ddbsymtab = ef->symtab; 442249259Sdim ef->ddbsymcnt = ef->nchains; 443249259Sdim ef->ddbstrtab = ef->strtab; 444249259Sdim ef->ddbstrcnt = ef->strsz; 445249259Sdim 446249259Sdim return 0; 447249259Sdim} 448249259Sdim 449249259Sdimstatic int 450249259Sdimlink_elf_link_preload(linker_class_t cls, 451249259Sdim const char* filename, linker_file_t *result) 452249259Sdim{ 453249259Sdim caddr_t modptr, baseptr, sizeptr, dynptr; 454249259Sdim char *type; 455249259Sdim elf_file_t ef; 456249259Sdim linker_file_t lf; 457249259Sdim int error; 458249259Sdim vm_offset_t dp; 459249259Sdim 460249259Sdim /* Look to see if we have the file preloaded */ 461249259Sdim modptr = preload_search_by_name(filename); 462249259Sdim if (modptr == NULL) 463249259Sdim return ENOENT; 464249259Sdim 465249259Sdim type = (char *)preload_search_info(modptr, MODINFO_TYPE); 466249259Sdim baseptr = preload_search_info(modptr, MODINFO_ADDR); 467249259Sdim sizeptr = preload_search_info(modptr, MODINFO_SIZE); 468249259Sdim dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC); 469249259Sdim if (type == NULL || 470249259Sdim (strcmp(type, "elf" __XSTRING(__ELF_WORD_SIZE) " module") != 0 && 471249259Sdim strcmp(type, "elf module") != 0)) 472249259Sdim return (EFTYPE); 473249259Sdim if (baseptr == NULL || sizeptr == NULL || dynptr == NULL) 474249259Sdim return (EINVAL); 475249259Sdim 476249259Sdim lf = linker_make_file(filename, &link_elf_class); 477249259Sdim if (lf == NULL) { 478249259Sdim return ENOMEM; 479 } 480 481 ef = (elf_file_t) lf; 482 ef->preloaded = 1; 483 ef->modptr = modptr; 484 ef->address = *(caddr_t *)baseptr; 485#ifdef SPARSE_MAPPING 486 ef->object = 0; 487#endif 488 dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; 489 ef->dynamic = (Elf_Dyn *)dp; 490 lf->address = ef->address; 491 lf->size = *(size_t *)sizeptr; 492 493 error = parse_dynamic(ef); 494 if (error) { 495 linker_file_unload(lf, LINKER_UNLOAD_FORCE); 496 return error; 497 } 498 link_elf_reloc_local(lf); 499 *result = lf; 500 return (0); 501} 502 503static int 504link_elf_link_preload_finish(linker_file_t lf) 505{ 506 elf_file_t ef; 507 int error; 508 509 ef = (elf_file_t) lf; 510#if 0 /* this will be more trouble than it's worth for now */ 511 for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 512 if (dp->d_tag != DT_NEEDED) 513 continue; 514 modname = ef->strtab + dp->d_un.d_val; 515 error = linker_load_module(modname, lf); 516 if (error) 517 goto out; 518 } 519#endif 520 error = relocate_file(ef); 521 if (error) 522 return error; 523 (void)link_elf_preload_parse_symbols(ef); 524 525 return (link_elf_link_common_finish(lf)); 526} 527 528static int 529link_elf_load_file(linker_class_t cls, const char* filename, 530 linker_file_t* result) 531{ 532 struct nameidata nd; 533 struct thread* td = curthread; /* XXX */ 534 Elf_Ehdr *hdr; 535 caddr_t firstpage; 536 int nbytes, i; 537 Elf_Phdr *phdr; 538 Elf_Phdr *phlimit; 539 Elf_Phdr *segs[2]; 540 int nsegs; 541 Elf_Phdr *phdyn; 542 Elf_Phdr *phphdr; 543 caddr_t mapbase; 544 size_t mapsize; 545 Elf_Off base_offset; 546 Elf_Addr base_vaddr; 547 Elf_Addr base_vlimit; 548 int error = 0; 549 int resid, flags; 550 elf_file_t ef; 551 linker_file_t lf; 552 Elf_Shdr *shdr; 553 int symtabindex; 554 int symstrindex; 555 int symcnt; 556 int strcnt; 557 558 GIANT_REQUIRED; 559 560 shdr = NULL; 561 lf = NULL; 562 563 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); 564 flags = FREAD; 565 error = vn_open(&nd, &flags, 0, -1); 566 if (error) 567 return error; 568 NDFREE(&nd, NDF_ONLY_PNBUF); 569#ifdef MAC 570 error = mac_check_kld_load(curthread->td_ucred, nd.ni_vp); 571 if (error) { 572 firstpage = NULL; 573 goto out; 574 } 575#endif 576 577 /* 578 * Read the elf header from the file. 579 */ 580 firstpage = malloc(PAGE_SIZE, M_LINKER, M_WAITOK); 581 if (firstpage == NULL) { 582 error = ENOMEM; 583 goto out; 584 } 585 hdr = (Elf_Ehdr *)firstpage; 586 error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0, 587 UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 588 &resid, td); 589 nbytes = PAGE_SIZE - resid; 590 if (error) 591 goto out; 592 593 if (!IS_ELF(*hdr)) { 594 error = ENOEXEC; 595 goto out; 596 } 597 598 if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS 599 || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { 600 link_elf_error("Unsupported file layout"); 601 error = ENOEXEC; 602 goto out; 603 } 604 if (hdr->e_ident[EI_VERSION] != EV_CURRENT 605 || hdr->e_version != EV_CURRENT) { 606 link_elf_error("Unsupported file version"); 607 error = ENOEXEC; 608 goto out; 609 } 610 if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) { 611 link_elf_error("Unsupported file type"); 612 error = ENOEXEC; 613 goto out; 614 } 615 if (hdr->e_machine != ELF_TARG_MACH) { 616 link_elf_error("Unsupported machine"); 617 error = ENOEXEC; 618 goto out; 619 } 620 621 /* 622 * We rely on the program header being in the first page. This is 623 * not strictly required by the ABI specification, but it seems to 624 * always true in practice. And, it simplifies things considerably. 625 */ 626 if (!((hdr->e_phentsize == sizeof(Elf_Phdr)) && 627 (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) && 628 (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= nbytes))) 629 link_elf_error("Unreadable program headers"); 630 631 /* 632 * Scan the program header entries, and save key information. 633 * 634 * We rely on there being exactly two load segments, text and data, 635 * in that order. 636 */ 637 phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff); 638 phlimit = phdr + hdr->e_phnum; 639 nsegs = 0; 640 phdyn = NULL; 641 phphdr = NULL; 642 while (phdr < phlimit) { 643 switch (phdr->p_type) { 644 645 case PT_LOAD: 646 if (nsegs == 2) { 647 link_elf_error("Too many sections"); 648 error = ENOEXEC; 649 goto out; 650 } 651 /* 652 * XXX: We just trust they come in right order ?? 653 */ 654 segs[nsegs] = phdr; 655 ++nsegs; 656 break; 657 658 case PT_PHDR: 659 phphdr = phdr; 660 break; 661 662 case PT_DYNAMIC: 663 phdyn = phdr; 664 break; 665 666 case PT_INTERP: 667 link_elf_error("Unsupported file type"); 668 error = ENOEXEC; 669 goto out; 670 } 671 672 ++phdr; 673 } 674 if (phdyn == NULL) { 675 link_elf_error("Object is not dynamically-linked"); 676 error = ENOEXEC; 677 goto out; 678 } 679 if (nsegs != 2) { 680 link_elf_error("Too few sections"); 681 error = ENOEXEC; 682 goto out; 683 } 684 685 /* 686 * Allocate the entire address space of the object, to stake out our 687 * contiguous region, and to establish the base address for relocation. 688 */ 689 base_offset = trunc_page(segs[0]->p_offset); 690 base_vaddr = trunc_page(segs[0]->p_vaddr); 691 base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz); 692 mapsize = base_vlimit - base_vaddr; 693 694 lf = linker_make_file(filename, &link_elf_class); 695 if (!lf) { 696 error = ENOMEM; 697 goto out; 698 } 699 700 ef = (elf_file_t) lf; 701#ifdef SPARSE_MAPPING 702 ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); 703 if (ef->object == NULL) { 704 error = ENOMEM; 705 goto out; 706 } 707 vm_object_reference(ef->object); 708 ef->address = (caddr_t) vm_map_min(kernel_map); 709 error = vm_map_find(kernel_map, ef->object, 0, 710 (vm_offset_t *) &ef->address, 711 mapsize, 1, 712 VM_PROT_ALL, VM_PROT_ALL, 0); 713#ifdef SPARSE_MAPPING 714 /* 715 * Wire down the pages 716 */ 717 if (error == 0) 718 error = vm_map_wire(kernel_map, (vm_offset_t) ef->address, 719 (vm_offset_t) ef->address + mapsize, 720 VM_MAP_WIRE_SYSTEM|VM_MAP_WIRE_NOHOLES); 721#endif 722 if (error) { 723 vm_object_deallocate(ef->object); 724 ef->object = 0; 725 goto out; 726 } 727#else 728 ef->address = malloc(mapsize, M_LINKER, M_WAITOK); 729 if (!ef->address) { 730 error = ENOMEM; 731 goto out; 732 } 733#endif 734 mapbase = ef->address; 735 736 /* 737 * Read the text and data sections and zero the bss. 738 */ 739 for (i = 0; i < 2; i++) { 740 caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; 741 error = vn_rdwr(UIO_READ, nd.ni_vp, 742 segbase, segs[i]->p_filesz, segs[i]->p_offset, 743 UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 744 &resid, td); 745 if (error) { 746 goto out; 747 } 748 bzero(segbase + segs[i]->p_filesz, 749 segs[i]->p_memsz - segs[i]->p_filesz); 750 } 751 752#ifdef GPROF 753 /* Update profiling information with the new text segment. */ 754 kmupetext((uintfptr_t)(mapbase + segs[0]->p_vaddr - base_vaddr + 755 segs[0]->p_memsz)); 756#endif 757 758 ef->dynamic = (Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); 759 760 lf->address = ef->address; 761 lf->size = mapsize; 762 763 error = parse_dynamic(ef); 764 if (error) 765 goto out; 766 link_elf_reloc_local(lf); 767 768 error = linker_load_dependencies(lf); 769 if (error) 770 goto out; 771#if 0 /* this will be more trouble than it's worth for now */ 772 for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 773 if (dp->d_tag != DT_NEEDED) 774 continue; 775 modname = ef->strtab + dp->d_un.d_val; 776 error = linker_load_module(modname, lf); 777 if (error) 778 goto out; 779 } 780#endif 781 error = relocate_file(ef); 782 if (error) 783 goto out; 784 785 /* Try and load the symbol table if it's present. (you can strip it!) */ 786 nbytes = hdr->e_shnum * hdr->e_shentsize; 787 if (nbytes == 0 || hdr->e_shoff == 0) 788 goto nosyms; 789 shdr = malloc(nbytes, M_LINKER, M_WAITOK | M_ZERO); 790 if (shdr == NULL) { 791 error = ENOMEM; 792 goto out; 793 } 794 error = vn_rdwr(UIO_READ, nd.ni_vp, 795 (caddr_t)shdr, nbytes, hdr->e_shoff, 796 UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 797 &resid, td); 798 if (error) 799 goto out; 800 symtabindex = -1; 801 symstrindex = -1; 802 for (i = 0; i < hdr->e_shnum; i++) { 803 if (shdr[i].sh_type == SHT_SYMTAB) { 804 symtabindex = i; 805 symstrindex = shdr[i].sh_link; 806 } 807 } 808 if (symtabindex < 0 || symstrindex < 0) 809 goto nosyms; 810 811 symcnt = shdr[symtabindex].sh_size; 812 ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK); 813 strcnt = shdr[symstrindex].sh_size; 814 ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK); 815 816 if (ef->symbase == NULL || ef->strbase == NULL) { 817 error = ENOMEM; 818 goto out; 819 } 820 error = vn_rdwr(UIO_READ, nd.ni_vp, 821 ef->symbase, symcnt, shdr[symtabindex].sh_offset, 822 UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 823 &resid, td); 824 if (error) 825 goto out; 826 error = vn_rdwr(UIO_READ, nd.ni_vp, 827 ef->strbase, strcnt, shdr[symstrindex].sh_offset, 828 UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 829 &resid, td); 830 if (error) 831 goto out; 832 833 ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); 834 ef->ddbsymtab = (const Elf_Sym *)ef->symbase; 835 ef->ddbstrcnt = strcnt; 836 ef->ddbstrtab = ef->strbase; 837 838 error = link_elf_link_common_finish(lf); 839 if (error) 840 goto out; 841 842nosyms: 843 844 *result = lf; 845 846out: 847 if (error && lf) 848 linker_file_unload(lf, LINKER_UNLOAD_FORCE); 849 if (shdr) 850 free(shdr, M_LINKER); 851 if (firstpage) 852 free(firstpage, M_LINKER); 853 VOP_UNLOCK(nd.ni_vp, 0, td); 854 vn_close(nd.ni_vp, FREAD, td->td_ucred, td); 855 856 return error; 857} 858 859static void 860link_elf_unload_file(linker_file_t file) 861{ 862 elf_file_t ef = (elf_file_t) file; 863 864#ifdef GDB 865 if (ef->gdb.l_ld) { 866 GDB_STATE(RT_DELETE); 867 free((void *)(uintptr_t)ef->gdb.l_name, M_LINKER); 868 link_elf_delete_gdb(&ef->gdb); 869 GDB_STATE(RT_CONSISTENT); 870 } 871#endif 872 873 /* Notify MD code that a module is being unloaded. */ 874 elf_cpu_unload_file(file); 875 876 if (ef->preloaded) { 877 link_elf_unload_preload(file); 878 return; 879 } 880 881#ifdef SPARSE_MAPPING 882 if (ef->object) { 883 /* 884 * Unwire the pages 885 */ 886 vm_map_unwire(kernel_map, 887 (vm_offset_t) ef->address, 888 (vm_offset_t) ef->address 889 + (ef->object->size << PAGE_SHIFT), 890 VM_MAP_WIRE_SYSTEM|VM_MAP_WIRE_NOHOLES); 891 vm_map_remove(kernel_map, (vm_offset_t) ef->address, 892 (vm_offset_t) ef->address 893 + (ef->object->size << PAGE_SHIFT)); 894 vm_object_deallocate(ef->object); 895 } 896#else 897 if (ef->address) 898 free(ef->address, M_LINKER); 899#endif 900 if (ef->symbase) 901 free(ef->symbase, M_LINKER); 902 if (ef->strbase) 903 free(ef->strbase, M_LINKER); 904} 905 906static void 907link_elf_unload_preload(linker_file_t file) 908{ 909 if (file->filename) 910 preload_delete_name(file->filename); 911} 912 913static const char * 914symbol_name(elf_file_t ef, Elf_Word r_info) 915{ 916 const Elf_Sym *ref; 917 918 if (ELF_R_SYM(r_info)) { 919 ref = ef->symtab + ELF_R_SYM(r_info); 920 return ef->strtab + ref->st_name; 921 } else 922 return NULL; 923} 924 925static int 926relocate_file(elf_file_t ef) 927{ 928 const Elf_Rel *rellim; 929 const Elf_Rel *rel; 930 const Elf_Rela *relalim; 931 const Elf_Rela *rela; 932 const char *symname; 933 934 /* Perform relocations without addend if there are any: */ 935 rel = ef->rel; 936 if (rel) { 937 rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize); 938 while (rel < rellim) { 939 if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel, ELF_RELOC_REL, 940 elf_lookup)) { 941 symname = symbol_name(ef, rel->r_info); 942 printf("link_elf: symbol %s undefined\n", symname); 943 return ENOENT; 944 } 945 rel++; 946 } 947 } 948 949 /* Perform relocations with addend if there are any: */ 950 rela = ef->rela; 951 if (rela) { 952 relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize); 953 while (rela < relalim) { 954 if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela, ELF_RELOC_RELA, 955 elf_lookup)) { 956 symname = symbol_name(ef, rela->r_info); 957 printf("link_elf: symbol %s undefined\n", symname); 958 return ENOENT; 959 } 960 rela++; 961 } 962 } 963 964 /* Perform PLT relocations without addend if there are any: */ 965 rel = ef->pltrel; 966 if (rel) { 967 rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize); 968 while (rel < rellim) { 969 if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel, ELF_RELOC_REL, 970 elf_lookup)) { 971 symname = symbol_name(ef, rel->r_info); 972 printf("link_elf: symbol %s undefined\n", symname); 973 return ENOENT; 974 } 975 rel++; 976 } 977 } 978 979 /* Perform relocations with addend if there are any: */ 980 rela = ef->pltrela; 981 if (rela) { 982 relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize); 983 while (rela < relalim) { 984 if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela, ELF_RELOC_RELA, 985 elf_lookup)) { 986 symname = symbol_name(ef, rela->r_info); 987 printf("link_elf: symbol %s undefined\n", symname); 988 return ENOENT; 989 } 990 rela++; 991 } 992 } 993 994 return 0; 995} 996 997/* 998 * Hash function for symbol table lookup. Don't even think about changing 999 * this. It is specified by the System V ABI. 1000 */ 1001static unsigned long 1002elf_hash(const char *name) 1003{ 1004 const unsigned char *p = (const unsigned char *) name; 1005 unsigned long h = 0; 1006 unsigned long g; 1007 1008 while (*p != '\0') { 1009 h = (h << 4) + *p++; 1010 if ((g = h & 0xf0000000) != 0) 1011 h ^= g >> 24; 1012 h &= ~g; 1013 } 1014 return h; 1015} 1016 1017static int 1018link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym) 1019{ 1020 elf_file_t ef = (elf_file_t) lf; 1021 unsigned long symnum; 1022 const Elf_Sym* symp; 1023 const char *strp; 1024 unsigned long hash; 1025 int i; 1026 1027 /* First, search hashed global symbols */ 1028 hash = elf_hash(name); 1029 symnum = ef->buckets[hash % ef->nbuckets]; 1030 1031 while (symnum != STN_UNDEF) { 1032 if (symnum >= ef->nchains) { 1033 printf("link_elf_lookup_symbol: corrupt symbol table\n"); 1034 return ENOENT; 1035 } 1036 1037 symp = ef->symtab + symnum; 1038 if (symp->st_name == 0) { 1039 printf("link_elf_lookup_symbol: corrupt symbol table\n"); 1040 return ENOENT; 1041 } 1042 1043 strp = ef->strtab + symp->st_name; 1044 1045 if (strcmp(name, strp) == 0) { 1046 if (symp->st_shndx != SHN_UNDEF || 1047 (symp->st_value != 0 && 1048 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 1049 *sym = (c_linker_sym_t) symp; 1050 return 0; 1051 } else 1052 return ENOENT; 1053 } 1054 1055 symnum = ef->chains[symnum]; 1056 } 1057 1058 /* If we have not found it, look at the full table (if loaded) */ 1059 if (ef->symtab == ef->ddbsymtab) 1060 return ENOENT; 1061 1062 /* Exhaustive search */ 1063 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 1064 strp = ef->ddbstrtab + symp->st_name; 1065 if (strcmp(name, strp) == 0) { 1066 if (symp->st_shndx != SHN_UNDEF || 1067 (symp->st_value != 0 && 1068 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { 1069 *sym = (c_linker_sym_t) symp; 1070 return 0; 1071 } else 1072 return ENOENT; 1073 } 1074 } 1075 1076 return ENOENT; 1077} 1078 1079static int 1080link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, linker_symval_t* symval) 1081{ 1082 elf_file_t ef = (elf_file_t) lf; 1083 const Elf_Sym* es = (const Elf_Sym*) sym; 1084 1085 if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) { 1086 symval->name = ef->strtab + es->st_name; 1087 symval->value = (caddr_t) ef->address + es->st_value; 1088 symval->size = es->st_size; 1089 return 0; 1090 } 1091 if (ef->symtab == ef->ddbsymtab) 1092 return ENOENT; 1093 if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) { 1094 symval->name = ef->ddbstrtab + es->st_name; 1095 symval->value = (caddr_t) ef->address + es->st_value; 1096 symval->size = es->st_size; 1097 return 0; 1098 } 1099 return ENOENT; 1100} 1101 1102static int 1103link_elf_search_symbol(linker_file_t lf, caddr_t value, 1104 c_linker_sym_t* sym, long* diffp) 1105{ 1106 elf_file_t ef = (elf_file_t) lf; 1107 u_long off = (uintptr_t) (void *) value; 1108 u_long diff = off; 1109 u_long st_value; 1110 const Elf_Sym* es; 1111 const Elf_Sym* best = 0; 1112 int i; 1113 1114 for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) { 1115 if (es->st_name == 0) 1116 continue; 1117 st_value = es->st_value + (uintptr_t) (void *) ef->address; 1118 if (off >= st_value) { 1119 if (off - st_value < diff) { 1120 diff = off - st_value; 1121 best = es; 1122 if (diff == 0) 1123 break; 1124 } else if (off - st_value == diff) { 1125 best = es; 1126 } 1127 } 1128 } 1129 if (best == 0) 1130 *diffp = off; 1131 else 1132 *diffp = diff; 1133 *sym = (c_linker_sym_t) best; 1134 1135 return 0; 1136} 1137 1138/* 1139 * Look up a linker set on an ELF system. 1140 */ 1141static int 1142link_elf_lookup_set(linker_file_t lf, const char *name, 1143 void ***startp, void ***stopp, int *countp) 1144{ 1145 c_linker_sym_t sym; 1146 linker_symval_t symval; 1147 char *setsym; 1148 void **start, **stop; 1149 int len, error = 0, count; 1150 1151 len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */ 1152 setsym = malloc(len, M_LINKER, M_WAITOK); 1153 if (setsym == NULL) 1154 return ENOMEM; 1155 1156 /* get address of first entry */ 1157 snprintf(setsym, len, "%s%s", "__start_set_", name); 1158 error = link_elf_lookup_symbol(lf, setsym, &sym); 1159 if (error) 1160 goto out; 1161 link_elf_symbol_values(lf, sym, &symval); 1162 if (symval.value == 0) { 1163 error = ESRCH; 1164 goto out; 1165 } 1166 start = (void **)symval.value; 1167 1168 /* get address of last entry */ 1169 snprintf(setsym, len, "%s%s", "__stop_set_", name); 1170 error = link_elf_lookup_symbol(lf, setsym, &sym); 1171 if (error) 1172 goto out; 1173 link_elf_symbol_values(lf, sym, &symval); 1174 if (symval.value == 0) { 1175 error = ESRCH; 1176 goto out; 1177 } 1178 stop = (void **)symval.value; 1179 1180 /* and the number of entries */ 1181 count = stop - start; 1182 1183 /* and copy out */ 1184 if (startp) 1185 *startp = start; 1186 if (stopp) 1187 *stopp = stop; 1188 if (countp) 1189 *countp = count; 1190 1191out: 1192 free(setsym, M_LINKER); 1193 return error; 1194} 1195 1196static int 1197link_elf_each_function_name(linker_file_t file, 1198 int (*callback)(const char *, void *), void *opaque) { 1199 elf_file_t ef = (elf_file_t)file; 1200 const Elf_Sym* symp; 1201 int i, error; 1202 1203 /* Exhaustive search */ 1204 for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 1205 if (symp->st_value != 0 && 1206 ELF_ST_TYPE(symp->st_info) == STT_FUNC) { 1207 error = callback(ef->ddbstrtab + symp->st_name, opaque); 1208 if (error) 1209 return (error); 1210 } 1211 } 1212 return (0); 1213} 1214 1215#ifdef __ia64__ 1216/* 1217 * Each KLD has its own GP. The GP value for each load module is given by 1218 * DT_PLTGOT on ia64. We need GP to construct function descriptors, but 1219 * don't have direct access to the ELF file structure. The link_elf_get_gp() 1220 * function returns the GP given a pointer to a generic linker file struct. 1221 */ 1222Elf_Addr 1223link_elf_get_gp(linker_file_t lf) 1224{ 1225 elf_file_t ef = (elf_file_t)lf; 1226 return (Elf_Addr)ef->got; 1227} 1228#endif 1229 1230const Elf_Sym * 1231elf_get_sym(linker_file_t lf, Elf_Word symidx) 1232{ 1233 elf_file_t ef = (elf_file_t)lf; 1234 1235 if (symidx >= ef->nchains) 1236 return (NULL); 1237 return (ef->symtab + symidx); 1238} 1239 1240const char * 1241elf_get_symname(linker_file_t lf, Elf_Word symidx) 1242{ 1243 elf_file_t ef = (elf_file_t)lf; 1244 const Elf_Sym *sym; 1245 1246 if (symidx >= ef->nchains) 1247 return (NULL); 1248 sym = ef->symtab + symidx; 1249 return (ef->strtab + sym->st_name); 1250} 1251 1252/* 1253 * Symbol lookup function that can be used when the symbol index is known (ie 1254 * in relocations). It uses the symbol index instead of doing a fully fledged 1255 * hash table based lookup when such is valid. For example for local symbols. 1256 * This is not only more efficient, it's also more correct. It's not always 1257 * the case that the symbol can be found through the hash table. 1258 */ 1259static Elf_Addr 1260elf_lookup(linker_file_t lf, Elf_Word symidx, int deps) 1261{ 1262 elf_file_t ef = (elf_file_t)lf; 1263 const Elf_Sym *sym; 1264 const char *symbol; 1265 1266 /* Don't even try to lookup the symbol if the index is bogus. */ 1267 if (symidx >= ef->nchains) 1268 return (0); 1269 1270 sym = ef->symtab + symidx; 1271 1272 /* 1273 * Don't do a full lookup when the symbol is local. It may even 1274 * fail because it may not be found through the hash table. 1275 */ 1276 if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 1277 /* Force lookup failure when we have an insanity. */ 1278 if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0) 1279 return (0); 1280 return ((Elf_Addr)ef->address + sym->st_value); 1281 } 1282 1283 /* 1284 * XXX we can avoid doing a hash table based lookup for global 1285 * symbols as well. This however is not always valid, so we'll 1286 * just do it the hard way for now. Performance tweaks can 1287 * always be added. 1288 */ 1289 1290 symbol = ef->strtab + sym->st_name; 1291 1292 /* Force a lookup failure if the symbol name is bogus. */ 1293 if (*symbol == 0) 1294 return (0); 1295 1296 return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps)); 1297} 1298 1299static void 1300link_elf_reloc_local(linker_file_t lf) 1301{ 1302 const Elf_Rel *rellim; 1303 const Elf_Rel *rel; 1304 const Elf_Rela *relalim; 1305 const Elf_Rela *rela; 1306 elf_file_t ef = (elf_file_t)lf; 1307 1308 /* Perform relocations without addend if there are any: */ 1309 if ((rel = ef->rel) != NULL) { 1310 rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize); 1311 while (rel < rellim) { 1312 elf_reloc_local(lf, (Elf_Addr)ef->address, rel, ELF_RELOC_REL, 1313 elf_lookup); 1314 rel++; 1315 } 1316 } 1317 1318 /* Perform relocations with addend if there are any: */ 1319 if ((rela = ef->rela) != NULL) { 1320 relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize); 1321 while (rela < relalim) { 1322 elf_reloc_local(lf, (Elf_Addr)ef->address, rela, ELF_RELOC_RELA, 1323 elf_lookup); 1324 rela++; 1325 } 1326 } 1327} 1328