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