1a4f67738SDoug Rabson /*- 2a4f67738SDoug Rabson * Copyright (c) 1998 Doug Rabson 3a4f67738SDoug Rabson * All rights reserved. 4a4f67738SDoug Rabson * 5a4f67738SDoug Rabson * Redistribution and use in source and binary forms, with or without 6a4f67738SDoug Rabson * modification, are permitted provided that the following conditions 7a4f67738SDoug Rabson * are met: 8a4f67738SDoug Rabson * 1. Redistributions of source code must retain the above copyright 9a4f67738SDoug Rabson * notice, this list of conditions and the following disclaimer. 10a4f67738SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 11a4f67738SDoug Rabson * notice, this list of conditions and the following disclaimer in the 12a4f67738SDoug Rabson * documentation and/or other materials provided with the distribution. 13a4f67738SDoug Rabson * 14a4f67738SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15a4f67738SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a4f67738SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17a4f67738SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a4f67738SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a4f67738SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a4f67738SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a4f67738SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a4f67738SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a4f67738SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a4f67738SDoug Rabson * SUCH DAMAGE. 25a4f67738SDoug Rabson * 26a4f67738SDoug Rabson * $Id$ 27a4f67738SDoug Rabson */ 28a4f67738SDoug Rabson 29a4f67738SDoug Rabson #include <sys/param.h> 30a4f67738SDoug Rabson #include <sys/kernel.h> 31a4f67738SDoug Rabson #include <sys/systm.h> 32a4f67738SDoug Rabson #include <sys/malloc.h> 33a4f67738SDoug Rabson #include <sys/proc.h> 34a4f67738SDoug Rabson #include <sys/namei.h> 35a4f67738SDoug Rabson #include <sys/fcntl.h> 36a4f67738SDoug Rabson #include <sys/vnode.h> 37a4f67738SDoug Rabson #include <sys/linker.h> 38a4f67738SDoug Rabson #include <machine/elf.h> 39a4f67738SDoug Rabson 40a4f67738SDoug Rabson static int link_elf_load_file(const char*, linker_file_t*); 41a4f67738SDoug Rabson static int link_elf_lookup_symbol(linker_file_t, const char*, 42a4f67738SDoug Rabson linker_sym_t*); 43a4f67738SDoug Rabson static void link_elf_symbol_values(linker_file_t, linker_sym_t, linker_symval_t*); 44a4f67738SDoug Rabson static int link_elf_search_symbol(linker_file_t, caddr_t value, 45a4f67738SDoug Rabson linker_sym_t* sym, long* diffp); 46a4f67738SDoug Rabson 47a4f67738SDoug Rabson static void link_elf_unload(linker_file_t); 48a4f67738SDoug Rabson 49a4f67738SDoug Rabson /* 50a4f67738SDoug Rabson * The file representing the currently running kernel. This contains 51a4f67738SDoug Rabson * the global symbol table. 52a4f67738SDoug Rabson */ 53a4f67738SDoug Rabson 54a4f67738SDoug Rabson linker_file_t linker_kernel_file; 55a4f67738SDoug Rabson 56a4f67738SDoug Rabson static struct linker_class_ops link_elf_class_ops = { 57a4f67738SDoug Rabson link_elf_load_file, 58a4f67738SDoug Rabson }; 59a4f67738SDoug Rabson 60a4f67738SDoug Rabson static struct linker_file_ops link_elf_file_ops = { 61a4f67738SDoug Rabson link_elf_lookup_symbol, 62a4f67738SDoug Rabson link_elf_symbol_values, 63a4f67738SDoug Rabson link_elf_search_symbol, 64a4f67738SDoug Rabson link_elf_unload, 65a4f67738SDoug Rabson }; 66a4f67738SDoug Rabson 67a4f67738SDoug Rabson typedef struct elf_file { 68a4f67738SDoug Rabson caddr_t address; /* Load address */ 69a4f67738SDoug Rabson Elf_Dyn* dynamic; /* Symbol table etc. */ 70a4f67738SDoug Rabson Elf_Off nbuckets; /* DT_HASH info */ 71a4f67738SDoug Rabson Elf_Off nchains; 72a4f67738SDoug Rabson const Elf_Off* buckets; 73a4f67738SDoug Rabson const Elf_Off* chains; 74a4f67738SDoug Rabson caddr_t hash; 75a4f67738SDoug Rabson caddr_t strtab; /* DT_STRTAB */ 76a4f67738SDoug Rabson Elf_Sym* symtab; /* DT_SYMTAB */ 77a4f67738SDoug Rabson } *elf_file_t; 78a4f67738SDoug Rabson 79a4f67738SDoug Rabson static int parse_dynamic(linker_file_t lf); 80a4f67738SDoug Rabson static int load_dependancies(linker_file_t lf); 81a4f67738SDoug Rabson static int relocate_file(linker_file_t lf); 82a4f67738SDoug Rabson 83a4f67738SDoug Rabson /* 84a4f67738SDoug Rabson * The kernel symbol table starts here. 85a4f67738SDoug Rabson */ 86a4f67738SDoug Rabson extern struct _dynamic _DYNAMIC; 87a4f67738SDoug Rabson 88a4f67738SDoug Rabson static void 89a4f67738SDoug Rabson link_elf_init(void* arg) 90a4f67738SDoug Rabson { 91a4f67738SDoug Rabson Elf_Dyn* dp = (Elf_Dyn*) &_DYNAMIC; 92a4f67738SDoug Rabson 93a4f67738SDoug Rabson #if ELF_TARG_CLASS == ELFCLASS32 94a4f67738SDoug Rabson linker_add_class("elf32", NULL, &link_elf_class_ops); 95a4f67738SDoug Rabson #else 96a4f67738SDoug Rabson linker_add_class("elf64", NULL, &link_elf_class_ops); 97a4f67738SDoug Rabson #endif 98a4f67738SDoug Rabson 99a4f67738SDoug Rabson if (dp) { 100a4f67738SDoug Rabson elf_file_t ef; 101a4f67738SDoug Rabson 102a4f67738SDoug Rabson ef = malloc(sizeof(struct elf_file), M_LINKER, M_NOWAIT); 103a4f67738SDoug Rabson if (ef == NULL) 104a4f67738SDoug Rabson panic("link_elf_init: Can't create linker structures for kernel"); 105a4f67738SDoug Rabson 106a4f67738SDoug Rabson ef->address = 0; 107a4f67738SDoug Rabson ef->dynamic = dp; 108a4f67738SDoug Rabson linker_kernel_file = 109a4f67738SDoug Rabson linker_make_file(kernelname, ef, &link_elf_file_ops); 110a4f67738SDoug Rabson if (linker_kernel_file == NULL) 111a4f67738SDoug Rabson panic("link_elf_init: Can't create linker structures for kernel"); 112a4f67738SDoug Rabson parse_dynamic(linker_kernel_file); 113a4f67738SDoug Rabson /* 114a4f67738SDoug Rabson * XXX there must be a better way of getting these constants. 115a4f67738SDoug Rabson */ 116a4f67738SDoug Rabson #ifdef __alpha__ 117a4f67738SDoug Rabson linker_kernel_file->address = (caddr_t) 0xfffffc0000300000; 118a4f67738SDoug Rabson #else 119a4f67738SDoug Rabson linker_kernel_file->address = (caddr_t) 0xf0100000; 120a4f67738SDoug Rabson #endif 121a4f67738SDoug Rabson linker_kernel_file->size = -(long)linker_kernel_file->address; 122a4f67738SDoug Rabson linker_current_file = linker_kernel_file; 123a4f67738SDoug Rabson } 124a4f67738SDoug Rabson } 125a4f67738SDoug Rabson 126a4f67738SDoug Rabson SYSINIT(link_elf, SI_SUB_KMEM, SI_ORDER_THIRD, link_elf_init, 0); 127a4f67738SDoug Rabson 128a4f67738SDoug Rabson static int 129a4f67738SDoug Rabson parse_dynamic(linker_file_t lf) 130a4f67738SDoug Rabson { 131a4f67738SDoug Rabson elf_file_t ef = lf->priv; 132a4f67738SDoug Rabson Elf_Dyn *dp; 133a4f67738SDoug Rabson 134a4f67738SDoug Rabson for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { 135a4f67738SDoug Rabson switch (dp->d_tag) { 136a4f67738SDoug Rabson case DT_HASH: 137a4f67738SDoug Rabson { 138a4f67738SDoug Rabson /* From src/libexec/rtld-elf/rtld.c */ 139a4f67738SDoug Rabson const Elf_Off *hashtab = (const Elf_Off *) 140a4f67738SDoug Rabson (ef->address + dp->d_un.d_ptr); 141a4f67738SDoug Rabson ef->nbuckets = hashtab[0]; 142a4f67738SDoug Rabson ef->nchains = hashtab[1]; 143a4f67738SDoug Rabson ef->buckets = hashtab + 2; 144a4f67738SDoug Rabson ef->chains = ef->buckets + ef->nbuckets; 145a4f67738SDoug Rabson break; 146a4f67738SDoug Rabson } 147a4f67738SDoug Rabson case DT_STRTAB: 148a4f67738SDoug Rabson ef->strtab = (caddr_t) dp->d_un.d_ptr; 149a4f67738SDoug Rabson break; 150a4f67738SDoug Rabson case DT_SYMTAB: 151a4f67738SDoug Rabson ef->symtab = (Elf_Sym*) dp->d_un.d_ptr; 152a4f67738SDoug Rabson break; 153a4f67738SDoug Rabson case DT_SYMENT: 154a4f67738SDoug Rabson if (dp->d_un.d_val != sizeof(Elf_Sym)) 155a4f67738SDoug Rabson return ENOEXEC; 156a4f67738SDoug Rabson } 157a4f67738SDoug Rabson } 158a4f67738SDoug Rabson return 0; 159a4f67738SDoug Rabson } 160a4f67738SDoug Rabson 161a4f67738SDoug Rabson static int 162a4f67738SDoug Rabson link_elf_load_file(const char* filename, linker_file_t* result) 163a4f67738SDoug Rabson { 164a4f67738SDoug Rabson #if 0 165a4f67738SDoug Rabson struct nameidata nd; 166a4f67738SDoug Rabson struct proc* p = curproc; /* XXX */ 167a4f67738SDoug Rabson int error = 0; 168a4f67738SDoug Rabson int resid; 169a4f67738SDoug Rabson struct exec header; 170a4f67738SDoug Rabson elf_file_t ef; 171a4f67738SDoug Rabson linker_file_t lf; 172a4f67738SDoug Rabson 173a4f67738SDoug Rabson NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p); 174a4f67738SDoug Rabson error = vn_open(&nd, FREAD, 0); 175a4f67738SDoug Rabson if (error) 176a4f67738SDoug Rabson return error; 177a4f67738SDoug Rabson 178a4f67738SDoug Rabson /* 179a4f67738SDoug Rabson * Read the a.out header from the file. 180a4f67738SDoug Rabson */ 181a4f67738SDoug Rabson error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &header, sizeof header, 0, 182a4f67738SDoug Rabson UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 183a4f67738SDoug Rabson if (error) 184a4f67738SDoug Rabson goto out; 185a4f67738SDoug Rabson 186a4f67738SDoug Rabson if (N_BADMAG(header) || !(N_GETFLAG(header) & EX_DYNAMIC)) 187a4f67738SDoug Rabson goto out; 188a4f67738SDoug Rabson 189a4f67738SDoug Rabson /* 190a4f67738SDoug Rabson * We have an a.out file, so make some space to read it in. 191a4f67738SDoug Rabson */ 192a4f67738SDoug Rabson ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK); 193a4f67738SDoug Rabson ef->address = malloc(header.a_text + header.a_data + header.a_bss, 194a4f67738SDoug Rabson M_LINKER, M_WAITOK); 195a4f67738SDoug Rabson 196a4f67738SDoug Rabson /* 197a4f67738SDoug Rabson * Read the text and data sections and zero the bss. 198a4f67738SDoug Rabson */ 199a4f67738SDoug Rabson error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) ef->address, 200a4f67738SDoug Rabson header.a_text + header.a_data, 0, 201a4f67738SDoug Rabson UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); 202a4f67738SDoug Rabson if (error) 203a4f67738SDoug Rabson goto out; 204a4f67738SDoug Rabson bzero(ef->address + header.a_text + header.a_data, header.a_bss); 205a4f67738SDoug Rabson 206a4f67738SDoug Rabson /* 207a4f67738SDoug Rabson * Assume _DYNAMIC is the first data item. 208a4f67738SDoug Rabson */ 209a4f67738SDoug Rabson ef->dynamic = (struct _dynamic*) (ef->address + header.a_text); 210a4f67738SDoug Rabson if (ef->dynamic->d_version != LD_VERSION_BSD) { 211a4f67738SDoug Rabson free(ef->address, M_LINKER); 212a4f67738SDoug Rabson free(ef, M_LINKER); 213a4f67738SDoug Rabson goto out; 214a4f67738SDoug Rabson } 215a4f67738SDoug Rabson (long) ef->dynamic->d_un.d_sdt += ef->address; 216a4f67738SDoug Rabson 217a4f67738SDoug Rabson lf = linker_make_file(filename, ef, &link_elf_file_ops); 218a4f67738SDoug Rabson if (lf == NULL) { 219a4f67738SDoug Rabson free(ef->address, M_LINKER); 220a4f67738SDoug Rabson free(ef, M_LINKER); 221a4f67738SDoug Rabson error = ENOMEM; 222a4f67738SDoug Rabson goto out; 223a4f67738SDoug Rabson } 224a4f67738SDoug Rabson lf->address = ef->address; 225a4f67738SDoug Rabson lf->size = header.a_text + header.a_data + header.a_bss; 226a4f67738SDoug Rabson 227a4f67738SDoug Rabson if ((error = load_dependancies(lf)) != 0 228a4f67738SDoug Rabson || (error = relocate_file(lf)) != 0) { 229a4f67738SDoug Rabson linker_file_unload(lf); 230a4f67738SDoug Rabson goto out; 231a4f67738SDoug Rabson } 232a4f67738SDoug Rabson 233a4f67738SDoug Rabson *result = lf; 234a4f67738SDoug Rabson 235a4f67738SDoug Rabson out: 236a4f67738SDoug Rabson VOP_UNLOCK(nd.ni_vp, 0, p); 237a4f67738SDoug Rabson vn_close(nd.ni_vp, FREAD, p->p_ucred, p); 238a4f67738SDoug Rabson 239a4f67738SDoug Rabson return error; 240a4f67738SDoug Rabson #else 241a4f67738SDoug Rabson return ENOEXEC; 242a4f67738SDoug Rabson #endif 243a4f67738SDoug Rabson } 244a4f67738SDoug Rabson 245a4f67738SDoug Rabson static void 246a4f67738SDoug Rabson link_elf_unload(linker_file_t file) 247a4f67738SDoug Rabson { 248a4f67738SDoug Rabson elf_file_t ef = file->priv; 249a4f67738SDoug Rabson 250a4f67738SDoug Rabson if (ef) { 251a4f67738SDoug Rabson if (ef->address) 252a4f67738SDoug Rabson free(ef->address, M_LINKER); 253a4f67738SDoug Rabson free(ef, M_LINKER); 254a4f67738SDoug Rabson } 255a4f67738SDoug Rabson } 256a4f67738SDoug Rabson 257a4f67738SDoug Rabson #define ELF_RELOC(ef, type, off) (type*) ((ef)->address + (off)) 258a4f67738SDoug Rabson 259a4f67738SDoug Rabson static int 260a4f67738SDoug Rabson load_dependancies(linker_file_t lf) 261a4f67738SDoug Rabson { 262a4f67738SDoug Rabson #if 0 263a4f67738SDoug Rabson elf_file_t ef = lf->priv; 264a4f67738SDoug Rabson linker_file_t lfdep; 265a4f67738SDoug Rabson long off; 266a4f67738SDoug Rabson struct sod* sodp; 267a4f67738SDoug Rabson char* name; 268a4f67738SDoug Rabson char* filename = 0; 269a4f67738SDoug Rabson int error = 0; 270a4f67738SDoug Rabson 271a4f67738SDoug Rabson /* 272a4f67738SDoug Rabson * All files are dependant on /kernel. 273a4f67738SDoug Rabson */ 274a4f67738SDoug Rabson linker_kernel_file->refs++; 275a4f67738SDoug Rabson linker_file_add_dependancy(lf, linker_kernel_file); 276a4f67738SDoug Rabson 277a4f67738SDoug Rabson off = LD_NEED(ef->dynamic); 278a4f67738SDoug Rabson 279a4f67738SDoug Rabson /* 280a4f67738SDoug Rabson * Load the dependancies. 281a4f67738SDoug Rabson */ 282a4f67738SDoug Rabson while (off != 0) { 283a4f67738SDoug Rabson sodp = ELF_RELOC(ef, struct sod, off); 284a4f67738SDoug Rabson name = ELF_RELOC(ef, char, sodp->sod_name); 285a4f67738SDoug Rabson 286a4f67738SDoug Rabson /* 287a4f67738SDoug Rabson * Prepend pathname if dep is not an absolute filename. 288a4f67738SDoug Rabson */ 289a4f67738SDoug Rabson if (name[0] != '/') { 290a4f67738SDoug Rabson char* p; 291a4f67738SDoug Rabson filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 292a4f67738SDoug Rabson p = lf->filename + strlen(lf->filename) - 1; 293a4f67738SDoug Rabson while (p >= lf->filename && *p != '/') 294a4f67738SDoug Rabson p--; 295a4f67738SDoug Rabson if (p >= lf->filename) { 296a4f67738SDoug Rabson strncpy(filename, lf->filename, p - lf->filename); 297a4f67738SDoug Rabson filename[p - lf->filename] = '\0'; 298a4f67738SDoug Rabson strcat(filename, "/"); 299a4f67738SDoug Rabson strcat(filename, name); 300a4f67738SDoug Rabson name = filename; 301a4f67738SDoug Rabson } 302a4f67738SDoug Rabson } 303a4f67738SDoug Rabson error = linker_load_file(name, &lfdep); 304a4f67738SDoug Rabson if (error) 305a4f67738SDoug Rabson goto out; 306a4f67738SDoug Rabson error = linker_file_add_dependancy(lf, lfdep); 307a4f67738SDoug Rabson if (error) 308a4f67738SDoug Rabson goto out; 309a4f67738SDoug Rabson off = sodp->sod_next; 310a4f67738SDoug Rabson } 311a4f67738SDoug Rabson 312a4f67738SDoug Rabson out: 313a4f67738SDoug Rabson if (filename) 314a4f67738SDoug Rabson free(filename, M_TEMP); 315a4f67738SDoug Rabson return error; 316a4f67738SDoug Rabson #else 317a4f67738SDoug Rabson return ENOEXEC; 318a4f67738SDoug Rabson #endif 319a4f67738SDoug Rabson } 320a4f67738SDoug Rabson 321a4f67738SDoug Rabson #if 0 322a4f67738SDoug Rabson /* 323a4f67738SDoug Rabson * XXX i386 dependant. 324a4f67738SDoug Rabson */ 325a4f67738SDoug Rabson static long 326a4f67738SDoug Rabson read_relocation(struct relocation_info* r, char* addr) 327a4f67738SDoug Rabson { 328a4f67738SDoug Rabson int length = r->r_length; 329a4f67738SDoug Rabson if (length == 0) 330a4f67738SDoug Rabson return *(u_char*) addr; 331a4f67738SDoug Rabson else if (length == 1) 332a4f67738SDoug Rabson return *(u_short*) addr; 333a4f67738SDoug Rabson else if (length == 2) 334a4f67738SDoug Rabson return *(u_int*) addr; 335a4f67738SDoug Rabson else 336a4f67738SDoug Rabson printf("link_elf: unsupported relocation size %d\n", r->r_length); 337a4f67738SDoug Rabson return 0; 338a4f67738SDoug Rabson } 339a4f67738SDoug Rabson 340a4f67738SDoug Rabson static void 341a4f67738SDoug Rabson write_relocation(struct relocation_info* r, char* addr, long value) 342a4f67738SDoug Rabson { 343a4f67738SDoug Rabson int length = r->r_length; 344a4f67738SDoug Rabson if (length == 0) 345a4f67738SDoug Rabson *(u_char*) addr = value; 346a4f67738SDoug Rabson else if (length == 1) 347a4f67738SDoug Rabson *(u_short*) addr = value; 348a4f67738SDoug Rabson else if (length == 2) 349a4f67738SDoug Rabson *(u_int*) addr = value; 350a4f67738SDoug Rabson else 351a4f67738SDoug Rabson printf("link_elf: unsupported relocation size %d\n", r->r_length); 352a4f67738SDoug Rabson } 353a4f67738SDoug Rabson 354a4f67738SDoug Rabson static int 355a4f67738SDoug Rabson relocate_file(linker_file_t lf) 356a4f67738SDoug Rabson { 357a4f67738SDoug Rabson elf_file_t ef = lf->priv; 358a4f67738SDoug Rabson struct relocation_info* rel; 359a4f67738SDoug Rabson struct relocation_info* erel; 360a4f67738SDoug Rabson struct relocation_info* r; 361a4f67738SDoug Rabson struct nzlist* symbolbase; 362a4f67738SDoug Rabson char* stringbase; 363a4f67738SDoug Rabson struct nzlist* np; 364a4f67738SDoug Rabson char* sym; 365a4f67738SDoug Rabson long relocation; 366a4f67738SDoug Rabson 367a4f67738SDoug Rabson rel = ELF_RELOC(ef, struct relocation_info, LD_REL(ef->dynamic)); 368a4f67738SDoug Rabson erel = ELF_RELOC(ef, struct relocation_info, 369a4f67738SDoug Rabson LD_REL(ef->dynamic) + LD_RELSZ(ef->dynamic)); 370a4f67738SDoug Rabson symbolbase = ELF_RELOC(ef, struct nzlist, LD_SYMBOL(ef->dynamic)); 371a4f67738SDoug Rabson stringbase = ELF_RELOC(ef, char, LD_STRINGS(ef->dynamic)); 372a4f67738SDoug Rabson 373a4f67738SDoug Rabson for (r = rel; r < erel; r++) { 374a4f67738SDoug Rabson char* addr; 375a4f67738SDoug Rabson 376a4f67738SDoug Rabson if (r->r_address == 0) 377a4f67738SDoug Rabson break; 378a4f67738SDoug Rabson 379a4f67738SDoug Rabson addr = ELF_RELOC(ef, char, r->r_address); 380a4f67738SDoug Rabson if (r->r_extern) { 381a4f67738SDoug Rabson np = &symbolbase[r->r_symbolnum]; 382a4f67738SDoug Rabson sym = &stringbase[np->nz_strx]; 383a4f67738SDoug Rabson 384a4f67738SDoug Rabson if (sym[0] != '_') { 385a4f67738SDoug Rabson printf("link_elf: bad symbol name %s\n", sym); 386a4f67738SDoug Rabson relocation = 0; 387a4f67738SDoug Rabson } else 388a4f67738SDoug Rabson relocation = (long) 389a4f67738SDoug Rabson linker_file_lookup_symbol(lf, sym + 1, 390a4f67738SDoug Rabson np->nz_type != (N_SETV+N_EXT)); 391a4f67738SDoug Rabson if (!relocation) { 392a4f67738SDoug Rabson printf("link_elf: symbol %s not found\n", sym); 393a4f67738SDoug Rabson return ENOENT; 394a4f67738SDoug Rabson } 395a4f67738SDoug Rabson 396a4f67738SDoug Rabson relocation += read_relocation(r, addr); 397a4f67738SDoug Rabson 398a4f67738SDoug Rabson if (r->r_jmptable) { 399a4f67738SDoug Rabson printf("link_elf: can't cope with jump table relocations\n"); 400a4f67738SDoug Rabson continue; 401a4f67738SDoug Rabson } 402a4f67738SDoug Rabson 403a4f67738SDoug Rabson if (r->r_pcrel) 404a4f67738SDoug Rabson relocation -= (long) ef->address; 405a4f67738SDoug Rabson 406a4f67738SDoug Rabson if (r->r_copy) { 407a4f67738SDoug Rabson printf("link_elf: can't cope with copy relocations\n"); 408a4f67738SDoug Rabson continue; 409a4f67738SDoug Rabson } 410a4f67738SDoug Rabson 411a4f67738SDoug Rabson write_relocation(r, addr, relocation); 412a4f67738SDoug Rabson } else { 413a4f67738SDoug Rabson write_relocation(r, addr, 414a4f67738SDoug Rabson (long)(read_relocation(r, addr) + ef->address)); 415a4f67738SDoug Rabson } 416a4f67738SDoug Rabson 417a4f67738SDoug Rabson } 418a4f67738SDoug Rabson 419a4f67738SDoug Rabson return 0; 420a4f67738SDoug Rabson } 421a4f67738SDoug Rabson 422a4f67738SDoug Rabson static long 423a4f67738SDoug Rabson symbol_hash_value(elf_file_t ef, const char* name) 424a4f67738SDoug Rabson { 425a4f67738SDoug Rabson long hashval; 426a4f67738SDoug Rabson const char* p; 427a4f67738SDoug Rabson 428a4f67738SDoug Rabson hashval = '_'; /* fake a starting '_' for C symbols */ 429a4f67738SDoug Rabson for (p = name; *p; p++) 430a4f67738SDoug Rabson hashval = (hashval << 1) + *p; 431a4f67738SDoug Rabson 432a4f67738SDoug Rabson return (hashval & 0x7fffffff) % LD_BUCKETS(ef->dynamic); 433a4f67738SDoug Rabson } 434a4f67738SDoug Rabson 435a4f67738SDoug Rabson #endif 436a4f67738SDoug Rabson 437a4f67738SDoug Rabson int 438a4f67738SDoug Rabson link_elf_lookup_symbol(linker_file_t lf, const char* name, linker_sym_t* sym) 439a4f67738SDoug Rabson { 440a4f67738SDoug Rabson elf_file_t ef = lf->priv; 441a4f67738SDoug Rabson int symcount = ef->nchains; 442a4f67738SDoug Rabson Elf_Sym* es; 443a4f67738SDoug Rabson int i; 444a4f67738SDoug Rabson 445a4f67738SDoug Rabson /* XXX use hash table */ 446a4f67738SDoug Rabson for (i = 0, es = ef->symtab; i < ef->nchains; i++, es++) { 447a4f67738SDoug Rabson if (es->st_name == 0) 448a4f67738SDoug Rabson continue; 449a4f67738SDoug Rabson if (!strcmp(ef->strtab + es->st_name, name)) { 450a4f67738SDoug Rabson *sym = (linker_sym_t) es; 451a4f67738SDoug Rabson return 0; 452a4f67738SDoug Rabson } 453a4f67738SDoug Rabson } 454a4f67738SDoug Rabson 455a4f67738SDoug Rabson return ENOENT; 456a4f67738SDoug Rabson } 457a4f67738SDoug Rabson 458a4f67738SDoug Rabson static void 459a4f67738SDoug Rabson link_elf_symbol_values(linker_file_t lf, linker_sym_t sym, linker_symval_t* symval) 460a4f67738SDoug Rabson { 461a4f67738SDoug Rabson elf_file_t ef = lf->priv; 462a4f67738SDoug Rabson Elf_Sym* es = (Elf_Sym*) sym; 463a4f67738SDoug Rabson 464a4f67738SDoug Rabson symval->name = ef->strtab + es->st_name; 465a4f67738SDoug Rabson symval->value = (caddr_t) es->st_value; 466a4f67738SDoug Rabson symval->size = es->st_size; 467a4f67738SDoug Rabson } 468a4f67738SDoug Rabson 469a4f67738SDoug Rabson static int 470a4f67738SDoug Rabson link_elf_search_symbol(linker_file_t lf, caddr_t value, 471a4f67738SDoug Rabson linker_sym_t* sym, long* diffp) 472a4f67738SDoug Rabson { 473a4f67738SDoug Rabson elf_file_t ef = lf->priv; 474a4f67738SDoug Rabson u_long off = (u_long) value; 475a4f67738SDoug Rabson u_long diff = off; 476a4f67738SDoug Rabson int symcount = ef->nchains; 477a4f67738SDoug Rabson Elf_Sym* es; 478a4f67738SDoug Rabson Elf_Sym* best = 0; 479a4f67738SDoug Rabson int i; 480a4f67738SDoug Rabson 481a4f67738SDoug Rabson for (i = 0, es = ef->symtab; i < ef->nchains; i++, es++) { 482a4f67738SDoug Rabson if (es->st_name == 0) 483a4f67738SDoug Rabson continue; 484a4f67738SDoug Rabson if (off >= es->st_value) { 485a4f67738SDoug Rabson if (off - es->st_value < diff) { 486a4f67738SDoug Rabson diff = off - es->st_value; 487a4f67738SDoug Rabson best = es; 488a4f67738SDoug Rabson if (diff == 0) 489a4f67738SDoug Rabson break; 490a4f67738SDoug Rabson } else if (off - es->st_value == diff) { 491a4f67738SDoug Rabson best = es; 492a4f67738SDoug Rabson } 493a4f67738SDoug Rabson } 494a4f67738SDoug Rabson } 495a4f67738SDoug Rabson if (best == 0) 496a4f67738SDoug Rabson *diffp = off; 497a4f67738SDoug Rabson else 498a4f67738SDoug Rabson *diffp = diff; 499a4f67738SDoug Rabson *sym = (linker_sym_t) best; 500a4f67738SDoug Rabson 501a4f67738SDoug Rabson return 0; 502a4f67738SDoug Rabson } 503a4f67738SDoug Rabson 504