link_elf.c revision 43309
1/*-
2 * Copyright (c) 1998 Doug Rabson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *	$Id: link_elf.c,v 1.13 1999/01/27 21:49:56 dillon Exp $
27 */
28
29#include <sys/param.h>
30#include <sys/kernel.h>
31#include <sys/systm.h>
32#include <sys/malloc.h>
33#include <sys/proc.h>
34#include <sys/namei.h>
35#include <sys/fcntl.h>
36#include <sys/vnode.h>
37#include <sys/linker.h>
38#include <machine/elf.h>
39
40#include <vm/vm.h>
41#include <vm/vm_prot.h>
42#include <vm/vm_param.h>
43#include <sys/lock.h>
44#include <vm/vm_object.h>
45#include <vm/vm_kern.h>
46#include <vm/vm_extern.h>
47#include <vm/pmap.h>
48#include <vm/vm_map.h>
49
50static int	link_elf_load_module(const char*, linker_file_t*);
51static int	link_elf_load_file(const char*, linker_file_t*);
52static int	link_elf_lookup_symbol(linker_file_t, const char*,
53				       c_linker_sym_t*);
54static int	link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*);
55static int	link_elf_search_symbol(linker_file_t, caddr_t value,
56				       c_linker_sym_t* sym, long* diffp);
57
58static void	link_elf_unload_file(linker_file_t);
59static void	link_elf_unload_module(linker_file_t);
60
61static struct linker_class_ops link_elf_class_ops = {
62    link_elf_load_module,
63};
64
65static struct linker_file_ops link_elf_file_ops = {
66    link_elf_lookup_symbol,
67    link_elf_symbol_values,
68    link_elf_search_symbol,
69    link_elf_unload_file,
70};
71
72static struct linker_file_ops link_elf_module_ops = {
73    link_elf_lookup_symbol,
74    link_elf_symbol_values,
75    link_elf_search_symbol,
76    link_elf_unload_module,
77};
78typedef struct elf_file {
79    caddr_t		address;	/* Relocation address */
80#ifdef SPARSE_MAPPING
81    vm_object_t		object;		/* VM object to hold file pages */
82#endif
83    const Elf_Dyn*	dynamic;	/* Symbol table etc. */
84    Elf_Off		nbuckets;	/* DT_HASH info */
85    Elf_Off		nchains;
86    const Elf_Off*	buckets;
87    const Elf_Off*	chains;
88    caddr_t		hash;
89    caddr_t		strtab;		/* DT_STRTAB */
90    int			strsz;		/* DT_STRSZ */
91    const Elf_Sym*	symtab;		/* DT_SYMTAB */
92    Elf_Addr*		got;		/* DT_PLTGOT */
93    const Elf_Rel*	pltrel;		/* DT_JMPREL */
94    int			pltrelsize;	/* DT_PLTRELSZ */
95    const Elf_Rela*	pltrela;	/* DT_JMPREL */
96    int			pltrelasize;	/* DT_PLTRELSZ */
97    const Elf_Rel*	rel;		/* DT_REL */
98    int			relsize;	/* DT_RELSZ */
99    const Elf_Rela*	rela;		/* DT_RELA */
100    int			relasize;	/* DT_RELASZ */
101    caddr_t		modptr;
102    const Elf_Sym*	ddbsymtab;	/* The symbol table we are using */
103    long		ddbsymcnt;	/* Number of symbols */
104    caddr_t		ddbstrtab;	/* String table */
105    long		ddbstrcnt;	/* number of bytes in string table */
106    caddr_t		symbase;	/* malloc'ed symbold base */
107    caddr_t		strbase;	/* malloc'ed string base */
108} *elf_file_t;
109
110static int		parse_dynamic(linker_file_t lf);
111static int		load_dependancies(linker_file_t lf);
112static int		relocate_file(linker_file_t lf);
113static int		parse_module_symbols(linker_file_t lf);
114
115/*
116 * The kernel symbol table starts here.
117 */
118extern struct _dynamic _DYNAMIC;
119
120static void
121link_elf_init(void* arg)
122{
123#ifdef __ELF__
124    Elf_Dyn	*dp;
125    caddr_t	modptr, baseptr, sizeptr;
126    elf_file_t	ef;
127    char	*modname;
128#endif
129
130#if ELF_TARG_CLASS == ELFCLASS32
131    linker_add_class("elf32", NULL, &link_elf_class_ops);
132#else
133    linker_add_class("elf64", NULL, &link_elf_class_ops);
134#endif
135
136#ifdef __ELF__
137    dp = (Elf_Dyn*) &_DYNAMIC;
138    if (dp) {
139	ef = malloc(sizeof(struct elf_file), M_LINKER, M_NOWAIT);
140	if (ef == NULL)
141	    panic("link_elf_init: Can't create linker structures for kernel");
142	bzero(ef, sizeof(*ef));
143
144	ef->address = 0;
145#ifdef SPARSE_MAPPING
146	ef->object = 0;
147#endif
148	ef->dynamic = dp;
149	modname = NULL;
150	modptr = preload_search_by_type("elf kernel");
151	if (modptr)
152	    modname = (char *)preload_search_info(modptr, MODINFO_NAME);
153	if (modname == NULL)
154	    modname = "kernel";
155	linker_kernel_file = linker_make_file(modname, ef, &link_elf_file_ops);
156	if (linker_kernel_file == NULL)
157	    panic("link_elf_init: Can't create linker structures for kernel");
158	parse_dynamic(linker_kernel_file);
159	/* Sigh, magic constants. */
160#ifdef __alpha__
161	linker_kernel_file->address = (caddr_t) 0xfffffc0000300000;
162#else
163	linker_kernel_file->address = (caddr_t) 0xf0100000;
164#endif
165	linker_kernel_file->size = -(long)linker_kernel_file->address;
166
167	if (modptr) {
168	    ef->modptr = modptr;
169	    baseptr = preload_search_info(modptr, MODINFO_ADDR);
170	    if (baseptr)
171		linker_kernel_file->address = *(caddr_t *)baseptr;
172	    sizeptr = preload_search_info(modptr, MODINFO_SIZE);
173	    if (sizeptr)
174		linker_kernel_file->size = *(size_t *)sizeptr;
175	}
176	(void)parse_module_symbols(linker_kernel_file);
177	linker_current_file = linker_kernel_file;
178	linker_kernel_file->flags |= LINKER_FILE_LINKED;
179    }
180#endif
181}
182
183SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0);
184
185static int
186parse_module_symbols(linker_file_t lf)
187{
188    elf_file_t ef = lf->priv;
189    caddr_t	pointer;
190    caddr_t	ssym, esym, base;
191    caddr_t	strtab;
192    int		strcnt;
193    Elf_Sym*	symtab;
194    int		symcnt;
195
196    if (ef->modptr == NULL)
197	return 0;
198    pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM);
199    if (pointer == NULL)
200	return 0;
201    ssym = *(caddr_t *)pointer;
202    pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM);
203    if (pointer == NULL)
204	return 0;
205    esym = *(caddr_t *)pointer;
206
207    base = ssym;
208
209    symcnt = *(long *)base;
210    base += sizeof(long);
211    symtab = (Elf_Sym *)base;
212    base += roundup(symcnt, sizeof(long));
213
214    if (base > esym || base < ssym) {
215	printf("Symbols are corrupt!\n");
216	return EINVAL;
217    }
218
219    strcnt = *(long *)base;
220    base += sizeof(long);
221    strtab = base;
222    base += roundup(strcnt, sizeof(long));
223
224    if (base > esym || base < ssym) {
225	printf("Symbols are corrupt!\n");
226	return EINVAL;
227    }
228
229    ef->ddbsymtab = symtab;
230    ef->ddbsymcnt = symcnt / sizeof(Elf_Sym);
231    ef->ddbstrtab = strtab;
232    ef->ddbstrcnt = strcnt;
233
234    return 0;
235}
236
237static int
238parse_dynamic(linker_file_t lf)
239{
240    elf_file_t ef = lf->priv;
241    const Elf_Dyn *dp;
242    int plttype = DT_REL;
243
244    for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
245	switch (dp->d_tag) {
246	case DT_HASH:
247	{
248	    /* From src/libexec/rtld-elf/rtld.c */
249	    const Elf_Off *hashtab = (const Elf_Off *)
250		(ef->address + dp->d_un.d_ptr);
251	    ef->nbuckets = hashtab[0];
252	    ef->nchains = hashtab[1];
253	    ef->buckets = hashtab + 2;
254	    ef->chains = ef->buckets + ef->nbuckets;
255	    break;
256	}
257	case DT_STRTAB:
258	    ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr);
259	    break;
260	case DT_STRSZ:
261	    ef->strsz = dp->d_un.d_val;
262	    break;
263	case DT_SYMTAB:
264	    ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr);
265	    break;
266	case DT_SYMENT:
267	    if (dp->d_un.d_val != sizeof(Elf_Sym))
268		return ENOEXEC;
269	    break;
270	case DT_PLTGOT:
271	    ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr);
272	    break;
273	case DT_REL:
274	    ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr);
275	    break;
276	case DT_RELSZ:
277	    ef->relsize = dp->d_un.d_val;
278	    break;
279	case DT_RELENT:
280	    if (dp->d_un.d_val != sizeof(Elf_Rel))
281		return ENOEXEC;
282	    break;
283	case DT_JMPREL:
284	    ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr);
285	    break;
286	case DT_PLTRELSZ:
287	    ef->pltrelsize = dp->d_un.d_val;
288	    break;
289	case DT_RELA:
290	    ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr);
291	    break;
292	case DT_RELASZ:
293	    ef->relasize = dp->d_un.d_val;
294	    break;
295	case DT_RELAENT:
296	    if (dp->d_un.d_val != sizeof(Elf_Rela))
297		return ENOEXEC;
298	    break;
299	case DT_PLTREL:
300	    plttype = dp->d_un.d_val;
301	    if (plttype != DT_REL && plttype != DT_RELA)
302		return ENOEXEC;
303	    break;
304	}
305    }
306
307    if (plttype == DT_RELA) {
308	ef->pltrela = (const Elf_Rela *) ef->pltrel;
309	ef->pltrel = NULL;
310	ef->pltrelasize = ef->pltrelsize;
311	ef->pltrelsize = 0;
312    }
313
314    ef->ddbsymtab = ef->symtab;
315    ef->ddbsymcnt = ef->nchains;
316    ef->ddbstrtab = ef->strtab;
317    ef->ddbstrcnt = ef->strsz;
318
319    return 0;
320}
321
322static void
323link_elf_error(const char *s)
324{
325    printf("kldload: %s\n", s);
326}
327
328static int
329link_elf_load_module(const char *filename, linker_file_t *result)
330{
331    caddr_t		modptr, baseptr, sizeptr, dynptr;
332    char		*type;
333    elf_file_t		ef;
334    linker_file_t	lf;
335    int			error;
336    vm_offset_t		dp;
337
338    /* Look to see if we have the module preloaded */
339    modptr = preload_search_by_name(filename);
340    if (modptr == NULL)
341	return (link_elf_load_file(filename, result));
342
343    /* It's preloaded, check we can handle it and collect information */
344    type = (char *)preload_search_info(modptr, MODINFO_TYPE);
345    baseptr = preload_search_info(modptr, MODINFO_ADDR);
346    sizeptr = preload_search_info(modptr, MODINFO_SIZE);
347    dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC);
348    if (type == NULL || strcmp(type, "elf module") != 0)
349	return (EFTYPE);
350    if (baseptr == NULL || sizeptr == NULL || dynptr == NULL)
351	return (EINVAL);
352
353    ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK);
354    if (ef == NULL)
355	return (ENOMEM);
356    bzero(ef, sizeof(*ef));
357    ef->modptr = modptr;
358    ef->address = *(caddr_t *)baseptr;
359#ifdef SPARSE_MAPPING
360    ef->object = 0;
361#endif
362    dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr;
363    ef->dynamic = (Elf_Dyn *)dp;
364    lf = linker_make_file(filename, ef, &link_elf_module_ops);
365    if (lf == NULL) {
366	free(ef, M_LINKER);
367	return ENOMEM;
368    }
369    lf->address = ef->address;
370    lf->size = *(size_t *)sizeptr;
371
372    error = parse_dynamic(lf);
373    if (error) {
374	linker_file_unload(lf);
375	return error;
376    }
377    error = load_dependancies(lf);
378    if (error) {
379	linker_file_unload(lf);
380	return error;
381    }
382    error = relocate_file(lf);
383    if (error) {
384	linker_file_unload(lf);
385	return error;
386    }
387    (void)parse_module_symbols(lf);
388    lf->flags |= LINKER_FILE_LINKED;
389    *result = lf;
390    return (0);
391}
392
393static int
394link_elf_load_file(const char* filename, linker_file_t* result)
395{
396    struct nameidata nd;
397    struct proc* p = curproc;	/* XXX */
398    Elf_Ehdr *hdr;
399    caddr_t firstpage;
400    int nbytes, i;
401    Elf_Phdr *phdr;
402    Elf_Phdr *phlimit;
403    Elf_Phdr *segs[2];
404    int nsegs;
405    Elf_Phdr *phdyn;
406    Elf_Phdr *phphdr;
407    caddr_t mapbase;
408    size_t mapsize;
409    Elf_Off base_offset;
410    Elf_Addr base_vaddr;
411    Elf_Addr base_vlimit;
412    int error = 0;
413    int resid;
414    elf_file_t ef;
415    linker_file_t lf;
416    char *pathname;
417    Elf_Shdr *shdr;
418    int symtabindex;
419    int symstrindex;
420    int symcnt;
421    int strcnt;
422
423    shdr = NULL;
424    lf = NULL;
425
426    pathname = linker_search_path(filename);
427    if (pathname == NULL)
428	return ENOENT;
429
430    NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pathname, p);
431    error = vn_open(&nd, FREAD, 0);
432    free(pathname, M_LINKER);
433    if (error)
434	return error;
435
436    /*
437     * Read the elf header from the file.
438     */
439    firstpage = malloc(PAGE_SIZE, M_LINKER, M_WAITOK);
440    if (firstpage == NULL) {
441	error = ENOMEM;
442	goto out;
443    }
444    hdr = (Elf_Ehdr *)firstpage;
445    error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0,
446		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
447    nbytes = PAGE_SIZE - resid;
448    if (error)
449	goto out;
450
451    if (!IS_ELF(*hdr)) {
452	error = ENOEXEC;
453	goto out;
454    }
455
456    if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS
457      || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) {
458	link_elf_error("Unsupported file layout");
459	error = ENOEXEC;
460	goto out;
461    }
462    if (hdr->e_ident[EI_VERSION] != EV_CURRENT
463      || hdr->e_version != EV_CURRENT) {
464	link_elf_error("Unsupported file version");
465	error = ENOEXEC;
466	goto out;
467    }
468    if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) {
469	link_elf_error("Unsupported file type");
470	error = ENOEXEC;
471	goto out;
472    }
473    if (hdr->e_machine != ELF_TARG_MACH) {
474	link_elf_error("Unsupported machine");
475	error = ENOEXEC;
476	goto out;
477    }
478
479    /*
480     * We rely on the program header being in the first page.  This is
481     * not strictly required by the ABI specification, but it seems to
482     * always true in practice.  And, it simplifies things considerably.
483     */
484    if (!((hdr->e_phentsize == sizeof(Elf_Phdr)) &&
485	  (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) &&
486	  (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= nbytes)))
487	link_elf_error("Unreadable program headers");
488
489    /*
490     * Scan the program header entries, and save key information.
491     *
492     * We rely on there being exactly two load segments, text and data,
493     * in that order.
494     */
495    phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff);
496    phlimit = phdr + hdr->e_phnum;
497    nsegs = 0;
498    phdyn = NULL;
499    phphdr = NULL;
500    while (phdr < phlimit) {
501	switch (phdr->p_type) {
502
503	case PT_LOAD:
504	    if (nsegs == 2) {
505		link_elf_error("Too many sections");
506		error = ENOEXEC;
507		goto out;
508	    }
509	    segs[nsegs] = phdr;
510	    ++nsegs;
511	    break;
512
513	case PT_PHDR:
514	    phphdr = phdr;
515	    break;
516
517	case PT_DYNAMIC:
518	    phdyn = phdr;
519	    break;
520	}
521
522	++phdr;
523    }
524    if (phdyn == NULL) {
525	link_elf_error("Object is not dynamically-linked");
526	error = ENOEXEC;
527	goto out;
528    }
529
530    /*
531     * Allocate the entire address space of the object, to stake out our
532     * contiguous region, and to establish the base address for relocation.
533     */
534    base_offset = trunc_page(segs[0]->p_offset);
535    base_vaddr = trunc_page(segs[0]->p_vaddr);
536    base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz);
537    mapsize = base_vlimit - base_vaddr;
538
539    ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK);
540    bzero(ef, sizeof(*ef));
541#ifdef SPARSE_MAPPING
542    ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT);
543    if (ef->object == NULL) {
544	free(ef, M_LINKER);
545	error = ENOMEM;
546	goto out;
547    }
548    vm_object_reference(ef->object);
549    ef->address = (caddr_t) vm_map_min(kernel_map);
550    error = vm_map_find(kernel_map, ef->object, 0,
551			(vm_offset_t *) &ef->address,
552			mapsize, 1,
553			VM_PROT_ALL, VM_PROT_ALL, 0);
554    if (error) {
555	vm_object_deallocate(ef->object);
556	free(ef, M_LINKER);
557	goto out;
558    }
559#else
560    ef->address = malloc(mapsize, M_LINKER, M_WAITOK);
561#endif
562    mapbase = ef->address;
563
564    /*
565     * Read the text and data sections and zero the bss.
566     */
567    for (i = 0; i < 2; i++) {
568	caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr;
569	error = vn_rdwr(UIO_READ, nd.ni_vp,
570			segbase, segs[i]->p_filesz, segs[i]->p_offset,
571			UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
572	if (error) {
573#ifdef SPARSE_MAPPING
574	    vm_map_remove(kernel_map, (vm_offset_t) ef->address,
575			  (vm_offset_t) ef->address
576			  + (ef->object->size << PAGE_SHIFT));
577	    vm_object_deallocate(ef->object);
578#else
579	    free(ef->address, M_LINKER);
580#endif
581	    free(ef, M_LINKER);
582	    goto out;
583	}
584	bzero(segbase + segs[i]->p_filesz,
585	      segs[i]->p_memsz - segs[i]->p_filesz);
586
587#ifdef SPARSE_MAPPING
588	/*
589	 * Wire down the pages
590	 */
591	vm_map_pageable(kernel_map,
592			(vm_offset_t) segbase,
593			(vm_offset_t) segbase + segs[i]->p_memsz,
594			FALSE);
595#endif
596    }
597
598    ef->dynamic = (const Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr);
599
600    lf = linker_make_file(filename, ef, &link_elf_file_ops);
601    if (lf == NULL) {
602#ifdef SPARSE_MAPPING
603	vm_map_remove(kernel_map, (vm_offset_t) ef->address,
604		      (vm_offset_t) ef->address
605		      + (ef->object->size << PAGE_SHIFT));
606	vm_object_deallocate(ef->object);
607#else
608	free(ef->address, M_LINKER);
609#endif
610	free(ef, M_LINKER);
611	error = ENOMEM;
612	goto out;
613    }
614    lf->address = ef->address;
615    lf->size = mapsize;
616
617    error = parse_dynamic(lf);
618    if (error)
619	goto out;
620    error = load_dependancies(lf);
621    if (error)
622	goto out;
623    error = relocate_file(lf);
624    if (error)
625	goto out;
626
627    /* Try and load the symbol table if it's present.  (you can strip it!) */
628    nbytes = hdr->e_shnum * hdr->e_shentsize;
629    if (nbytes == 0 || hdr->e_shoff == 0)
630	goto nosyms;
631    shdr = malloc(nbytes, M_LINKER, M_WAITOK);
632    if (shdr == NULL) {
633	error = ENOMEM;
634	goto out;
635    }
636    bzero(shdr, nbytes);
637    error = vn_rdwr(UIO_READ, nd.ni_vp,
638		    (caddr_t)shdr, nbytes, hdr->e_shoff,
639		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
640    if (error)
641	goto out;
642    symtabindex = -1;
643    symstrindex = -1;
644    for (i = 0; i < hdr->e_shnum; i++) {
645	if (shdr[i].sh_type == SHT_SYMTAB) {
646	    symtabindex = i;
647	    symstrindex = shdr[i].sh_link;
648	}
649    }
650    if (symtabindex < 0 || symstrindex < 0)
651	goto nosyms;
652
653    symcnt = shdr[symtabindex].sh_size;
654    ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK);
655    strcnt = shdr[symstrindex].sh_size;
656    ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK);
657
658    if (ef->symbase == NULL || ef->strbase == NULL) {
659	error = ENOMEM;
660	goto out;
661    }
662    error = vn_rdwr(UIO_READ, nd.ni_vp,
663		    ef->symbase, symcnt, shdr[symtabindex].sh_offset,
664		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
665    if (error)
666	goto out;
667    error = vn_rdwr(UIO_READ, nd.ni_vp,
668		    ef->strbase, strcnt, shdr[symstrindex].sh_offset,
669		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
670    if (error)
671	goto out;
672
673    ef->ddbsymcnt = symcnt / sizeof(Elf_Sym);
674    ef->ddbsymtab = (const Elf_Sym *)ef->symbase;
675    ef->ddbstrcnt = strcnt;
676    ef->ddbstrtab = ef->strbase;
677
678    lf->flags |= LINKER_FILE_LINKED;
679
680nosyms:
681
682    *result = lf;
683
684out:
685    if (error && lf)
686	linker_file_unload(lf);
687    if (shdr)
688	free(shdr, M_LINKER);
689    if (firstpage)
690	free(firstpage, M_LINKER);
691    VOP_UNLOCK(nd.ni_vp, 0, p);
692    vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
693
694    return error;
695}
696
697static void
698link_elf_unload_file(linker_file_t file)
699{
700    elf_file_t ef = file->priv;
701
702    if (ef) {
703#ifdef SPARSE_MAPPING
704	if (ef->object) {
705	    vm_map_remove(kernel_map, (vm_offset_t) ef->address,
706			  (vm_offset_t) ef->address
707			  + (ef->object->size << PAGE_SHIFT));
708	    vm_object_deallocate(ef->object);
709	}
710#else
711	if (ef->address)
712	    free(ef->address, M_LINKER);
713#endif
714	if (ef->symbase)
715	    free(ef->symbase, M_LINKER);
716	if (ef->strbase)
717	    free(ef->strbase, M_LINKER);
718	free(ef, M_LINKER);
719    }
720}
721
722static void
723link_elf_unload_module(linker_file_t file)
724{
725    elf_file_t ef = file->priv;
726
727    if (ef)
728	free(ef, M_LINKER);
729    if (file->filename)
730	preload_delete_name(file->filename);
731}
732
733static int
734load_dependancies(linker_file_t lf)
735{
736    elf_file_t ef = lf->priv;
737    linker_file_t lfdep;
738    char* name;
739    const Elf_Dyn *dp;
740    int error = 0;
741
742    /*
743     * All files are dependant on /kernel.
744     */
745    if (linker_kernel_file) {
746	linker_kernel_file->refs++;
747	linker_file_add_dependancy(lf, linker_kernel_file);
748    }
749
750    for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
751	if (dp->d_tag == DT_NEEDED) {
752	    name = ef->strtab + dp->d_un.d_val;
753
754	    error = linker_load_file(name, &lfdep);
755	    if (error)
756		goto out;
757	    error = linker_file_add_dependancy(lf, lfdep);
758	    if (error)
759		goto out;
760	}
761    }
762
763out:
764    return error;
765}
766
767static const char *
768symbol_name(elf_file_t ef, Elf_Word r_info)
769{
770    const Elf_Sym *ref;
771
772    if (ELF_R_SYM(r_info)) {
773	ref = ef->symtab + ELF_R_SYM(r_info);
774	return ef->strtab + ref->st_name;
775    } else
776	return NULL;
777}
778
779static int
780relocate_file(linker_file_t lf)
781{
782    elf_file_t ef = lf->priv;
783    const Elf_Rel *rellim;
784    const Elf_Rel *rel;
785    const Elf_Rela *relalim;
786    const Elf_Rela *rela;
787    const char *symname;
788
789    /* Perform relocations without addend if there are any: */
790    rel = ef->rel;
791    if (rel) {
792	rellim = (const Elf_Rel *) ((c_caddr_t) ef->rel + ef->relsize);
793	while (rel < rellim) {
794	    symname = symbol_name(ef, rel->r_info);
795	    if (elf_reloc(lf, rel, ELF_RELOC_REL, symname)) {
796		printf("link_elf: symbol %s undefined\n", symname);
797		return ENOENT;
798	    }
799	    rel++;
800	}
801    }
802
803    /* Perform relocations with addend if there are any: */
804    rela = ef->rela;
805    if (rela) {
806	relalim = (const Elf_Rela *) ((c_caddr_t) ef->rela + ef->relasize);
807	while (rela < relalim) {
808	    symname = symbol_name(ef, rela->r_info);
809	    if (elf_reloc(lf, rela, ELF_RELOC_RELA, symname)) {
810		printf("link_elf: symbol %s undefined\n", symname);
811		return ENOENT;
812	    }
813	    rela++;
814	}
815    }
816
817    /* Perform PLT relocations without addend if there are any: */
818    rel = ef->pltrel;
819    if (rel) {
820	rellim = (const Elf_Rel *) ((c_caddr_t) ef->pltrel + ef->pltrelsize);
821	while (rel < rellim) {
822	    symname = symbol_name(ef, rel->r_info);
823	    if (elf_reloc(lf, rel, ELF_RELOC_REL, symname)) {
824		printf("link_elf: symbol %s undefined\n", symname);
825		return ENOENT;
826	    }
827	    rel++;
828	}
829    }
830
831    /* Perform relocations with addend if there are any: */
832    rela = ef->pltrela;
833    if (rela) {
834	relalim = (const Elf_Rela *) ((c_caddr_t) ef->pltrela + ef->pltrelasize);
835	while (rela < relalim) {
836	    symname = symbol_name(ef, rela->r_info);
837	    if (elf_reloc(lf, rela, ELF_RELOC_RELA, symname)) {
838		printf("link_elf: symbol %s undefined\n", symname);
839		return ENOENT;
840	    }
841	    rela++;
842	}
843    }
844
845    return 0;
846}
847
848/*
849 * Hash function for symbol table lookup.  Don't even think about changing
850 * this.  It is specified by the System V ABI.
851 */
852static unsigned long
853elf_hash(const char *name)
854{
855    const unsigned char *p = (const unsigned char *) name;
856    unsigned long h = 0;
857    unsigned long g;
858
859    while (*p != '\0') {
860	h = (h << 4) + *p++;
861	if ((g = h & 0xf0000000) != 0)
862	    h ^= g >> 24;
863	h &= ~g;
864    }
865    return h;
866}
867
868int
869link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym)
870{
871    elf_file_t ef = lf->priv;
872    unsigned long symnum;
873    const Elf_Sym* symp;
874    const char *strp;
875    unsigned long hash;
876    int i;
877
878    /* First, search hashed global symbols */
879    hash = elf_hash(name);
880    symnum = ef->buckets[hash % ef->nbuckets];
881
882    while (symnum != STN_UNDEF) {
883	if (symnum >= ef->nchains) {
884	    printf("link_elf_lookup_symbol: corrupt symbol table\n");
885	    return ENOENT;
886	}
887
888	symp = ef->symtab + symnum;
889	if (symp->st_name == 0) {
890	    printf("link_elf_lookup_symbol: corrupt symbol table\n");
891	    return ENOENT;
892	}
893
894	strp = ef->strtab + symp->st_name;
895
896	if (strcmp(name, strp) == 0) {
897	    if (symp->st_shndx != SHN_UNDEF ||
898		(symp->st_value != 0 &&
899		 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
900		*sym = (c_linker_sym_t) symp;
901		return 0;
902	    } else
903		return ENOENT;
904	}
905
906	symnum = ef->chains[symnum];
907    }
908
909    /* If we have not found it, look at the full table (if loaded) */
910    if (ef->symtab == ef->ddbsymtab)
911	return ENOENT;
912
913    /* Exhaustive search */
914    for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
915	strp = ef->ddbstrtab + symp->st_name;
916	if (strcmp(name, strp) == 0) {
917	    if (symp->st_shndx != SHN_UNDEF ||
918		(symp->st_value != 0 &&
919		 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
920		*sym = (c_linker_sym_t) symp;
921		return 0;
922	    } else
923		return ENOENT;
924	}
925    }
926
927    return ENOENT;
928}
929
930static int
931link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, linker_symval_t* symval)
932{
933	elf_file_t ef = lf->priv;
934	Elf_Sym* es = (Elf_Sym*) sym;
935
936	if (es >= ef->symtab && ((es - ef->symtab) < ef->nchains)) {
937	    symval->name = ef->strtab + es->st_name;
938	    symval->value = (caddr_t) ef->address + es->st_value;
939	    symval->size = es->st_size;
940	    return 0;
941	}
942	if (ef->symtab == ef->ddbsymtab)
943	    return ENOENT;
944	if (es >= ef->ddbsymtab && ((es - ef->ddbsymtab) < ef->ddbsymcnt)) {
945	    symval->name = ef->ddbstrtab + es->st_name;
946	    symval->value = (caddr_t) ef->address + es->st_value;
947	    symval->size = es->st_size;
948	    return 0;
949	}
950	return ENOENT;
951}
952
953static int
954link_elf_search_symbol(linker_file_t lf, caddr_t value,
955		       c_linker_sym_t* sym, long* diffp)
956{
957	elf_file_t ef = lf->priv;
958	u_long off = (u_long) value;
959	u_long diff = off;
960	const Elf_Sym* es;
961	const Elf_Sym* best = 0;
962	int i;
963
964	for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) {
965		if (es->st_name == 0)
966			continue;
967		if (off >= es->st_value) {
968			if (off - es->st_value < diff) {
969				diff = off - es->st_value;
970				best = es;
971				if (diff == 0)
972					break;
973			} else if (off - es->st_value == diff) {
974				best = es;
975			}
976		}
977	}
978	if (best == 0)
979		*diffp = off;
980	else
981		*diffp = diff;
982	*sym = (c_linker_sym_t) best;
983
984	return 0;
985}
986