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