1a4f67738SDoug Rabson /*- 28a36da99SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 38a36da99SPedro F. Giffuni * 4326e27d8SDoug Rabson * Copyright (c) 1998-2000 Doug Rabson 5e9eabf59SPeter Wemm * Copyright (c) 2004 Peter Wemm 6a4f67738SDoug Rabson * All rights reserved. 7a4f67738SDoug Rabson * 8a4f67738SDoug Rabson * Redistribution and use in source and binary forms, with or without 9a4f67738SDoug Rabson * modification, are permitted provided that the following conditions 10a4f67738SDoug Rabson * are met: 11a4f67738SDoug Rabson * 1. Redistributions of source code must retain the above copyright 12a4f67738SDoug Rabson * notice, this list of conditions and the following disclaimer. 13a4f67738SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 14a4f67738SDoug Rabson * notice, this list of conditions and the following disclaimer in the 15a4f67738SDoug Rabson * documentation and/or other materials provided with the distribution. 16a4f67738SDoug Rabson * 17a4f67738SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18a4f67738SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19a4f67738SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20a4f67738SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21a4f67738SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22a4f67738SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23a4f67738SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24a4f67738SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25a4f67738SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26a4f67738SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27a4f67738SDoug Rabson * SUCH DAMAGE. 28a4f67738SDoug Rabson */ 29a4f67738SDoug Rabson 30677b542eSDavid E. O'Brien #include <sys/cdefs.h> 31677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 32677b542eSDavid E. O'Brien 33326e27d8SDoug Rabson #include "opt_ddb.h" 34326e27d8SDoug Rabson 35a4f67738SDoug Rabson #include <sys/param.h> 36a4f67738SDoug Rabson #include <sys/systm.h> 37fb919e4dSMark Murray #include <sys/kernel.h> 38fb919e4dSMark Murray #include <sys/lock.h> 39a4f67738SDoug Rabson #include <sys/malloc.h> 40c0b824f9SDima Dorfman #include <sys/mutex.h> 4162d615d5SJohn Baldwin #include <sys/mount.h> 42a4f67738SDoug Rabson #include <sys/proc.h> 43a4f67738SDoug Rabson #include <sys/namei.h> 44a4f67738SDoug Rabson #include <sys/fcntl.h> 45a4f67738SDoug Rabson #include <sys/vnode.h> 46a4f67738SDoug Rabson #include <sys/linker.h> 47fb919e4dSMark Murray 48a4f67738SDoug Rabson #include <machine/elf.h> 49a4f67738SDoug Rabson 50eddfbb76SRobert Watson #include <net/vnet.h> 51eddfbb76SRobert Watson 52aed55708SRobert Watson #include <security/mac/mac_framework.h> 53aed55708SRobert Watson 54fe3db7c7SDoug Rabson #include <vm/vm.h> 55fe3db7c7SDoug Rabson #include <vm/vm_param.h> 56fe3db7c7SDoug Rabson #include <vm/vm_object.h> 57fe3db7c7SDoug Rabson #include <vm/vm_kern.h> 58fe3db7c7SDoug Rabson #include <vm/vm_extern.h> 59fe3db7c7SDoug Rabson #include <vm/pmap.h> 60fe3db7c7SDoug Rabson #include <vm/vm_map.h> 61fb919e4dSMark Murray 62f9980387SPeter Wemm #include <sys/link_elf.h> 63fe3db7c7SDoug Rabson 64a2024a3eSJohn Birrell #ifdef DDB_CTF 65d9db5225SCraig Rodrigues #include <sys/zlib.h> 66a2024a3eSJohn Birrell #endif 67a2024a3eSJohn Birrell 68326e27d8SDoug Rabson #include "linker_if.h" 69a4f67738SDoug Rabson 70e9eabf59SPeter Wemm typedef struct { 71e9eabf59SPeter Wemm void *addr; 7220947801SPeter Wemm Elf_Off size; 73e9eabf59SPeter Wemm int flags; 74e9eabf59SPeter Wemm int sec; /* Original section */ 75e9eabf59SPeter Wemm char *name; 76e9eabf59SPeter Wemm } Elf_progent; 77e9eabf59SPeter Wemm 78e9eabf59SPeter Wemm typedef struct { 79e9eabf59SPeter Wemm Elf_Rel *rel; 8020947801SPeter Wemm int nrel; 81e9eabf59SPeter Wemm int sec; 82e9eabf59SPeter Wemm } Elf_relent; 83e9eabf59SPeter Wemm 84e9eabf59SPeter Wemm typedef struct { 85e9eabf59SPeter Wemm Elf_Rela *rela; 8620947801SPeter Wemm int nrela; 87e9eabf59SPeter Wemm int sec; 88e9eabf59SPeter Wemm } Elf_relaent; 89e9eabf59SPeter Wemm 90e9eabf59SPeter Wemm 91a4f67738SDoug Rabson typedef struct elf_file { 92326e27d8SDoug Rabson struct linker_file lf; /* Common fields */ 9320947801SPeter Wemm 9470b7ffeeSIan Dowse int preloaded; 95fe3db7c7SDoug Rabson caddr_t address; /* Relocation address */ 96fe3db7c7SDoug Rabson vm_object_t object; /* VM object to hold file pages */ 97e9eabf59SPeter Wemm Elf_Shdr *e_shdr; 98e9eabf59SPeter Wemm 99e9eabf59SPeter Wemm Elf_progent *progtab; 100d821d364SPedro F. Giffuni u_int nprogtab; 101e9eabf59SPeter Wemm 102e9eabf59SPeter Wemm Elf_relaent *relatab; 103d821d364SPedro F. Giffuni u_int nrelatab; 104e9eabf59SPeter Wemm 105e9eabf59SPeter Wemm Elf_relent *reltab; 106b474c780SDavid E. O'Brien int nreltab; 107e9eabf59SPeter Wemm 108e9eabf59SPeter Wemm Elf_Sym *ddbsymtab; /* The symbol table we are using */ 1092d636ab0SPeter Wemm long ddbsymcnt; /* Number of symbols */ 1102d636ab0SPeter Wemm caddr_t ddbstrtab; /* String table */ 1112d636ab0SPeter Wemm long ddbstrcnt; /* number of bytes in string table */ 112e9eabf59SPeter Wemm 113e9eabf59SPeter Wemm caddr_t shstrtab; /* Section name string table */ 114e9eabf59SPeter Wemm long shstrcnt; /* number of bytes in string table */ 115e9eabf59SPeter Wemm 116a2024a3eSJohn Birrell caddr_t ctftab; /* CTF table */ 117a2024a3eSJohn Birrell long ctfcnt; /* number of bytes in CTF table */ 118a2024a3eSJohn Birrell caddr_t ctfoff; /* CTF offset table */ 119a2024a3eSJohn Birrell caddr_t typoff; /* Type offset table */ 120a2024a3eSJohn Birrell long typlen; /* Number of type entries. */ 121a2024a3eSJohn Birrell 122a4f67738SDoug Rabson } *elf_file_t; 123a4f67738SDoug Rabson 124a2024a3eSJohn Birrell #include <kern/kern_ctf.c> 125a2024a3eSJohn Birrell 12654823af2SPeter Wemm static int link_elf_link_preload(linker_class_t cls, 127326e27d8SDoug Rabson const char *, linker_file_t *); 12854823af2SPeter Wemm static int link_elf_link_preload_finish(linker_file_t); 12954823af2SPeter Wemm static int link_elf_load_file(linker_class_t, const char *, linker_file_t *); 130326e27d8SDoug Rabson static int link_elf_lookup_symbol(linker_file_t, const char *, 131326e27d8SDoug Rabson c_linker_sym_t *); 132e9eabf59SPeter Wemm static int link_elf_symbol_values(linker_file_t, c_linker_sym_t, 133e9eabf59SPeter Wemm linker_symval_t *); 134326e27d8SDoug Rabson static int link_elf_search_symbol(linker_file_t, caddr_t value, 135326e27d8SDoug Rabson c_linker_sym_t *sym, long *diffp); 136326e27d8SDoug Rabson 137326e27d8SDoug Rabson static void link_elf_unload_file(linker_file_t); 138f41325dbSPeter Wemm static int link_elf_lookup_set(linker_file_t, const char *, 139f41325dbSPeter Wemm void ***, void ***, int *); 140bb9fe9ddSBrian Feldman static int link_elf_each_function_name(linker_file_t, 141e9eabf59SPeter Wemm int (*)(const char *, void *), void *); 142a2024a3eSJohn Birrell static int link_elf_each_function_nameval(linker_file_t, 143a2024a3eSJohn Birrell linker_function_nameval_callback_t, 144a2024a3eSJohn Birrell void *); 1453cfce8e4SKonstantin Belousov static int link_elf_reloc_local(linker_file_t); 146e76f11f4SAndriy Gapon static long link_elf_symtab_get(linker_file_t, const Elf_Sym **); 14700a5db46SStacey Son static long link_elf_strtab_get(linker_file_t, caddr_t *); 148326e27d8SDoug Rabson 149cff8c6f2SKonstantin Belousov static int elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps, 150cff8c6f2SKonstantin Belousov Elf_Addr *); 151e9eabf59SPeter Wemm 152326e27d8SDoug Rabson static kobj_method_t link_elf_methods[] = { 153326e27d8SDoug Rabson KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), 154326e27d8SDoug Rabson KOBJMETHOD(linker_symbol_values, link_elf_symbol_values), 155326e27d8SDoug Rabson KOBJMETHOD(linker_search_symbol, link_elf_search_symbol), 156326e27d8SDoug Rabson KOBJMETHOD(linker_unload, link_elf_unload_file), 15754823af2SPeter Wemm KOBJMETHOD(linker_load_file, link_elf_load_file), 15854823af2SPeter Wemm KOBJMETHOD(linker_link_preload, link_elf_link_preload), 15954823af2SPeter Wemm KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), 160f41325dbSPeter Wemm KOBJMETHOD(linker_lookup_set, link_elf_lookup_set), 161bb9fe9ddSBrian Feldman KOBJMETHOD(linker_each_function_name, link_elf_each_function_name), 162a2024a3eSJohn Birrell KOBJMETHOD(linker_each_function_nameval, link_elf_each_function_nameval), 163a2024a3eSJohn Birrell KOBJMETHOD(linker_ctf_get, link_elf_ctf_get), 16400a5db46SStacey Son KOBJMETHOD(linker_symtab_get, link_elf_symtab_get), 16500a5db46SStacey Son KOBJMETHOD(linker_strtab_get, link_elf_strtab_get), 166326e27d8SDoug Rabson { 0, 0 } 167326e27d8SDoug Rabson }; 168326e27d8SDoug Rabson 169326e27d8SDoug Rabson static struct linker_class link_elf_class = { 170326e27d8SDoug Rabson #if ELF_TARG_CLASS == ELFCLASS32 171e9eabf59SPeter Wemm "elf32_obj", 172326e27d8SDoug Rabson #else 173e9eabf59SPeter Wemm "elf64_obj", 174326e27d8SDoug Rabson #endif 175326e27d8SDoug Rabson link_elf_methods, sizeof(struct elf_file) 176326e27d8SDoug Rabson }; 177326e27d8SDoug Rabson 178326e27d8SDoug Rabson static int relocate_file(elf_file_t ef); 1792832cd54SKonstantin Belousov static void elf_obj_cleanup_globals_cache(elf_file_t); 180a4f67738SDoug Rabson 181a4f67738SDoug Rabson static void 182552f9f63SEdwin Groothuis link_elf_error(const char *filename, const char *s) 1831720979bSMarcel Moolenaar { 184552f9f63SEdwin Groothuis if (filename == NULL) 1851720979bSMarcel Moolenaar printf("kldload: %s\n", s); 186552f9f63SEdwin Groothuis else 187552f9f63SEdwin Groothuis printf("kldload: %s: %s\n", filename, s); 1881720979bSMarcel Moolenaar } 1891720979bSMarcel Moolenaar 1901720979bSMarcel Moolenaar static void 191a4f67738SDoug Rabson link_elf_init(void *arg) 192a4f67738SDoug Rabson { 193a4f67738SDoug Rabson 194326e27d8SDoug Rabson linker_add_class(&link_elf_class); 195a4f67738SDoug Rabson } 196a4f67738SDoug Rabson 197e9eabf59SPeter Wemm SYSINIT(link_elf_obj, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); 198a4f67738SDoug Rabson 199a4f67738SDoug Rabson static int 200e9eabf59SPeter Wemm link_elf_link_preload(linker_class_t cls, const char *filename, 201e9eabf59SPeter Wemm linker_file_t *result) 2022d636ab0SPeter Wemm { 20370b7ffeeSIan Dowse Elf_Ehdr *hdr; 20470b7ffeeSIan Dowse Elf_Shdr *shdr; 20570b7ffeeSIan Dowse Elf_Sym *es; 20670b7ffeeSIan Dowse void *modptr, *baseptr, *sizeptr; 20770b7ffeeSIan Dowse char *type; 20870b7ffeeSIan Dowse elf_file_t ef; 20970b7ffeeSIan Dowse linker_file_t lf; 21070b7ffeeSIan Dowse Elf_Addr off; 21170b7ffeeSIan Dowse int error, i, j, pb, ra, rl, shstrindex, symstrindex, symtabindex; 21270b7ffeeSIan Dowse 21370b7ffeeSIan Dowse /* Look to see if we have the file preloaded */ 21470b7ffeeSIan Dowse modptr = preload_search_by_name(filename); 21570b7ffeeSIan Dowse if (modptr == NULL) 21670b7ffeeSIan Dowse return ENOENT; 21770b7ffeeSIan Dowse 21870b7ffeeSIan Dowse type = (char *)preload_search_info(modptr, MODINFO_TYPE); 21970b7ffeeSIan Dowse baseptr = preload_search_info(modptr, MODINFO_ADDR); 22070b7ffeeSIan Dowse sizeptr = preload_search_info(modptr, MODINFO_SIZE); 22170b7ffeeSIan Dowse hdr = (Elf_Ehdr *)preload_search_info(modptr, MODINFO_METADATA | 22270b7ffeeSIan Dowse MODINFOMD_ELFHDR); 22370b7ffeeSIan Dowse shdr = (Elf_Shdr *)preload_search_info(modptr, MODINFO_METADATA | 22470b7ffeeSIan Dowse MODINFOMD_SHDR); 22570b7ffeeSIan Dowse if (type == NULL || (strcmp(type, "elf" __XSTRING(__ELF_WORD_SIZE) 22670b7ffeeSIan Dowse " obj module") != 0 && 22770b7ffeeSIan Dowse strcmp(type, "elf obj module") != 0)) { 228de78ca7eSPeter Wemm return (EFTYPE); 229de78ca7eSPeter Wemm } 23070b7ffeeSIan Dowse if (baseptr == NULL || sizeptr == NULL || hdr == NULL || 23170b7ffeeSIan Dowse shdr == NULL) 23270b7ffeeSIan Dowse return (EINVAL); 23370b7ffeeSIan Dowse 23470b7ffeeSIan Dowse lf = linker_make_file(filename, &link_elf_class); 23570b7ffeeSIan Dowse if (lf == NULL) 23670b7ffeeSIan Dowse return (ENOMEM); 23770b7ffeeSIan Dowse 23870b7ffeeSIan Dowse ef = (elf_file_t)lf; 23970b7ffeeSIan Dowse ef->preloaded = 1; 24070b7ffeeSIan Dowse ef->address = *(caddr_t *)baseptr; 24170b7ffeeSIan Dowse lf->address = *(caddr_t *)baseptr; 24270b7ffeeSIan Dowse lf->size = *(size_t *)sizeptr; 24370b7ffeeSIan Dowse 24470b7ffeeSIan Dowse if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 24570b7ffeeSIan Dowse hdr->e_ident[EI_DATA] != ELF_TARG_DATA || 24670b7ffeeSIan Dowse hdr->e_ident[EI_VERSION] != EV_CURRENT || 24770b7ffeeSIan Dowse hdr->e_version != EV_CURRENT || 24870b7ffeeSIan Dowse hdr->e_type != ET_REL || 24970b7ffeeSIan Dowse hdr->e_machine != ELF_TARG_MACH) { 25070b7ffeeSIan Dowse error = EFTYPE; 25170b7ffeeSIan Dowse goto out; 25270b7ffeeSIan Dowse } 25370b7ffeeSIan Dowse ef->e_shdr = shdr; 25470b7ffeeSIan Dowse 25570b7ffeeSIan Dowse /* Scan the section header for information and table sizing. */ 25670b7ffeeSIan Dowse symtabindex = -1; 25770b7ffeeSIan Dowse symstrindex = -1; 25870b7ffeeSIan Dowse for (i = 0; i < hdr->e_shnum; i++) { 25970b7ffeeSIan Dowse switch (shdr[i].sh_type) { 26070b7ffeeSIan Dowse case SHT_PROGBITS: 26170b7ffeeSIan Dowse case SHT_NOBITS: 26213f28d96SKonstantin Belousov #ifdef __amd64__ 263b715d9afSKonstantin Belousov case SHT_X86_64_UNWIND: 26413f28d96SKonstantin Belousov #endif 26558c4aee0SJohn Baldwin /* Ignore sections not loaded by the loader. */ 26658c4aee0SJohn Baldwin if (shdr[i].sh_addr == 0) 26758c4aee0SJohn Baldwin break; 26870b7ffeeSIan Dowse ef->nprogtab++; 26970b7ffeeSIan Dowse break; 27070b7ffeeSIan Dowse case SHT_SYMTAB: 27170b7ffeeSIan Dowse symtabindex = i; 27270b7ffeeSIan Dowse symstrindex = shdr[i].sh_link; 27370b7ffeeSIan Dowse break; 27470b7ffeeSIan Dowse case SHT_REL: 275*15746ef4SJohn Baldwin /* 276*15746ef4SJohn Baldwin * Ignore relocation tables for sections not 277*15746ef4SJohn Baldwin * loaded by the loader. 278*15746ef4SJohn Baldwin */ 279*15746ef4SJohn Baldwin if (shdr[shdr[i].sh_info].sh_addr == 0) 280*15746ef4SJohn Baldwin break; 281b474c780SDavid E. O'Brien ef->nreltab++; 28270b7ffeeSIan Dowse break; 28370b7ffeeSIan Dowse case SHT_RELA: 284*15746ef4SJohn Baldwin if (shdr[shdr[i].sh_info].sh_addr == 0) 285*15746ef4SJohn Baldwin break; 286b474c780SDavid E. O'Brien ef->nrelatab++; 28770b7ffeeSIan Dowse break; 28870b7ffeeSIan Dowse } 28970b7ffeeSIan Dowse } 29070b7ffeeSIan Dowse 29170b7ffeeSIan Dowse shstrindex = hdr->e_shstrndx; 29270b7ffeeSIan Dowse if (ef->nprogtab == 0 || symstrindex < 0 || 29370b7ffeeSIan Dowse symstrindex >= hdr->e_shnum || 29470b7ffeeSIan Dowse shdr[symstrindex].sh_type != SHT_STRTAB || shstrindex == 0 || 29570b7ffeeSIan Dowse shstrindex >= hdr->e_shnum || 29670b7ffeeSIan Dowse shdr[shstrindex].sh_type != SHT_STRTAB) { 29770b7ffeeSIan Dowse printf("%s: bad/missing section headers\n", filename); 29870b7ffeeSIan Dowse error = ENOEXEC; 29970b7ffeeSIan Dowse goto out; 30070b7ffeeSIan Dowse } 30170b7ffeeSIan Dowse 30270b7ffeeSIan Dowse /* Allocate space for tracking the load chunks */ 30370b7ffeeSIan Dowse if (ef->nprogtab != 0) 30470b7ffeeSIan Dowse ef->progtab = malloc(ef->nprogtab * sizeof(*ef->progtab), 30570b7ffeeSIan Dowse M_LINKER, M_WAITOK | M_ZERO); 306b474c780SDavid E. O'Brien if (ef->nreltab != 0) 307b474c780SDavid E. O'Brien ef->reltab = malloc(ef->nreltab * sizeof(*ef->reltab), 308b474c780SDavid E. O'Brien M_LINKER, M_WAITOK | M_ZERO); 309b474c780SDavid E. O'Brien if (ef->nrelatab != 0) 310b474c780SDavid E. O'Brien ef->relatab = malloc(ef->nrelatab * sizeof(*ef->relatab), 311b474c780SDavid E. O'Brien M_LINKER, M_WAITOK | M_ZERO); 31270b7ffeeSIan Dowse if ((ef->nprogtab != 0 && ef->progtab == NULL) || 313b474c780SDavid E. O'Brien (ef->nreltab != 0 && ef->reltab == NULL) || 314b474c780SDavid E. O'Brien (ef->nrelatab != 0 && ef->relatab == NULL)) { 31570b7ffeeSIan Dowse error = ENOMEM; 31670b7ffeeSIan Dowse goto out; 31770b7ffeeSIan Dowse } 31870b7ffeeSIan Dowse 31970b7ffeeSIan Dowse /* XXX, relocate the sh_addr fields saved by the loader. */ 32070b7ffeeSIan Dowse off = 0; 32170b7ffeeSIan Dowse for (i = 0; i < hdr->e_shnum; i++) { 32270b7ffeeSIan Dowse if (shdr[i].sh_addr != 0 && (off == 0 || shdr[i].sh_addr < off)) 32370b7ffeeSIan Dowse off = shdr[i].sh_addr; 32470b7ffeeSIan Dowse } 32570b7ffeeSIan Dowse for (i = 0; i < hdr->e_shnum; i++) { 32670b7ffeeSIan Dowse if (shdr[i].sh_addr != 0) 32770b7ffeeSIan Dowse shdr[i].sh_addr = shdr[i].sh_addr - off + 32870b7ffeeSIan Dowse (Elf_Addr)ef->address; 32970b7ffeeSIan Dowse } 33070b7ffeeSIan Dowse 33170b7ffeeSIan Dowse ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); 33270b7ffeeSIan Dowse ef->ddbsymtab = (Elf_Sym *)shdr[symtabindex].sh_addr; 33370b7ffeeSIan Dowse ef->ddbstrcnt = shdr[symstrindex].sh_size; 33470b7ffeeSIan Dowse ef->ddbstrtab = (char *)shdr[symstrindex].sh_addr; 33570b7ffeeSIan Dowse ef->shstrcnt = shdr[shstrindex].sh_size; 33670b7ffeeSIan Dowse ef->shstrtab = (char *)shdr[shstrindex].sh_addr; 33770b7ffeeSIan Dowse 33870b7ffeeSIan Dowse /* Now fill out progtab and the relocation tables. */ 33970b7ffeeSIan Dowse pb = 0; 34070b7ffeeSIan Dowse rl = 0; 34170b7ffeeSIan Dowse ra = 0; 34270b7ffeeSIan Dowse for (i = 0; i < hdr->e_shnum; i++) { 34370b7ffeeSIan Dowse switch (shdr[i].sh_type) { 34470b7ffeeSIan Dowse case SHT_PROGBITS: 34570b7ffeeSIan Dowse case SHT_NOBITS: 34613f28d96SKonstantin Belousov #ifdef __amd64__ 347b715d9afSKonstantin Belousov case SHT_X86_64_UNWIND: 34813f28d96SKonstantin Belousov #endif 34958c4aee0SJohn Baldwin if (shdr[i].sh_addr == 0) 35058c4aee0SJohn Baldwin break; 35170b7ffeeSIan Dowse ef->progtab[pb].addr = (void *)shdr[i].sh_addr; 35270b7ffeeSIan Dowse if (shdr[i].sh_type == SHT_PROGBITS) 35370b7ffeeSIan Dowse ef->progtab[pb].name = "<<PROGBITS>>"; 35413f28d96SKonstantin Belousov #ifdef __amd64__ 355b715d9afSKonstantin Belousov else if (shdr[i].sh_type == SHT_X86_64_UNWIND) 35613f28d96SKonstantin Belousov ef->progtab[pb].name = "<<UNWIND>>"; 35713f28d96SKonstantin Belousov #endif 35870b7ffeeSIan Dowse else 35970b7ffeeSIan Dowse ef->progtab[pb].name = "<<NOBITS>>"; 36070b7ffeeSIan Dowse ef->progtab[pb].size = shdr[i].sh_size; 36170b7ffeeSIan Dowse ef->progtab[pb].sec = i; 36270b7ffeeSIan Dowse if (ef->shstrtab && shdr[i].sh_name != 0) 36370b7ffeeSIan Dowse ef->progtab[pb].name = 36470b7ffeeSIan Dowse ef->shstrtab + shdr[i].sh_name; 36550c202c5SJeff Roberson if (ef->progtab[pb].name != NULL && 3665f67450dSDimitry Andric !strcmp(ef->progtab[pb].name, DPCPU_SETNAME)) { 36750c202c5SJeff Roberson void *dpcpu; 36850c202c5SJeff Roberson 36950c202c5SJeff Roberson dpcpu = dpcpu_alloc(shdr[i].sh_size); 37050c202c5SJeff Roberson if (dpcpu == NULL) { 37150c202c5SJeff Roberson error = ENOSPC; 37250c202c5SJeff Roberson goto out; 37350c202c5SJeff Roberson } 37450c202c5SJeff Roberson memcpy(dpcpu, ef->progtab[pb].addr, 37550c202c5SJeff Roberson ef->progtab[pb].size); 37650c202c5SJeff Roberson dpcpu_copy(dpcpu, shdr[i].sh_size); 37750c202c5SJeff Roberson ef->progtab[pb].addr = dpcpu; 378eddfbb76SRobert Watson #ifdef VIMAGE 379eddfbb76SRobert Watson } else if (ef->progtab[pb].name != NULL && 38017ef1febSRobert Watson !strcmp(ef->progtab[pb].name, VNET_SETNAME)) { 381eddfbb76SRobert Watson void *vnet_data; 382eddfbb76SRobert Watson 383eddfbb76SRobert Watson vnet_data = vnet_data_alloc(shdr[i].sh_size); 384eddfbb76SRobert Watson if (vnet_data == NULL) { 385eddfbb76SRobert Watson error = ENOSPC; 386eddfbb76SRobert Watson goto out; 387eddfbb76SRobert Watson } 388eddfbb76SRobert Watson memcpy(vnet_data, ef->progtab[pb].addr, 389eddfbb76SRobert Watson ef->progtab[pb].size); 390eddfbb76SRobert Watson vnet_data_copy(vnet_data, shdr[i].sh_size); 391eddfbb76SRobert Watson ef->progtab[pb].addr = vnet_data; 392eddfbb76SRobert Watson #endif 3930067051fSMarcel Moolenaar } else if (ef->progtab[pb].name != NULL && 3940067051fSMarcel Moolenaar !strcmp(ef->progtab[pb].name, ".ctors")) { 3950067051fSMarcel Moolenaar lf->ctors_addr = ef->progtab[pb].addr; 3960067051fSMarcel Moolenaar lf->ctors_size = shdr[i].sh_size; 39750c202c5SJeff Roberson } 39870b7ffeeSIan Dowse 39970b7ffeeSIan Dowse /* Update all symbol values with the offset. */ 40070b7ffeeSIan Dowse for (j = 0; j < ef->ddbsymcnt; j++) { 40170b7ffeeSIan Dowse es = &ef->ddbsymtab[j]; 40270b7ffeeSIan Dowse if (es->st_shndx != i) 40370b7ffeeSIan Dowse continue; 40470b7ffeeSIan Dowse es->st_value += (Elf_Addr)ef->progtab[pb].addr; 40570b7ffeeSIan Dowse } 40670b7ffeeSIan Dowse pb++; 40770b7ffeeSIan Dowse break; 40870b7ffeeSIan Dowse case SHT_REL: 409*15746ef4SJohn Baldwin if (shdr[shdr[i].sh_info].sh_addr == 0) 410*15746ef4SJohn Baldwin break; 41170b7ffeeSIan Dowse ef->reltab[rl].rel = (Elf_Rel *)shdr[i].sh_addr; 41270b7ffeeSIan Dowse ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); 41370b7ffeeSIan Dowse ef->reltab[rl].sec = shdr[i].sh_info; 41470b7ffeeSIan Dowse rl++; 41570b7ffeeSIan Dowse break; 41670b7ffeeSIan Dowse case SHT_RELA: 417*15746ef4SJohn Baldwin if (shdr[shdr[i].sh_info].sh_addr == 0) 418*15746ef4SJohn Baldwin break; 41970b7ffeeSIan Dowse ef->relatab[ra].rela = (Elf_Rela *)shdr[i].sh_addr; 42070b7ffeeSIan Dowse ef->relatab[ra].nrela = 42170b7ffeeSIan Dowse shdr[i].sh_size / sizeof(Elf_Rela); 42270b7ffeeSIan Dowse ef->relatab[ra].sec = shdr[i].sh_info; 42370b7ffeeSIan Dowse ra++; 42470b7ffeeSIan Dowse break; 42570b7ffeeSIan Dowse } 42670b7ffeeSIan Dowse } 4273cfce8e4SKonstantin Belousov if (pb != ef->nprogtab) { 4283cfce8e4SKonstantin Belousov printf("%s: lost progbits\n", filename); 4293cfce8e4SKonstantin Belousov error = ENOEXEC; 4303cfce8e4SKonstantin Belousov goto out; 4313cfce8e4SKonstantin Belousov } 4323cfce8e4SKonstantin Belousov if (rl != ef->nreltab) { 4333cfce8e4SKonstantin Belousov printf("%s: lost reltab\n", filename); 4343cfce8e4SKonstantin Belousov error = ENOEXEC; 4353cfce8e4SKonstantin Belousov goto out; 4363cfce8e4SKonstantin Belousov } 4373cfce8e4SKonstantin Belousov if (ra != ef->nrelatab) { 4383cfce8e4SKonstantin Belousov printf("%s: lost relatab\n", filename); 4393cfce8e4SKonstantin Belousov error = ENOEXEC; 4403cfce8e4SKonstantin Belousov goto out; 4413cfce8e4SKonstantin Belousov } 44270b7ffeeSIan Dowse 44370b7ffeeSIan Dowse /* Local intra-module relocations */ 4443cfce8e4SKonstantin Belousov error = link_elf_reloc_local(lf); 4453cfce8e4SKonstantin Belousov if (error != 0) 4463cfce8e4SKonstantin Belousov goto out; 44770b7ffeeSIan Dowse 44870b7ffeeSIan Dowse *result = lf; 44970b7ffeeSIan Dowse return (0); 45070b7ffeeSIan Dowse 45170b7ffeeSIan Dowse out: 45270b7ffeeSIan Dowse /* preload not done this way */ 45370b7ffeeSIan Dowse linker_file_unload(lf, LINKER_UNLOAD_FORCE); 45470b7ffeeSIan Dowse return (error); 45570b7ffeeSIan Dowse } 456de78ca7eSPeter Wemm 4570067051fSMarcel Moolenaar static void 4580067051fSMarcel Moolenaar link_elf_invoke_ctors(caddr_t addr, size_t size) 4590067051fSMarcel Moolenaar { 4600067051fSMarcel Moolenaar void (**ctor)(void); 4610067051fSMarcel Moolenaar size_t i, cnt; 4620067051fSMarcel Moolenaar 4630067051fSMarcel Moolenaar if (addr == NULL || size == 0) 4640067051fSMarcel Moolenaar return; 4650067051fSMarcel Moolenaar cnt = size / sizeof(*ctor); 4660067051fSMarcel Moolenaar ctor = (void *)addr; 4670067051fSMarcel Moolenaar for (i = 0; i < cnt; i++) { 4680067051fSMarcel Moolenaar if (ctor[i] != NULL) 4690067051fSMarcel Moolenaar (*ctor[i])(); 4700067051fSMarcel Moolenaar } 4710067051fSMarcel Moolenaar } 4720067051fSMarcel Moolenaar 473de78ca7eSPeter Wemm static int 47454823af2SPeter Wemm link_elf_link_preload_finish(linker_file_t lf) 47554823af2SPeter Wemm { 47670b7ffeeSIan Dowse elf_file_t ef; 47770b7ffeeSIan Dowse int error; 47870b7ffeeSIan Dowse 47970b7ffeeSIan Dowse ef = (elf_file_t)lf; 48070b7ffeeSIan Dowse error = relocate_file(ef); 48170b7ffeeSIan Dowse if (error) 48270b7ffeeSIan Dowse return error; 48370b7ffeeSIan Dowse 48470b7ffeeSIan Dowse /* Notify MD code that a module is being loaded. */ 48570b7ffeeSIan Dowse error = elf_cpu_load_file(lf); 48670b7ffeeSIan Dowse if (error) 48770b7ffeeSIan Dowse return (error); 48870b7ffeeSIan Dowse 4890067051fSMarcel Moolenaar /* Invoke .ctors */ 4900067051fSMarcel Moolenaar link_elf_invoke_ctors(lf->ctors_addr, lf->ctors_size); 49170b7ffeeSIan Dowse return (0); 49254823af2SPeter Wemm } 49354823af2SPeter Wemm 49454823af2SPeter Wemm static int 495c143d6c2SMarcel Moolenaar link_elf_load_file(linker_class_t cls, const char *filename, 496c143d6c2SMarcel Moolenaar linker_file_t *result) 497a4f67738SDoug Rabson { 498a344babfSGleb Smirnoff struct nameidata *nd; 499b40ce416SJulian Elischer struct thread *td = curthread; /* XXX */ 500caab6e90SPeter Wemm Elf_Ehdr *hdr; 501e9eabf59SPeter Wemm Elf_Shdr *shdr; 502a8774e39SPeter Wemm Elf_Sym *es; 503a8774e39SPeter Wemm int nbytes, i, j; 50420947801SPeter Wemm vm_offset_t mapbase; 505fe3db7c7SDoug Rabson size_t mapsize; 506a4f67738SDoug Rabson int error = 0; 507526d0bd5SKonstantin Belousov ssize_t resid; 508526d0bd5SKonstantin Belousov int flags; 509a4f67738SDoug Rabson elf_file_t ef; 510a4f67738SDoug Rabson linker_file_t lf; 511ca65d5c7SPeter Wemm int symtabindex; 512ca65d5c7SPeter Wemm int symstrindex; 513e9eabf59SPeter Wemm int shstrindex; 514e9eabf59SPeter Wemm int nsym; 51520947801SPeter Wemm int pb, rl, ra; 516e9eabf59SPeter Wemm int alignmask; 517ca65d5c7SPeter Wemm 518ca65d5c7SPeter Wemm shdr = NULL; 519ca65d5c7SPeter Wemm lf = NULL; 520e9eabf59SPeter Wemm mapsize = 0; 521e9eabf59SPeter Wemm hdr = NULL; 522a4f67738SDoug Rabson 523a344babfSGleb Smirnoff nd = malloc(sizeof(struct nameidata), M_TEMP, M_WAITOK); 524a344babfSGleb Smirnoff NDINIT(nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td); 525e6796b67SKirk McKusick flags = FREAD; 526a344babfSGleb Smirnoff error = vn_open(nd, &flags, 0, NULL); 527a344babfSGleb Smirnoff if (error) { 528a344babfSGleb Smirnoff free(nd, M_TEMP); 529a4f67738SDoug Rabson return error; 530a344babfSGleb Smirnoff } 531a344babfSGleb Smirnoff NDFREE(nd, NDF_ONLY_PNBUF); 532a344babfSGleb Smirnoff if (nd->ni_vp->v_type != VREG) { 5331f49b573SRuslan Ermilov error = ENOEXEC; 5341f49b573SRuslan Ermilov goto out; 5351f49b573SRuslan Ermilov } 536a3df768bSRobert Watson #ifdef MAC 537a344babfSGleb Smirnoff error = mac_kld_check_load(td->td_ucred, nd->ni_vp); 538a3df768bSRobert Watson if (error) { 539a3df768bSRobert Watson goto out; 540a3df768bSRobert Watson } 541a3df768bSRobert Watson #endif 542a4f67738SDoug Rabson 543e9eabf59SPeter Wemm /* Read the elf header from the file. */ 544e9eabf59SPeter Wemm hdr = malloc(sizeof(*hdr), M_LINKER, M_WAITOK); 545a344babfSGleb Smirnoff error = vn_rdwr(UIO_READ, nd->ni_vp, (void *)hdr, sizeof(*hdr), 0, 5469ca43589SRobert Watson UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 5479ca43589SRobert Watson &resid, td); 548a4f67738SDoug Rabson if (error) 549a4f67738SDoug Rabson goto out; 550e9eabf59SPeter Wemm if (resid != 0){ 551e9eabf59SPeter Wemm error = ENOEXEC; 552e9eabf59SPeter Wemm goto out; 553e9eabf59SPeter Wemm } 554a4f67738SDoug Rabson 555caab6e90SPeter Wemm if (!IS_ELF(*hdr)) { 556fe3db7c7SDoug Rabson error = ENOEXEC; 557a4f67738SDoug Rabson goto out; 558fe3db7c7SDoug Rabson } 559fe3db7c7SDoug Rabson 560caab6e90SPeter Wemm if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS 561caab6e90SPeter Wemm || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { 562552f9f63SEdwin Groothuis link_elf_error(filename, "Unsupported file layout"); 563fe3db7c7SDoug Rabson error = ENOEXEC; 564fe3db7c7SDoug Rabson goto out; 565fe3db7c7SDoug Rabson } 566caab6e90SPeter Wemm if (hdr->e_ident[EI_VERSION] != EV_CURRENT 567caab6e90SPeter Wemm || hdr->e_version != EV_CURRENT) { 568552f9f63SEdwin Groothuis link_elf_error(filename, "Unsupported file version"); 569fe3db7c7SDoug Rabson error = ENOEXEC; 570fe3db7c7SDoug Rabson goto out; 571fe3db7c7SDoug Rabson } 572e9eabf59SPeter Wemm if (hdr->e_type != ET_REL) { 573a1d7ce03SAttilio Rao error = ENOSYS; 574fe3db7c7SDoug Rabson goto out; 575fe3db7c7SDoug Rabson } 576caab6e90SPeter Wemm if (hdr->e_machine != ELF_TARG_MACH) { 577552f9f63SEdwin Groothuis link_elf_error(filename, "Unsupported machine"); 578fe3db7c7SDoug Rabson error = ENOEXEC; 579fe3db7c7SDoug Rabson goto out; 580fe3db7c7SDoug Rabson } 581a4f67738SDoug Rabson 582326e27d8SDoug Rabson lf = linker_make_file(filename, &link_elf_class); 583326e27d8SDoug Rabson if (!lf) { 584326e27d8SDoug Rabson error = ENOMEM; 585326e27d8SDoug Rabson goto out; 586326e27d8SDoug Rabson } 587326e27d8SDoug Rabson ef = (elf_file_t) lf; 588e9eabf59SPeter Wemm ef->nprogtab = 0; 589e9eabf59SPeter Wemm ef->e_shdr = 0; 590b474c780SDavid E. O'Brien ef->nreltab = 0; 591b474c780SDavid E. O'Brien ef->nrelatab = 0; 592e9eabf59SPeter Wemm 593e9eabf59SPeter Wemm /* Allocate and read in the section header */ 594e9eabf59SPeter Wemm nbytes = hdr->e_shnum * hdr->e_shentsize; 595e9eabf59SPeter Wemm if (nbytes == 0 || hdr->e_shoff == 0 || 596e9eabf59SPeter Wemm hdr->e_shentsize != sizeof(Elf_Shdr)) { 597e9eabf59SPeter Wemm error = ENOEXEC; 598e9eabf59SPeter Wemm goto out; 599e9eabf59SPeter Wemm } 60020947801SPeter Wemm shdr = malloc(nbytes, M_LINKER, M_WAITOK); 601e9eabf59SPeter Wemm ef->e_shdr = shdr; 602a344babfSGleb Smirnoff error = vn_rdwr(UIO_READ, nd->ni_vp, (caddr_t)shdr, nbytes, 603a344babfSGleb Smirnoff hdr->e_shoff, UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, 604a344babfSGleb Smirnoff NOCRED, &resid, td); 605e9eabf59SPeter Wemm if (error) 606e9eabf59SPeter Wemm goto out; 607e9eabf59SPeter Wemm if (resid) { 608e9eabf59SPeter Wemm error = ENOEXEC; 609e9eabf59SPeter Wemm goto out; 610e9eabf59SPeter Wemm } 611e9eabf59SPeter Wemm 612e9eabf59SPeter Wemm /* Scan the section header for information and table sizing. */ 613e9eabf59SPeter Wemm nsym = 0; 614e9eabf59SPeter Wemm symtabindex = -1; 615e9eabf59SPeter Wemm symstrindex = -1; 616e9eabf59SPeter Wemm for (i = 0; i < hdr->e_shnum; i++) { 617676799a0SAndriy Gapon if (shdr[i].sh_size == 0) 618676799a0SAndriy Gapon continue; 619e9eabf59SPeter Wemm switch (shdr[i].sh_type) { 620e9eabf59SPeter Wemm case SHT_PROGBITS: 621e9eabf59SPeter Wemm case SHT_NOBITS: 62213f28d96SKonstantin Belousov #ifdef __amd64__ 623b715d9afSKonstantin Belousov case SHT_X86_64_UNWIND: 62413f28d96SKonstantin Belousov #endif 62558c4aee0SJohn Baldwin if ((shdr[i].sh_flags & SHF_ALLOC) == 0) 62658c4aee0SJohn Baldwin break; 62720947801SPeter Wemm ef->nprogtab++; 628e9eabf59SPeter Wemm break; 629e9eabf59SPeter Wemm case SHT_SYMTAB: 630e9eabf59SPeter Wemm nsym++; 631e9eabf59SPeter Wemm symtabindex = i; 632e9eabf59SPeter Wemm symstrindex = shdr[i].sh_link; 633e9eabf59SPeter Wemm break; 634e9eabf59SPeter Wemm case SHT_REL: 635*15746ef4SJohn Baldwin /* 636*15746ef4SJohn Baldwin * Ignore relocation tables for unallocated 637*15746ef4SJohn Baldwin * sections. 638*15746ef4SJohn Baldwin */ 639*15746ef4SJohn Baldwin if ((shdr[shdr[i].sh_info].sh_flags & SHF_ALLOC) == 0) 640*15746ef4SJohn Baldwin break; 641b474c780SDavid E. O'Brien ef->nreltab++; 642e9eabf59SPeter Wemm break; 643e9eabf59SPeter Wemm case SHT_RELA: 644*15746ef4SJohn Baldwin if ((shdr[shdr[i].sh_info].sh_flags & SHF_ALLOC) == 0) 645*15746ef4SJohn Baldwin break; 646b474c780SDavid E. O'Brien ef->nrelatab++; 647e9eabf59SPeter Wemm break; 648e9eabf59SPeter Wemm case SHT_STRTAB: 649e9eabf59SPeter Wemm break; 650e9eabf59SPeter Wemm } 651e9eabf59SPeter Wemm } 65220947801SPeter Wemm if (ef->nprogtab == 0) { 653552f9f63SEdwin Groothuis link_elf_error(filename, "file has no contents"); 654e9eabf59SPeter Wemm error = ENOEXEC; 655e9eabf59SPeter Wemm goto out; 656e9eabf59SPeter Wemm } 657e9eabf59SPeter Wemm if (nsym != 1) { 658e9eabf59SPeter Wemm /* Only allow one symbol table for now */ 659552f9f63SEdwin Groothuis link_elf_error(filename, "file has no valid symbol table"); 660e9eabf59SPeter Wemm error = ENOEXEC; 661e9eabf59SPeter Wemm goto out; 662e9eabf59SPeter Wemm } 663e9eabf59SPeter Wemm if (symstrindex < 0 || symstrindex > hdr->e_shnum || 664e9eabf59SPeter Wemm shdr[symstrindex].sh_type != SHT_STRTAB) { 665552f9f63SEdwin Groothuis link_elf_error(filename, "file has invalid symbol strings"); 666e9eabf59SPeter Wemm error = ENOEXEC; 667e9eabf59SPeter Wemm goto out; 668e9eabf59SPeter Wemm } 669e9eabf59SPeter Wemm 670e9eabf59SPeter Wemm /* Allocate space for tracking the load chunks */ 671e9eabf59SPeter Wemm if (ef->nprogtab != 0) 67220947801SPeter Wemm ef->progtab = malloc(ef->nprogtab * sizeof(*ef->progtab), 67320947801SPeter Wemm M_LINKER, M_WAITOK | M_ZERO); 674b474c780SDavid E. O'Brien if (ef->nreltab != 0) 675b474c780SDavid E. O'Brien ef->reltab = malloc(ef->nreltab * sizeof(*ef->reltab), 676b474c780SDavid E. O'Brien M_LINKER, M_WAITOK | M_ZERO); 677b474c780SDavid E. O'Brien if (ef->nrelatab != 0) 678b474c780SDavid E. O'Brien ef->relatab = malloc(ef->nrelatab * sizeof(*ef->relatab), 679b474c780SDavid E. O'Brien M_LINKER, M_WAITOK | M_ZERO); 680e9eabf59SPeter Wemm 6813cfce8e4SKonstantin Belousov if (symtabindex == -1) { 6823cfce8e4SKonstantin Belousov link_elf_error(filename, "lost symbol table index"); 6833cfce8e4SKonstantin Belousov error = ENOEXEC; 6843cfce8e4SKonstantin Belousov goto out; 6853cfce8e4SKonstantin Belousov } 68620947801SPeter Wemm /* Allocate space for and load the symbol table */ 687e9eabf59SPeter Wemm ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); 688e9eabf59SPeter Wemm ef->ddbsymtab = malloc(shdr[symtabindex].sh_size, M_LINKER, M_WAITOK); 689a344babfSGleb Smirnoff error = vn_rdwr(UIO_READ, nd->ni_vp, (void *)ef->ddbsymtab, 69020947801SPeter Wemm shdr[symtabindex].sh_size, shdr[symtabindex].sh_offset, 69120947801SPeter Wemm UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 69220947801SPeter Wemm &resid, td); 69320947801SPeter Wemm if (error) 69420947801SPeter Wemm goto out; 69520947801SPeter Wemm if (resid != 0){ 69620947801SPeter Wemm error = EINVAL; 69720947801SPeter Wemm goto out; 69820947801SPeter Wemm } 699e9eabf59SPeter Wemm 7003cfce8e4SKonstantin Belousov if (symstrindex == -1) { 7013cfce8e4SKonstantin Belousov link_elf_error(filename, "lost symbol string index"); 7023cfce8e4SKonstantin Belousov error = ENOEXEC; 7033cfce8e4SKonstantin Belousov goto out; 7043cfce8e4SKonstantin Belousov } 70520947801SPeter Wemm /* Allocate space for and load the symbol strings */ 706e9eabf59SPeter Wemm ef->ddbstrcnt = shdr[symstrindex].sh_size; 707e9eabf59SPeter Wemm ef->ddbstrtab = malloc(shdr[symstrindex].sh_size, M_LINKER, M_WAITOK); 708a344babfSGleb Smirnoff error = vn_rdwr(UIO_READ, nd->ni_vp, ef->ddbstrtab, 70920947801SPeter Wemm shdr[symstrindex].sh_size, shdr[symstrindex].sh_offset, 71020947801SPeter Wemm UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 71120947801SPeter Wemm &resid, td); 71220947801SPeter Wemm if (error) 71320947801SPeter Wemm goto out; 71420947801SPeter Wemm if (resid != 0){ 71520947801SPeter Wemm error = EINVAL; 71620947801SPeter Wemm goto out; 71720947801SPeter Wemm } 718e9eabf59SPeter Wemm 719e9eabf59SPeter Wemm /* Do we have a string table for the section names? */ 720e9eabf59SPeter Wemm shstrindex = -1; 72120947801SPeter Wemm if (hdr->e_shstrndx != 0 && 72220947801SPeter Wemm shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { 723e9eabf59SPeter Wemm shstrindex = hdr->e_shstrndx; 724e9eabf59SPeter Wemm ef->shstrcnt = shdr[shstrindex].sh_size; 72520947801SPeter Wemm ef->shstrtab = malloc(shdr[shstrindex].sh_size, M_LINKER, 72620947801SPeter Wemm M_WAITOK); 727a344babfSGleb Smirnoff error = vn_rdwr(UIO_READ, nd->ni_vp, ef->shstrtab, 72820947801SPeter Wemm shdr[shstrindex].sh_size, shdr[shstrindex].sh_offset, 729e9eabf59SPeter Wemm UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 730e9eabf59SPeter Wemm &resid, td); 731e9eabf59SPeter Wemm if (error) 732e9eabf59SPeter Wemm goto out; 73320947801SPeter Wemm if (resid != 0){ 73420947801SPeter Wemm error = EINVAL; 73520947801SPeter Wemm goto out; 73620947801SPeter Wemm } 737e9eabf59SPeter Wemm } 738e9eabf59SPeter Wemm 73920947801SPeter Wemm /* Size up code/data(progbits) and bss(nobits). */ 740e9eabf59SPeter Wemm alignmask = 0; 741e9eabf59SPeter Wemm for (i = 0; i < hdr->e_shnum; i++) { 742676799a0SAndriy Gapon if (shdr[i].sh_size == 0) 743676799a0SAndriy Gapon continue; 744e9eabf59SPeter Wemm switch (shdr[i].sh_type) { 745e9eabf59SPeter Wemm case SHT_PROGBITS: 746e9eabf59SPeter Wemm case SHT_NOBITS: 74713f28d96SKonstantin Belousov #ifdef __amd64__ 748b715d9afSKonstantin Belousov case SHT_X86_64_UNWIND: 74913f28d96SKonstantin Belousov #endif 75058c4aee0SJohn Baldwin if ((shdr[i].sh_flags & SHF_ALLOC) == 0) 75158c4aee0SJohn Baldwin break; 752e9eabf59SPeter Wemm alignmask = shdr[i].sh_addralign - 1; 753e9eabf59SPeter Wemm mapsize += alignmask; 754e9eabf59SPeter Wemm mapsize &= ~alignmask; 755e9eabf59SPeter Wemm mapsize += shdr[i].sh_size; 756e9eabf59SPeter Wemm break; 757e9eabf59SPeter Wemm } 758e9eabf59SPeter Wemm } 759e9eabf59SPeter Wemm 760e9eabf59SPeter Wemm /* 761e9eabf59SPeter Wemm * We know how much space we need for the text/data/bss/etc. 762e9eabf59SPeter Wemm * This stuff needs to be in a single chunk so that profiling etc 763e9eabf59SPeter Wemm * can get the bounds and gdb can associate offsets with modules 764e9eabf59SPeter Wemm */ 76520947801SPeter Wemm ef->object = vm_object_allocate(OBJT_DEFAULT, 76620947801SPeter Wemm round_page(mapsize) >> PAGE_SHIFT); 767fe3db7c7SDoug Rabson if (ef->object == NULL) { 768fe3db7c7SDoug Rabson error = ENOMEM; 769fe3db7c7SDoug Rabson goto out; 770fe3db7c7SDoug Rabson } 771fe3db7c7SDoug Rabson ef->address = (caddr_t) vm_map_min(kernel_map); 772ac68d1c9SAlan Cox 773ac68d1c9SAlan Cox /* 774ac68d1c9SAlan Cox * In order to satisfy amd64's architectural requirements on the 775ac68d1c9SAlan Cox * location of code and data in the kernel's address space, request a 776ac68d1c9SAlan Cox * mapping that is above the kernel. 777ac68d1c9SAlan Cox */ 7784104e835SOleksandr Tymoshenko #ifdef __amd64__ 779ac68d1c9SAlan Cox mapbase = KERNBASE; 7804104e835SOleksandr Tymoshenko #else 7814104e835SOleksandr Tymoshenko mapbase = VM_MIN_KERNEL_ADDRESS; 7824104e835SOleksandr Tymoshenko #endif 78320947801SPeter Wemm error = vm_map_find(kernel_map, ef->object, 0, &mapbase, 784edb572a3SJohn Baldwin round_page(mapsize), 0, VMFS_OPTIMAL_SPACE, VM_PROT_ALL, 785edb572a3SJohn Baldwin VM_PROT_ALL, 0); 786fe3db7c7SDoug Rabson if (error) { 787fe3db7c7SDoug Rabson vm_object_deallocate(ef->object); 788326e27d8SDoug Rabson ef->object = 0; 789fe3db7c7SDoug Rabson goto out; 790fe3db7c7SDoug Rabson } 79120947801SPeter Wemm 792e9eabf59SPeter Wemm /* Wire the pages */ 7937f1ef325SAlan Cox error = vm_map_wire(kernel_map, mapbase, 79420947801SPeter Wemm mapbase + round_page(mapsize), 795e9eabf59SPeter Wemm VM_MAP_WIRE_SYSTEM|VM_MAP_WIRE_NOHOLES); 7967f1ef325SAlan Cox if (error != KERN_SUCCESS) { 7977f1ef325SAlan Cox error = ENOMEM; 7987f1ef325SAlan Cox goto out; 7997f1ef325SAlan Cox } 800a4f67738SDoug Rabson 80120947801SPeter Wemm /* Inform the kld system about the situation */ 80220947801SPeter Wemm lf->address = ef->address = (caddr_t)mapbase; 80320947801SPeter Wemm lf->size = mapsize; 804e9eabf59SPeter Wemm 805e9eabf59SPeter Wemm /* 80620947801SPeter Wemm * Now load code/data(progbits), zero bss(nobits), allocate space for 80720947801SPeter Wemm * and load relocs 808e9eabf59SPeter Wemm */ 80920947801SPeter Wemm pb = 0; 81020947801SPeter Wemm rl = 0; 81120947801SPeter Wemm ra = 0; 81220947801SPeter Wemm alignmask = 0; 81320947801SPeter Wemm for (i = 0; i < hdr->e_shnum; i++) { 814676799a0SAndriy Gapon if (shdr[i].sh_size == 0) 815676799a0SAndriy Gapon continue; 81620947801SPeter Wemm switch (shdr[i].sh_type) { 81720947801SPeter Wemm case SHT_PROGBITS: 81820947801SPeter Wemm case SHT_NOBITS: 81913f28d96SKonstantin Belousov #ifdef __amd64__ 820b715d9afSKonstantin Belousov case SHT_X86_64_UNWIND: 82113f28d96SKonstantin Belousov #endif 82258c4aee0SJohn Baldwin if ((shdr[i].sh_flags & SHF_ALLOC) == 0) 82358c4aee0SJohn Baldwin break; 82420947801SPeter Wemm alignmask = shdr[i].sh_addralign - 1; 82520947801SPeter Wemm mapbase += alignmask; 82620947801SPeter Wemm mapbase &= ~alignmask; 8270067051fSMarcel Moolenaar if (ef->shstrtab != NULL && shdr[i].sh_name != 0) { 82850c202c5SJeff Roberson ef->progtab[pb].name = 82950c202c5SJeff Roberson ef->shstrtab + shdr[i].sh_name; 8300067051fSMarcel Moolenaar if (!strcmp(ef->progtab[pb].name, ".ctors")) { 8310067051fSMarcel Moolenaar lf->ctors_addr = (caddr_t)mapbase; 8320067051fSMarcel Moolenaar lf->ctors_size = shdr[i].sh_size; 8330067051fSMarcel Moolenaar } 8340067051fSMarcel Moolenaar } else if (shdr[i].sh_type == SHT_PROGBITS) 83520947801SPeter Wemm ef->progtab[pb].name = "<<PROGBITS>>"; 83613f28d96SKonstantin Belousov #ifdef __amd64__ 837b715d9afSKonstantin Belousov else if (shdr[i].sh_type == SHT_X86_64_UNWIND) 83813f28d96SKonstantin Belousov ef->progtab[pb].name = "<<UNWIND>>"; 83913f28d96SKonstantin Belousov #endif 84050c202c5SJeff Roberson else 84150c202c5SJeff Roberson ef->progtab[pb].name = "<<NOBITS>>"; 84250c202c5SJeff Roberson if (ef->progtab[pb].name != NULL && 8435f67450dSDimitry Andric !strcmp(ef->progtab[pb].name, DPCPU_SETNAME)) 84450c202c5SJeff Roberson ef->progtab[pb].addr = 84550c202c5SJeff Roberson dpcpu_alloc(shdr[i].sh_size); 846eddfbb76SRobert Watson #ifdef VIMAGE 847eddfbb76SRobert Watson else if (ef->progtab[pb].name != NULL && 84817ef1febSRobert Watson !strcmp(ef->progtab[pb].name, VNET_SETNAME)) 849eddfbb76SRobert Watson ef->progtab[pb].addr = 850eddfbb76SRobert Watson vnet_data_alloc(shdr[i].sh_size); 851eddfbb76SRobert Watson #endif 85250c202c5SJeff Roberson else 85350c202c5SJeff Roberson ef->progtab[pb].addr = 85450c202c5SJeff Roberson (void *)(uintptr_t)mapbase; 85550c202c5SJeff Roberson if (ef->progtab[pb].addr == NULL) { 85650c202c5SJeff Roberson error = ENOSPC; 85750c202c5SJeff Roberson goto out; 85850c202c5SJeff Roberson } 85950c202c5SJeff Roberson ef->progtab[pb].size = shdr[i].sh_size; 86050c202c5SJeff Roberson ef->progtab[pb].sec = i; 86113f28d96SKonstantin Belousov if (shdr[i].sh_type == SHT_PROGBITS 86213f28d96SKonstantin Belousov #ifdef __amd64__ 863b715d9afSKonstantin Belousov || shdr[i].sh_type == SHT_X86_64_UNWIND 86413f28d96SKonstantin Belousov #endif 86513f28d96SKonstantin Belousov ) { 866a344babfSGleb Smirnoff error = vn_rdwr(UIO_READ, nd->ni_vp, 86720947801SPeter Wemm ef->progtab[pb].addr, 86820947801SPeter Wemm shdr[i].sh_size, shdr[i].sh_offset, 86920947801SPeter Wemm UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, 87020947801SPeter Wemm NOCRED, &resid, td); 87120947801SPeter Wemm if (error) 87220947801SPeter Wemm goto out; 87320947801SPeter Wemm if (resid != 0){ 87420947801SPeter Wemm error = EINVAL; 87520947801SPeter Wemm goto out; 87620947801SPeter Wemm } 877eddfbb76SRobert Watson /* Initialize the per-cpu or vnet area. */ 878eddfbb76SRobert Watson if (ef->progtab[pb].addr != (void *)mapbase && 8795f67450dSDimitry Andric !strcmp(ef->progtab[pb].name, DPCPU_SETNAME)) 88050c202c5SJeff Roberson dpcpu_copy(ef->progtab[pb].addr, 88150c202c5SJeff Roberson shdr[i].sh_size); 882eddfbb76SRobert Watson #ifdef VIMAGE 883eddfbb76SRobert Watson else if (ef->progtab[pb].addr != 884eddfbb76SRobert Watson (void *)mapbase && 88517ef1febSRobert Watson !strcmp(ef->progtab[pb].name, VNET_SETNAME)) 886eddfbb76SRobert Watson vnet_data_copy(ef->progtab[pb].addr, 887eddfbb76SRobert Watson shdr[i].sh_size); 888eddfbb76SRobert Watson #endif 88950c202c5SJeff Roberson } else 89020947801SPeter Wemm bzero(ef->progtab[pb].addr, shdr[i].sh_size); 891a8774e39SPeter Wemm 892a8774e39SPeter Wemm /* Update all symbol values with the offset. */ 893a8774e39SPeter Wemm for (j = 0; j < ef->ddbsymcnt; j++) { 894a8774e39SPeter Wemm es = &ef->ddbsymtab[j]; 895a8774e39SPeter Wemm if (es->st_shndx != i) 896a8774e39SPeter Wemm continue; 897a8774e39SPeter Wemm es->st_value += (Elf_Addr)ef->progtab[pb].addr; 898a8774e39SPeter Wemm } 89920947801SPeter Wemm mapbase += shdr[i].sh_size; 90020947801SPeter Wemm pb++; 90120947801SPeter Wemm break; 90220947801SPeter Wemm case SHT_REL: 903*15746ef4SJohn Baldwin if ((shdr[shdr[i].sh_info].sh_flags & SHF_ALLOC) == 0) 904*15746ef4SJohn Baldwin break; 90520947801SPeter Wemm ef->reltab[rl].rel = malloc(shdr[i].sh_size, M_LINKER, 90620947801SPeter Wemm M_WAITOK); 90720947801SPeter Wemm ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); 90820947801SPeter Wemm ef->reltab[rl].sec = shdr[i].sh_info; 909a344babfSGleb Smirnoff error = vn_rdwr(UIO_READ, nd->ni_vp, 91020947801SPeter Wemm (void *)ef->reltab[rl].rel, 91120947801SPeter Wemm shdr[i].sh_size, shdr[i].sh_offset, 912e9eabf59SPeter Wemm UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 913e9eabf59SPeter Wemm &resid, td); 914e9eabf59SPeter Wemm if (error) 915e9eabf59SPeter Wemm goto out; 91620947801SPeter Wemm if (resid != 0){ 91720947801SPeter Wemm error = EINVAL; 91820947801SPeter Wemm goto out; 919e9eabf59SPeter Wemm } 92020947801SPeter Wemm rl++; 92120947801SPeter Wemm break; 92220947801SPeter Wemm case SHT_RELA: 923*15746ef4SJohn Baldwin if ((shdr[shdr[i].sh_info].sh_flags & SHF_ALLOC) == 0) 924*15746ef4SJohn Baldwin break; 92520947801SPeter Wemm ef->relatab[ra].rela = malloc(shdr[i].sh_size, M_LINKER, 92620947801SPeter Wemm M_WAITOK); 92720947801SPeter Wemm ef->relatab[ra].nrela = 92820947801SPeter Wemm shdr[i].sh_size / sizeof(Elf_Rela); 92920947801SPeter Wemm ef->relatab[ra].sec = shdr[i].sh_info; 930a344babfSGleb Smirnoff error = vn_rdwr(UIO_READ, nd->ni_vp, 93120947801SPeter Wemm (void *)ef->relatab[ra].rela, 93220947801SPeter Wemm shdr[i].sh_size, shdr[i].sh_offset, 933e9eabf59SPeter Wemm UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED, 934e9eabf59SPeter Wemm &resid, td); 935e9eabf59SPeter Wemm if (error) 936e9eabf59SPeter Wemm goto out; 93720947801SPeter Wemm if (resid != 0){ 93820947801SPeter Wemm error = EINVAL; 93920947801SPeter Wemm goto out; 940e9eabf59SPeter Wemm } 94120947801SPeter Wemm ra++; 94220947801SPeter Wemm break; 94320947801SPeter Wemm } 94420947801SPeter Wemm } 9453cfce8e4SKonstantin Belousov if (pb != ef->nprogtab) { 9463cfce8e4SKonstantin Belousov link_elf_error(filename, "lost progbits"); 9473cfce8e4SKonstantin Belousov error = ENOEXEC; 9483cfce8e4SKonstantin Belousov goto out; 9493cfce8e4SKonstantin Belousov } 9503cfce8e4SKonstantin Belousov if (rl != ef->nreltab) { 9513cfce8e4SKonstantin Belousov link_elf_error(filename, "lost reltab"); 9523cfce8e4SKonstantin Belousov error = ENOEXEC; 9533cfce8e4SKonstantin Belousov goto out; 9543cfce8e4SKonstantin Belousov } 9553cfce8e4SKonstantin Belousov if (ra != ef->nrelatab) { 9563cfce8e4SKonstantin Belousov link_elf_error(filename, "lost relatab"); 9573cfce8e4SKonstantin Belousov error = ENOEXEC; 9583cfce8e4SKonstantin Belousov goto out; 9593cfce8e4SKonstantin Belousov } 9603cfce8e4SKonstantin Belousov if (mapbase != (vm_offset_t)ef->address + mapsize) { 9613cfce8e4SKonstantin Belousov printf( 9623cfce8e4SKonstantin Belousov "%s: mapbase 0x%lx != address %p + mapsize 0x%lx (0x%lx)\n", 9633cfce8e4SKonstantin Belousov filename != NULL ? filename : "<none>", 9646f3c6327SNeel Natu (u_long)mapbase, ef->address, (u_long)mapsize, 9656f3c6327SNeel Natu (u_long)(vm_offset_t)ef->address + mapsize); 9663cfce8e4SKonstantin Belousov error = ENOMEM; 9673cfce8e4SKonstantin Belousov goto out; 9683cfce8e4SKonstantin Belousov } 969e9eabf59SPeter Wemm 970e9eabf59SPeter Wemm /* Local intra-module relocations */ 9713cfce8e4SKonstantin Belousov error = link_elf_reloc_local(lf); 9723cfce8e4SKonstantin Belousov if (error != 0) 9733cfce8e4SKonstantin Belousov goto out; 9747251b4bfSJake Burkholder 975e9eabf59SPeter Wemm /* Pull in dependencies */ 976a344babfSGleb Smirnoff VOP_UNLOCK(nd->ni_vp, 0); 9777b9716baSIan Dowse error = linker_load_dependencies(lf); 978a344babfSGleb Smirnoff vn_lock(nd->ni_vp, LK_EXCLUSIVE | LK_RETRY); 979ca65d5c7SPeter Wemm if (error) 980de78ca7eSPeter Wemm goto out; 981e9eabf59SPeter Wemm 982e9eabf59SPeter Wemm /* External relocations */ 983326e27d8SDoug Rabson error = relocate_file(ef); 984ca65d5c7SPeter Wemm if (error) 985ca65d5c7SPeter Wemm goto out; 986ca65d5c7SPeter Wemm 987e9eabf59SPeter Wemm /* Notify MD code that a module is being loaded. */ 988e9eabf59SPeter Wemm error = elf_cpu_load_file(lf); 989ca65d5c7SPeter Wemm if (error) 990ca65d5c7SPeter Wemm goto out; 991a4f67738SDoug Rabson 9920067051fSMarcel Moolenaar /* Invoke .ctors */ 9930067051fSMarcel Moolenaar link_elf_invoke_ctors(lf->ctors_addr, lf->ctors_size); 9940067051fSMarcel Moolenaar 995a4f67738SDoug Rabson *result = lf; 996a4f67738SDoug Rabson 997a4f67738SDoug Rabson out: 998a344babfSGleb Smirnoff VOP_UNLOCK(nd->ni_vp, 0); 999a344babfSGleb Smirnoff vn_close(nd->ni_vp, FREAD, td->td_ucred, td); 1000a344babfSGleb Smirnoff free(nd, M_TEMP); 1001ca65d5c7SPeter Wemm if (error && lf) 100265a311fcSPoul-Henning Kamp linker_file_unload(lf, LINKER_UNLOAD_FORCE); 1003e9eabf59SPeter Wemm free(hdr, M_LINKER); 1004a4f67738SDoug Rabson 1005a4f67738SDoug Rabson return error; 1006a4f67738SDoug Rabson } 1007a4f67738SDoug Rabson 1008a4f67738SDoug Rabson static void 1009de78ca7eSPeter Wemm link_elf_unload_file(linker_file_t file) 1010a4f67738SDoug Rabson { 1011326e27d8SDoug Rabson elf_file_t ef = (elf_file_t) file; 1012d821d364SPedro F. Giffuni u_int i; 1013a4f67738SDoug Rabson 10141aeb23cdSMarcel Moolenaar /* Notify MD code that a module is being unloaded. */ 10151aeb23cdSMarcel Moolenaar elf_cpu_unload_file(file); 10161aeb23cdSMarcel Moolenaar 101750c202c5SJeff Roberson if (ef->progtab) { 101850c202c5SJeff Roberson for (i = 0; i < ef->nprogtab; i++) { 101950c202c5SJeff Roberson if (ef->progtab[i].size == 0) 102050c202c5SJeff Roberson continue; 102150c202c5SJeff Roberson if (ef->progtab[i].name == NULL) 102250c202c5SJeff Roberson continue; 10235f67450dSDimitry Andric if (!strcmp(ef->progtab[i].name, DPCPU_SETNAME)) 102450c202c5SJeff Roberson dpcpu_free(ef->progtab[i].addr, 102550c202c5SJeff Roberson ef->progtab[i].size); 1026eddfbb76SRobert Watson #ifdef VIMAGE 102717ef1febSRobert Watson else if (!strcmp(ef->progtab[i].name, VNET_SETNAME)) 1028eddfbb76SRobert Watson vnet_data_free(ef->progtab[i].addr, 1029eddfbb76SRobert Watson ef->progtab[i].size); 1030eddfbb76SRobert Watson #endif 103150c202c5SJeff Roberson } 103250c202c5SJeff Roberson } 103370b7ffeeSIan Dowse if (ef->preloaded) { 103470b7ffeeSIan Dowse free(ef->reltab, M_LINKER); 103570b7ffeeSIan Dowse free(ef->relatab, M_LINKER); 103670b7ffeeSIan Dowse free(ef->progtab, M_LINKER); 1037a2024a3eSJohn Birrell free(ef->ctftab, M_LINKER); 1038a2024a3eSJohn Birrell free(ef->ctfoff, M_LINKER); 1039a2024a3eSJohn Birrell free(ef->typoff, M_LINKER); 104070b7ffeeSIan Dowse if (file->filename != NULL) 104170b7ffeeSIan Dowse preload_delete_name(file->filename); 104270b7ffeeSIan Dowse /* XXX reclaim module memory? */ 104370b7ffeeSIan Dowse return; 104470b7ffeeSIan Dowse } 104570b7ffeeSIan Dowse 1046b474c780SDavid E. O'Brien for (i = 0; i < ef->nreltab; i++) 104720947801SPeter Wemm free(ef->reltab[i].rel, M_LINKER); 1048b474c780SDavid E. O'Brien for (i = 0; i < ef->nrelatab; i++) 104920947801SPeter Wemm free(ef->relatab[i].rela, M_LINKER); 105020947801SPeter Wemm free(ef->reltab, M_LINKER); 105120947801SPeter Wemm free(ef->relatab, M_LINKER); 105220947801SPeter Wemm free(ef->progtab, M_LINKER); 105320947801SPeter Wemm 1054fe3db7c7SDoug Rabson if (ef->object) { 1055fe3db7c7SDoug Rabson vm_map_remove(kernel_map, (vm_offset_t) ef->address, 105620947801SPeter Wemm (vm_offset_t) ef->address + 105720947801SPeter Wemm (ef->object->size << PAGE_SHIFT)); 1058fe3db7c7SDoug Rabson } 1059e9eabf59SPeter Wemm free(ef->e_shdr, M_LINKER); 1060e9eabf59SPeter Wemm free(ef->ddbsymtab, M_LINKER); 1061e9eabf59SPeter Wemm free(ef->ddbstrtab, M_LINKER); 106220947801SPeter Wemm free(ef->shstrtab, M_LINKER); 1063a2024a3eSJohn Birrell free(ef->ctftab, M_LINKER); 1064a2024a3eSJohn Birrell free(ef->ctfoff, M_LINKER); 1065a2024a3eSJohn Birrell free(ef->typoff, M_LINKER); 1066de78ca7eSPeter Wemm } 1067de78ca7eSPeter Wemm 1068fe3db7c7SDoug Rabson static const char * 1069757686b1SMarcel Moolenaar symbol_name(elf_file_t ef, Elf_Size r_info) 1070a4f67738SDoug Rabson { 1071fe3db7c7SDoug Rabson const Elf_Sym *ref; 1072a4f67738SDoug Rabson 1073aa855a59SPeter Wemm if (ELF_R_SYM(r_info)) { 1074e9eabf59SPeter Wemm ref = ef->ddbsymtab + ELF_R_SYM(r_info); 1075e9eabf59SPeter Wemm return ef->ddbstrtab + ref->st_name; 1076fe3db7c7SDoug Rabson } else 1077fe3db7c7SDoug Rabson return NULL; 1078a4f67738SDoug Rabson } 1079a4f67738SDoug Rabson 1080e9eabf59SPeter Wemm static Elf_Addr 1081e9eabf59SPeter Wemm findbase(elf_file_t ef, int sec) 1082e9eabf59SPeter Wemm { 1083e9eabf59SPeter Wemm int i; 1084e9eabf59SPeter Wemm Elf_Addr base = 0; 1085e9eabf59SPeter Wemm 1086e9eabf59SPeter Wemm for (i = 0; i < ef->nprogtab; i++) { 1087a8774e39SPeter Wemm if (sec == ef->progtab[i].sec) { 1088e9eabf59SPeter Wemm base = (Elf_Addr)ef->progtab[i].addr; 1089a8774e39SPeter Wemm break; 1090e9eabf59SPeter Wemm } 1091a8774e39SPeter Wemm } 1092e9eabf59SPeter Wemm return base; 1093e9eabf59SPeter Wemm } 1094e9eabf59SPeter Wemm 1095a4f67738SDoug Rabson static int 1096326e27d8SDoug Rabson relocate_file(elf_file_t ef) 1097a4f67738SDoug Rabson { 1098fe3db7c7SDoug Rabson const Elf_Rel *rellim; 1099fe3db7c7SDoug Rabson const Elf_Rel *rel; 1100fe3db7c7SDoug Rabson const Elf_Rela *relalim; 1101fe3db7c7SDoug Rabson const Elf_Rela *rela; 1102aa855a59SPeter Wemm const char *symname; 1103e9eabf59SPeter Wemm const Elf_Sym *sym; 1104e9eabf59SPeter Wemm int i; 1105757686b1SMarcel Moolenaar Elf_Size symidx; 1106e9eabf59SPeter Wemm Elf_Addr base; 1107e9eabf59SPeter Wemm 1108a4f67738SDoug Rabson 1109fe3db7c7SDoug Rabson /* Perform relocations without addend if there are any: */ 1110b474c780SDavid E. O'Brien for (i = 0; i < ef->nreltab; i++) { 1111e9eabf59SPeter Wemm rel = ef->reltab[i].rel; 11123cfce8e4SKonstantin Belousov if (rel == NULL) { 11133cfce8e4SKonstantin Belousov link_elf_error(ef->lf.filename, "lost a reltab!"); 11143cfce8e4SKonstantin Belousov return (ENOEXEC); 11153cfce8e4SKonstantin Belousov } 111620947801SPeter Wemm rellim = rel + ef->reltab[i].nrel; 1117e9eabf59SPeter Wemm base = findbase(ef, ef->reltab[i].sec); 11183cfce8e4SKonstantin Belousov if (base == 0) { 11193cfce8e4SKonstantin Belousov link_elf_error(ef->lf.filename, "lost base for reltab"); 11203cfce8e4SKonstantin Belousov return (ENOEXEC); 11213cfce8e4SKonstantin Belousov } 112220947801SPeter Wemm for ( ; rel < rellim; rel++) { 1123e9eabf59SPeter Wemm symidx = ELF_R_SYM(rel->r_info); 112420947801SPeter Wemm if (symidx >= ef->ddbsymcnt) 112520947801SPeter Wemm continue; 1126e9eabf59SPeter Wemm sym = ef->ddbsymtab + symidx; 112720947801SPeter Wemm /* Local relocs are already done */ 112820947801SPeter Wemm if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) 112920947801SPeter Wemm continue; 113020947801SPeter Wemm if (elf_reloc(&ef->lf, base, rel, ELF_RELOC_REL, 113120947801SPeter Wemm elf_obj_lookup)) { 1132aa855a59SPeter Wemm symname = symbol_name(ef, rel->r_info); 113320947801SPeter Wemm printf("link_elf_obj: symbol %s undefined\n", 113420947801SPeter Wemm symname); 11353cfce8e4SKonstantin Belousov return (ENOENT); 1136a13ddfb6SPeter Wemm } 1137aa855a59SPeter Wemm } 1138a4f67738SDoug Rabson } 1139a4f67738SDoug Rabson 1140fe3db7c7SDoug Rabson /* Perform relocations with addend if there are any: */ 1141b474c780SDavid E. O'Brien for (i = 0; i < ef->nrelatab; i++) { 1142e9eabf59SPeter Wemm rela = ef->relatab[i].rela; 11433cfce8e4SKonstantin Belousov if (rela == NULL) { 11443cfce8e4SKonstantin Belousov link_elf_error(ef->lf.filename, "lost a relatab!"); 11453cfce8e4SKonstantin Belousov return (ENOEXEC); 11463cfce8e4SKonstantin Belousov } 114720947801SPeter Wemm relalim = rela + ef->relatab[i].nrela; 1148e9eabf59SPeter Wemm base = findbase(ef, ef->relatab[i].sec); 11493cfce8e4SKonstantin Belousov if (base == 0) { 11503cfce8e4SKonstantin Belousov link_elf_error(ef->lf.filename, 11513cfce8e4SKonstantin Belousov "lost base for relatab"); 11523cfce8e4SKonstantin Belousov return (ENOEXEC); 11533cfce8e4SKonstantin Belousov } 115420947801SPeter Wemm for ( ; rela < relalim; rela++) { 1155e9eabf59SPeter Wemm symidx = ELF_R_SYM(rela->r_info); 115620947801SPeter Wemm if (symidx >= ef->ddbsymcnt) 115720947801SPeter Wemm continue; 1158e9eabf59SPeter Wemm sym = ef->ddbsymtab + symidx; 115920947801SPeter Wemm /* Local relocs are already done */ 116020947801SPeter Wemm if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) 116120947801SPeter Wemm continue; 116220947801SPeter Wemm if (elf_reloc(&ef->lf, base, rela, ELF_RELOC_RELA, 116320947801SPeter Wemm elf_obj_lookup)) { 1164aa855a59SPeter Wemm symname = symbol_name(ef, rela->r_info); 116520947801SPeter Wemm printf("link_elf_obj: symbol %s undefined\n", 116620947801SPeter Wemm symname); 11673cfce8e4SKonstantin Belousov return (ENOENT); 1168a13ddfb6SPeter Wemm } 1169e9eabf59SPeter Wemm } 1170e9eabf59SPeter Wemm } 1171a4f67738SDoug Rabson 11722832cd54SKonstantin Belousov /* 1173e3043798SPedro F. Giffuni * Only clean SHN_FBSD_CACHED for successful return. If we 11742832cd54SKonstantin Belousov * modified symbol table for the object but found an 11752832cd54SKonstantin Belousov * unresolved symbol, there is no reason to roll back. 11762832cd54SKonstantin Belousov */ 11772832cd54SKonstantin Belousov elf_obj_cleanup_globals_cache(ef); 11782832cd54SKonstantin Belousov 11793cfce8e4SKonstantin Belousov return (0); 1180a4f67738SDoug Rabson } 1181a4f67738SDoug Rabson 118237c84183SPoul-Henning Kamp static int 1183d254af07SMatthew Dillon link_elf_lookup_symbol(linker_file_t lf, const char *name, c_linker_sym_t *sym) 1184a4f67738SDoug Rabson { 1185326e27d8SDoug Rabson elf_file_t ef = (elf_file_t) lf; 11862d636ab0SPeter Wemm const Elf_Sym *symp; 11872d636ab0SPeter Wemm const char *strp; 1188a4f67738SDoug Rabson int i; 1189a4f67738SDoug Rabson 11902d636ab0SPeter Wemm for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 11912d636ab0SPeter Wemm strp = ef->ddbstrtab + symp->st_name; 1192a8774e39SPeter Wemm if (symp->st_shndx != SHN_UNDEF && strcmp(name, strp) == 0) { 1193d254af07SMatthew Dillon *sym = (c_linker_sym_t) symp; 11942d636ab0SPeter Wemm return 0; 11952d636ab0SPeter Wemm } 11962d636ab0SPeter Wemm } 1197a4f67738SDoug Rabson return ENOENT; 1198a4f67738SDoug Rabson } 1199a4f67738SDoug Rabson 1200de78ca7eSPeter Wemm static int 120120947801SPeter Wemm link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, 120220947801SPeter Wemm linker_symval_t *symval) 1203a4f67738SDoug Rabson { 1204326e27d8SDoug Rabson elf_file_t ef = (elf_file_t) lf; 12058aef1712SMatthew Dillon const Elf_Sym *es = (const Elf_Sym*) sym; 1206a4f67738SDoug Rabson 12075cf87418SMarcel Moolenaar if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) { 12082d636ab0SPeter Wemm symval->name = ef->ddbstrtab + es->st_name; 1209a8774e39SPeter Wemm symval->value = (caddr_t)es->st_value; 12102d636ab0SPeter Wemm symval->size = es->st_size; 12112d636ab0SPeter Wemm return 0; 12122d636ab0SPeter Wemm } 12132d636ab0SPeter Wemm return ENOENT; 12142d636ab0SPeter Wemm } 1215a4f67738SDoug Rabson 1216a4f67738SDoug Rabson static int 1217a4f67738SDoug Rabson link_elf_search_symbol(linker_file_t lf, caddr_t value, 1218d254af07SMatthew Dillon c_linker_sym_t *sym, long *diffp) 1219a4f67738SDoug Rabson { 1220326e27d8SDoug Rabson elf_file_t ef = (elf_file_t) lf; 1221586453feSBruce Evans u_long off = (uintptr_t) (void *) value; 1222a4f67738SDoug Rabson u_long diff = off; 1223586453feSBruce Evans u_long st_value; 1224fe3db7c7SDoug Rabson const Elf_Sym *es; 1225b85f65afSPedro F. Giffuni const Elf_Sym *best = NULL; 1226a4f67738SDoug Rabson int i; 1227a4f67738SDoug Rabson 12282d636ab0SPeter Wemm for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) { 1229a4f67738SDoug Rabson if (es->st_name == 0) 1230a4f67738SDoug Rabson continue; 1231a8774e39SPeter Wemm st_value = es->st_value; 1232b5abfb70SPeter Wemm if (off >= st_value) { 1233b5abfb70SPeter Wemm if (off - st_value < diff) { 1234b5abfb70SPeter Wemm diff = off - st_value; 1235a4f67738SDoug Rabson best = es; 1236a4f67738SDoug Rabson if (diff == 0) 1237a4f67738SDoug Rabson break; 1238b5abfb70SPeter Wemm } else if (off - st_value == diff) { 1239a4f67738SDoug Rabson best = es; 1240a4f67738SDoug Rabson } 1241a4f67738SDoug Rabson } 1242a4f67738SDoug Rabson } 1243b85f65afSPedro F. Giffuni if (best == NULL) 1244a4f67738SDoug Rabson *diffp = off; 1245a4f67738SDoug Rabson else 1246a4f67738SDoug Rabson *diffp = diff; 1247d254af07SMatthew Dillon *sym = (c_linker_sym_t) best; 1248a4f67738SDoug Rabson 1249a4f67738SDoug Rabson return 0; 1250a4f67738SDoug Rabson } 1251f41325dbSPeter Wemm 1252f41325dbSPeter Wemm /* 1253f41325dbSPeter Wemm * Look up a linker set on an ELF system. 1254f41325dbSPeter Wemm */ 1255f41325dbSPeter Wemm static int 1256f41325dbSPeter Wemm link_elf_lookup_set(linker_file_t lf, const char *name, 1257f41325dbSPeter Wemm void ***startp, void ***stopp, int *countp) 1258f41325dbSPeter Wemm { 1259e9eabf59SPeter Wemm elf_file_t ef = (elf_file_t)lf; 1260f41325dbSPeter Wemm void **start, **stop; 1261e9eabf59SPeter Wemm int i, count; 1262f41325dbSPeter Wemm 1263e9eabf59SPeter Wemm /* Relative to section number */ 1264e9eabf59SPeter Wemm for (i = 0; i < ef->nprogtab; i++) { 1265e9eabf59SPeter Wemm if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) && 1266e9eabf59SPeter Wemm strcmp(ef->progtab[i].name + 4, name) == 0) { 1267e9eabf59SPeter Wemm start = (void **)ef->progtab[i].addr; 126820947801SPeter Wemm stop = (void **)((char *)ef->progtab[i].addr + 126920947801SPeter Wemm ef->progtab[i].size); 1270f41325dbSPeter Wemm count = stop - start; 1271f41325dbSPeter Wemm if (startp) 1272f41325dbSPeter Wemm *startp = start; 1273f41325dbSPeter Wemm if (stopp) 1274f41325dbSPeter Wemm *stopp = stop; 1275f41325dbSPeter Wemm if (countp) 1276f41325dbSPeter Wemm *countp = count; 1277e9eabf59SPeter Wemm return (0); 1278e9eabf59SPeter Wemm } 1279e9eabf59SPeter Wemm } 1280e9eabf59SPeter Wemm return (ESRCH); 1281f41325dbSPeter Wemm } 1282bb9fe9ddSBrian Feldman 1283bb9fe9ddSBrian Feldman static int 1284bb9fe9ddSBrian Feldman link_elf_each_function_name(linker_file_t file, 1285e9eabf59SPeter Wemm int (*callback)(const char *, void *), void *opaque) 1286e9eabf59SPeter Wemm { 1287bb9fe9ddSBrian Feldman elf_file_t ef = (elf_file_t)file; 1288bb9fe9ddSBrian Feldman const Elf_Sym *symp; 1289bb9fe9ddSBrian Feldman int i, error; 1290bb9fe9ddSBrian Feldman 1291bb9fe9ddSBrian Feldman /* Exhaustive search */ 1292bb9fe9ddSBrian Feldman for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 1293bb9fe9ddSBrian Feldman if (symp->st_value != 0 && 1294bb9fe9ddSBrian Feldman ELF_ST_TYPE(symp->st_info) == STT_FUNC) { 1295bb9fe9ddSBrian Feldman error = callback(ef->ddbstrtab + symp->st_name, opaque); 1296bb9fe9ddSBrian Feldman if (error) 1297bb9fe9ddSBrian Feldman return (error); 1298bb9fe9ddSBrian Feldman } 1299bb9fe9ddSBrian Feldman } 1300bb9fe9ddSBrian Feldman return (0); 1301bb9fe9ddSBrian Feldman } 130284201059SMarcel Moolenaar 1303a2024a3eSJohn Birrell static int 1304a2024a3eSJohn Birrell link_elf_each_function_nameval(linker_file_t file, 1305a2024a3eSJohn Birrell linker_function_nameval_callback_t callback, void *opaque) 1306a2024a3eSJohn Birrell { 1307a2024a3eSJohn Birrell linker_symval_t symval; 1308a2024a3eSJohn Birrell elf_file_t ef = (elf_file_t)file; 1309a2024a3eSJohn Birrell const Elf_Sym* symp; 1310a2024a3eSJohn Birrell int i, error; 1311a2024a3eSJohn Birrell 1312a2024a3eSJohn Birrell /* Exhaustive search */ 1313a2024a3eSJohn Birrell for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { 1314a2024a3eSJohn Birrell if (symp->st_value != 0 && 1315a2024a3eSJohn Birrell ELF_ST_TYPE(symp->st_info) == STT_FUNC) { 1316a2024a3eSJohn Birrell error = link_elf_symbol_values(file, (c_linker_sym_t) symp, &symval); 1317a2024a3eSJohn Birrell if (error) 1318a2024a3eSJohn Birrell return (error); 1319a2024a3eSJohn Birrell error = callback(file, i, &symval, opaque); 1320a2024a3eSJohn Birrell if (error) 1321a2024a3eSJohn Birrell return (error); 1322a2024a3eSJohn Birrell } 1323a2024a3eSJohn Birrell } 1324a2024a3eSJohn Birrell return (0); 1325a2024a3eSJohn Birrell } 1326a2024a3eSJohn Birrell 13272832cd54SKonstantin Belousov static void 13282832cd54SKonstantin Belousov elf_obj_cleanup_globals_cache(elf_file_t ef) 13292832cd54SKonstantin Belousov { 13302832cd54SKonstantin Belousov Elf_Sym *sym; 13312832cd54SKonstantin Belousov Elf_Size i; 13322832cd54SKonstantin Belousov 13332832cd54SKonstantin Belousov for (i = 0; i < ef->ddbsymcnt; i++) { 13342832cd54SKonstantin Belousov sym = ef->ddbsymtab + i; 13352832cd54SKonstantin Belousov if (sym->st_shndx == SHN_FBSD_CACHED) { 13362832cd54SKonstantin Belousov sym->st_shndx = SHN_UNDEF; 13372832cd54SKonstantin Belousov sym->st_value = 0; 13382832cd54SKonstantin Belousov } 13392832cd54SKonstantin Belousov } 13402832cd54SKonstantin Belousov } 13412832cd54SKonstantin Belousov 1342d297ad16SMarcel Moolenaar /* 1343d297ad16SMarcel Moolenaar * Symbol lookup function that can be used when the symbol index is known (ie 1344d297ad16SMarcel Moolenaar * in relocations). It uses the symbol index instead of doing a fully fledged 1345d297ad16SMarcel Moolenaar * hash table based lookup when such is valid. For example for local symbols. 1346d297ad16SMarcel Moolenaar * This is not only more efficient, it's also more correct. It's not always 1347d297ad16SMarcel Moolenaar * the case that the symbol can be found through the hash table. 1348d297ad16SMarcel Moolenaar */ 1349cff8c6f2SKonstantin Belousov static int 1350cff8c6f2SKonstantin Belousov elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps, Elf_Addr *res) 1351d297ad16SMarcel Moolenaar { 1352d297ad16SMarcel Moolenaar elf_file_t ef = (elf_file_t)lf; 13532832cd54SKonstantin Belousov Elf_Sym *sym; 1354d297ad16SMarcel Moolenaar const char *symbol; 1355cff8c6f2SKonstantin Belousov Elf_Addr res1; 1356d297ad16SMarcel Moolenaar 1357d297ad16SMarcel Moolenaar /* Don't even try to lookup the symbol if the index is bogus. */ 1358cff8c6f2SKonstantin Belousov if (symidx >= ef->ddbsymcnt) { 1359cff8c6f2SKonstantin Belousov *res = 0; 1360cff8c6f2SKonstantin Belousov return (EINVAL); 1361cff8c6f2SKonstantin Belousov } 1362d297ad16SMarcel Moolenaar 1363e9eabf59SPeter Wemm sym = ef->ddbsymtab + symidx; 1364d297ad16SMarcel Moolenaar 13654cec6f5dSPeter Wemm /* Quick answer if there is a definition included. */ 1366cff8c6f2SKonstantin Belousov if (sym->st_shndx != SHN_UNDEF) { 1367cff8c6f2SKonstantin Belousov *res = sym->st_value; 1368cff8c6f2SKonstantin Belousov return (0); 1369cff8c6f2SKonstantin Belousov } 13704cec6f5dSPeter Wemm 13714cec6f5dSPeter Wemm /* If we get here, then it is undefined and needs a lookup. */ 13724cec6f5dSPeter Wemm switch (ELF_ST_BIND(sym->st_info)) { 13734cec6f5dSPeter Wemm case STB_LOCAL: 13744cec6f5dSPeter Wemm /* Local, but undefined? huh? */ 1375cff8c6f2SKonstantin Belousov *res = 0; 1376cff8c6f2SKonstantin Belousov return (EINVAL); 1377d297ad16SMarcel Moolenaar 1378e9eabf59SPeter Wemm case STB_GLOBAL: 1379cff8c6f2SKonstantin Belousov case STB_WEAK: 1380e9eabf59SPeter Wemm /* Relative to Data or Function name */ 1381e9eabf59SPeter Wemm symbol = ef->ddbstrtab + sym->st_name; 1382d297ad16SMarcel Moolenaar 1383d297ad16SMarcel Moolenaar /* Force a lookup failure if the symbol name is bogus. */ 1384cff8c6f2SKonstantin Belousov if (*symbol == 0) { 1385cff8c6f2SKonstantin Belousov *res = 0; 1386cff8c6f2SKonstantin Belousov return (EINVAL); 1387cff8c6f2SKonstantin Belousov } 1388cff8c6f2SKonstantin Belousov res1 = (Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps); 13892832cd54SKonstantin Belousov 13902832cd54SKonstantin Belousov /* 13912832cd54SKonstantin Belousov * Cache global lookups during module relocation. The failure 13922832cd54SKonstantin Belousov * case is particularly expensive for callers, who must scan 13932832cd54SKonstantin Belousov * through the entire globals table doing strcmp(). Cache to 13942832cd54SKonstantin Belousov * avoid doing such work repeatedly. 13952832cd54SKonstantin Belousov * 13962832cd54SKonstantin Belousov * After relocation is complete, undefined globals will be 13972832cd54SKonstantin Belousov * restored to SHN_UNDEF in elf_obj_cleanup_globals_cache(), 13982832cd54SKonstantin Belousov * above. 13992832cd54SKonstantin Belousov */ 1400cff8c6f2SKonstantin Belousov if (res1 != 0) { 14012832cd54SKonstantin Belousov sym->st_shndx = SHN_FBSD_CACHED; 1402cff8c6f2SKonstantin Belousov sym->st_value = res1; 1403cff8c6f2SKonstantin Belousov *res = res1; 1404e9eabf59SPeter Wemm return (0); 1405cff8c6f2SKonstantin Belousov } else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { 1406cff8c6f2SKonstantin Belousov sym->st_value = 0; 1407cff8c6f2SKonstantin Belousov *res = 0; 1408cff8c6f2SKonstantin Belousov return (0); 1409cff8c6f2SKonstantin Belousov } 1410cff8c6f2SKonstantin Belousov return (EINVAL); 1411e9eabf59SPeter Wemm 1412e9eabf59SPeter Wemm default: 1413cff8c6f2SKonstantin Belousov return (EINVAL); 1414d297ad16SMarcel Moolenaar } 1415e9eabf59SPeter Wemm } 1416e9eabf59SPeter Wemm 14177251b4bfSJake Burkholder static void 14187226306eSKonstantin Belousov link_elf_fix_link_set(elf_file_t ef) 14197226306eSKonstantin Belousov { 14207226306eSKonstantin Belousov static const char startn[] = "__start_"; 14217226306eSKonstantin Belousov static const char stopn[] = "__stop_"; 14227226306eSKonstantin Belousov Elf_Sym *sym; 14237226306eSKonstantin Belousov const char *sym_name, *linkset_name; 14247226306eSKonstantin Belousov Elf_Addr startp, stopp; 14257226306eSKonstantin Belousov Elf_Size symidx; 14267226306eSKonstantin Belousov int start, i; 14277226306eSKonstantin Belousov 14287226306eSKonstantin Belousov startp = stopp = 0; 14297226306eSKonstantin Belousov for (symidx = 1 /* zero entry is special */; 14307226306eSKonstantin Belousov symidx < ef->ddbsymcnt; symidx++) { 14317226306eSKonstantin Belousov sym = ef->ddbsymtab + symidx; 14327226306eSKonstantin Belousov if (sym->st_shndx != SHN_UNDEF) 14337226306eSKonstantin Belousov continue; 14347226306eSKonstantin Belousov 14357226306eSKonstantin Belousov sym_name = ef->ddbstrtab + sym->st_name; 14367226306eSKonstantin Belousov if (strncmp(sym_name, startn, sizeof(startn) - 1) == 0) { 14377226306eSKonstantin Belousov start = 1; 14387226306eSKonstantin Belousov linkset_name = sym_name + sizeof(startn) - 1; 14397226306eSKonstantin Belousov } 14407226306eSKonstantin Belousov else if (strncmp(sym_name, stopn, sizeof(stopn) - 1) == 0) { 14417226306eSKonstantin Belousov start = 0; 14427226306eSKonstantin Belousov linkset_name = sym_name + sizeof(stopn) - 1; 14437226306eSKonstantin Belousov } 14447226306eSKonstantin Belousov else 14457226306eSKonstantin Belousov continue; 14467226306eSKonstantin Belousov 14477226306eSKonstantin Belousov for (i = 0; i < ef->nprogtab; i++) { 14487226306eSKonstantin Belousov if (strcmp(ef->progtab[i].name, linkset_name) == 0) { 14497226306eSKonstantin Belousov startp = (Elf_Addr)ef->progtab[i].addr; 14507226306eSKonstantin Belousov stopp = (Elf_Addr)(startp + ef->progtab[i].size); 14517226306eSKonstantin Belousov break; 14527226306eSKonstantin Belousov } 14537226306eSKonstantin Belousov } 14547226306eSKonstantin Belousov if (i == ef->nprogtab) 14557226306eSKonstantin Belousov continue; 14567226306eSKonstantin Belousov 14577226306eSKonstantin Belousov sym->st_value = start ? startp : stopp; 14587226306eSKonstantin Belousov sym->st_shndx = i; 14597226306eSKonstantin Belousov } 14607226306eSKonstantin Belousov } 14617226306eSKonstantin Belousov 14623cfce8e4SKonstantin Belousov static int 14637251b4bfSJake Burkholder link_elf_reloc_local(linker_file_t lf) 14647251b4bfSJake Burkholder { 1465e9eabf59SPeter Wemm elf_file_t ef = (elf_file_t)lf; 14667251b4bfSJake Burkholder const Elf_Rel *rellim; 14677251b4bfSJake Burkholder const Elf_Rel *rel; 14687251b4bfSJake Burkholder const Elf_Rela *relalim; 14697251b4bfSJake Burkholder const Elf_Rela *rela; 1470e9eabf59SPeter Wemm const Elf_Sym *sym; 1471e9eabf59SPeter Wemm Elf_Addr base; 1472e9eabf59SPeter Wemm int i; 1473757686b1SMarcel Moolenaar Elf_Size symidx; 1474e9eabf59SPeter Wemm 14757226306eSKonstantin Belousov link_elf_fix_link_set(ef); 14767226306eSKonstantin Belousov 14777251b4bfSJake Burkholder /* Perform relocations without addend if there are any: */ 1478b474c780SDavid E. O'Brien for (i = 0; i < ef->nreltab; i++) { 1479e9eabf59SPeter Wemm rel = ef->reltab[i].rel; 14803cfce8e4SKonstantin Belousov if (rel == NULL) { 14813cfce8e4SKonstantin Belousov link_elf_error(ef->lf.filename, "lost a reltab"); 14823cfce8e4SKonstantin Belousov return (ENOEXEC); 14833cfce8e4SKonstantin Belousov } 148420947801SPeter Wemm rellim = rel + ef->reltab[i].nrel; 1485e9eabf59SPeter Wemm base = findbase(ef, ef->reltab[i].sec); 14863cfce8e4SKonstantin Belousov if (base == 0) { 14873cfce8e4SKonstantin Belousov link_elf_error(ef->lf.filename, "lost base for reltab"); 14883cfce8e4SKonstantin Belousov return (ENOEXEC); 14893cfce8e4SKonstantin Belousov } 149020947801SPeter Wemm for ( ; rel < rellim; rel++) { 1491e9eabf59SPeter Wemm symidx = ELF_R_SYM(rel->r_info); 149220947801SPeter Wemm if (symidx >= ef->ddbsymcnt) 149320947801SPeter Wemm continue; 1494e9eabf59SPeter Wemm sym = ef->ddbsymtab + symidx; 149520947801SPeter Wemm /* Only do local relocs */ 149620947801SPeter Wemm if (ELF_ST_BIND(sym->st_info) != STB_LOCAL) 149720947801SPeter Wemm continue; 149820947801SPeter Wemm elf_reloc_local(lf, base, rel, ELF_RELOC_REL, 149920947801SPeter Wemm elf_obj_lookup); 15007251b4bfSJake Burkholder } 1501e9eabf59SPeter Wemm } 15027251b4bfSJake Burkholder 15037251b4bfSJake Burkholder /* Perform relocations with addend if there are any: */ 1504b474c780SDavid E. O'Brien for (i = 0; i < ef->nrelatab; i++) { 1505e9eabf59SPeter Wemm rela = ef->relatab[i].rela; 15063cfce8e4SKonstantin Belousov if (rela == NULL) { 15073cfce8e4SKonstantin Belousov link_elf_error(ef->lf.filename, "lost a relatab!"); 15083cfce8e4SKonstantin Belousov return (ENOEXEC); 15093cfce8e4SKonstantin Belousov } 151020947801SPeter Wemm relalim = rela + ef->relatab[i].nrela; 1511e9eabf59SPeter Wemm base = findbase(ef, ef->relatab[i].sec); 15123cfce8e4SKonstantin Belousov if (base == 0) { 15133cfce8e4SKonstantin Belousov link_elf_error(ef->lf.filename, "lost base for reltab"); 15143cfce8e4SKonstantin Belousov return (ENOEXEC); 15153cfce8e4SKonstantin Belousov } 151620947801SPeter Wemm for ( ; rela < relalim; rela++) { 1517e9eabf59SPeter Wemm symidx = ELF_R_SYM(rela->r_info); 151820947801SPeter Wemm if (symidx >= ef->ddbsymcnt) 151920947801SPeter Wemm continue; 1520e9eabf59SPeter Wemm sym = ef->ddbsymtab + symidx; 152120947801SPeter Wemm /* Only do local relocs */ 152220947801SPeter Wemm if (ELF_ST_BIND(sym->st_info) != STB_LOCAL) 152320947801SPeter Wemm continue; 152420947801SPeter Wemm elf_reloc_local(lf, base, rela, ELF_RELOC_RELA, 152520947801SPeter Wemm elf_obj_lookup); 15267251b4bfSJake Burkholder } 15277251b4bfSJake Burkholder } 15283cfce8e4SKonstantin Belousov return (0); 1529e9eabf59SPeter Wemm } 153000a5db46SStacey Son 153100a5db46SStacey Son static long 1532e76f11f4SAndriy Gapon link_elf_symtab_get(linker_file_t lf, const Elf_Sym **symtab) 153300a5db46SStacey Son { 153400a5db46SStacey Son elf_file_t ef = (elf_file_t)lf; 153500a5db46SStacey Son 153600a5db46SStacey Son *symtab = ef->ddbsymtab; 153700a5db46SStacey Son 153800a5db46SStacey Son if (*symtab == NULL) 153900a5db46SStacey Son return (0); 154000a5db46SStacey Son 154100a5db46SStacey Son return (ef->ddbsymcnt); 154200a5db46SStacey Son } 154300a5db46SStacey Son 154400a5db46SStacey Son static long 154500a5db46SStacey Son link_elf_strtab_get(linker_file_t lf, caddr_t *strtab) 154600a5db46SStacey Son { 154700a5db46SStacey Son elf_file_t ef = (elf_file_t)lf; 154800a5db46SStacey Son 154900a5db46SStacey Son *strtab = ef->ddbstrtab; 155000a5db46SStacey Son 155100a5db46SStacey Son if (*strtab == NULL) 155200a5db46SStacey Son return (0); 155300a5db46SStacey Son 155400a5db46SStacey Son return (ef->ddbstrcnt); 155500a5db46SStacey Son } 1556