link_elf.c revision 151430
138514Sdfr/*-
259603Sdfr * Copyright (c) 1998-2000 Doug Rabson
338514Sdfr * All rights reserved.
438514Sdfr *
538514Sdfr * Redistribution and use in source and binary forms, with or without
638514Sdfr * modification, are permitted provided that the following conditions
738514Sdfr * are met:
838514Sdfr * 1. Redistributions of source code must retain the above copyright
938514Sdfr *    notice, this list of conditions and the following disclaimer.
1038514Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1138514Sdfr *    notice, this list of conditions and the following disclaimer in the
1238514Sdfr *    documentation and/or other materials provided with the distribution.
1338514Sdfr *
1438514Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538514Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638514Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738514Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838514Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938514Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038514Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138514Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238514Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338514Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438514Sdfr * SUCH DAMAGE.
2538514Sdfr */
2638514Sdfr
27116182Sobrien#include <sys/cdefs.h>
28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/link_elf.c 151430 2005-10-17 23:21:55Z peter $");
29116182Sobrien
30131928Smarcel#include "opt_gdb.h"
31107089Srwatson#include "opt_mac.h"
3259603Sdfr
3338514Sdfr#include <sys/param.h>
3476166Smarkm#include <sys/systm.h>
35129443Sbde#ifdef GPROF
36129443Sbde#include <sys/gmon.h>
37129443Sbde#endif
3838514Sdfr#include <sys/kernel.h>
3976166Smarkm#include <sys/lock.h>
40107089Srwatson#include <sys/mac.h>
4138514Sdfr#include <sys/malloc.h>
4277642Sdd#include <sys/mutex.h>
4338514Sdfr#include <sys/proc.h>
4438514Sdfr#include <sys/namei.h>
4538514Sdfr#include <sys/fcntl.h>
4638514Sdfr#include <sys/vnode.h>
4738514Sdfr#include <sys/linker.h>
4876166Smarkm
4938514Sdfr#include <machine/elf.h>
5038514Sdfr
5139071Sdfr#include <vm/vm.h>
5239071Sdfr#include <vm/vm_param.h>
5352128Speter#ifdef SPARSE_MAPPING
5439071Sdfr#include <vm/vm_object.h>
5539071Sdfr#include <vm/vm_kern.h>
5639071Sdfr#include <vm/vm_extern.h>
5752128Speter#endif
5839071Sdfr#include <vm/pmap.h>
5939071Sdfr#include <vm/vm_map.h>
6076166Smarkm
61102288Speter#include <sys/link_elf.h>
6239071Sdfr
6359603Sdfr#include "linker_if.h"
6438514Sdfr
65151430Speter#define MAXSEGS 4
66151430Speter
6738514Sdfrtypedef struct elf_file {
6859603Sdfr    struct linker_file	lf;		/* Common fields */
6959603Sdfr    int			preloaded;	/* Was file pre-loaded */
7039071Sdfr    caddr_t		address;	/* Relocation address */
7139071Sdfr#ifdef SPARSE_MAPPING
7239071Sdfr    vm_object_t		object;		/* VM object to hold file pages */
7339071Sdfr#endif
7459603Sdfr    Elf_Dyn*		dynamic;	/* Symbol table etc. */
7580700Sjake    Elf_Hashelt		nbuckets;	/* DT_HASH info */
7680700Sjake    Elf_Hashelt		nchains;
7780700Sjake    const Elf_Hashelt*	buckets;
7880700Sjake    const Elf_Hashelt*	chains;
7938514Sdfr    caddr_t		hash;
8038514Sdfr    caddr_t		strtab;		/* DT_STRTAB */
8140254Speter    int			strsz;		/* DT_STRSZ */
8239071Sdfr    const Elf_Sym*	symtab;		/* DT_SYMTAB */
8339071Sdfr    Elf_Addr*		got;		/* DT_PLTGOT */
8439071Sdfr    const Elf_Rel*	pltrel;		/* DT_JMPREL */
8539071Sdfr    int			pltrelsize;	/* DT_PLTRELSZ */
8639071Sdfr    const Elf_Rela*	pltrela;	/* DT_JMPREL */
8739071Sdfr    int			pltrelasize;	/* DT_PLTRELSZ */
8839071Sdfr    const Elf_Rel*	rel;		/* DT_REL */
8939071Sdfr    int			relsize;	/* DT_RELSZ */
9039071Sdfr    const Elf_Rela*	rela;		/* DT_RELA */
9139071Sdfr    int			relasize;	/* DT_RELASZ */
9240254Speter    caddr_t		modptr;
9340254Speter    const Elf_Sym*	ddbsymtab;	/* The symbol table we are using */
9440254Speter    long		ddbsymcnt;	/* Number of symbols */
9540254Speter    caddr_t		ddbstrtab;	/* String table */
9640254Speter    long		ddbstrcnt;	/* number of bytes in string table */
9740292Speter    caddr_t		symbase;	/* malloc'ed symbold base */
9840292Speter    caddr_t		strbase;	/* malloc'ed string base */
99131928Smarcel#ifdef GDB
10059603Sdfr    struct link_map	gdb;		/* hooks for gdb */
10159603Sdfr#endif
10238514Sdfr} *elf_file_t;
10338514Sdfr
104105468Smarcelstatic int	link_elf_link_common_finish(linker_file_t);
10559751Speterstatic int	link_elf_link_preload(linker_class_t cls,
10659751Speter				      const char*, linker_file_t*);
10759751Speterstatic int	link_elf_link_preload_finish(linker_file_t);
10859751Speterstatic int	link_elf_load_file(linker_class_t, const char*, linker_file_t*);
10959603Sdfrstatic int	link_elf_lookup_symbol(linker_file_t, const char*,
11059603Sdfr				       c_linker_sym_t*);
11159603Sdfrstatic int	link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*);
11259603Sdfrstatic int	link_elf_search_symbol(linker_file_t, caddr_t value,
11359603Sdfr				       c_linker_sym_t* sym, long* diffp);
11438514Sdfr
11559603Sdfrstatic void	link_elf_unload_file(linker_file_t);
11659751Speterstatic void	link_elf_unload_preload(linker_file_t);
11778161Speterstatic int	link_elf_lookup_set(linker_file_t, const char *,
11878161Speter				    void ***, void ***, int *);
11985736Sgreenstatic int	link_elf_each_function_name(linker_file_t,
12085736Sgreen				int (*)(const char *, void *),
12185736Sgreen				void *);
122109605Sjakestatic void	link_elf_reloc_local(linker_file_t);
123129282Speterstatic Elf_Addr	elf_lookup(linker_file_t lf, Elf_Word symidx, int deps);
12459603Sdfr
12559603Sdfrstatic kobj_method_t link_elf_methods[] = {
12659603Sdfr    KOBJMETHOD(linker_lookup_symbol,	link_elf_lookup_symbol),
12759603Sdfr    KOBJMETHOD(linker_symbol_values,	link_elf_symbol_values),
12859603Sdfr    KOBJMETHOD(linker_search_symbol,	link_elf_search_symbol),
12959603Sdfr    KOBJMETHOD(linker_unload,		link_elf_unload_file),
13059751Speter    KOBJMETHOD(linker_load_file,	link_elf_load_file),
13159751Speter    KOBJMETHOD(linker_link_preload,	link_elf_link_preload),
13259751Speter    KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish),
13378161Speter    KOBJMETHOD(linker_lookup_set,	link_elf_lookup_set),
13485736Sgreen    KOBJMETHOD(linker_each_function_name, link_elf_each_function_name),
13559603Sdfr    { 0, 0 }
13659603Sdfr};
13759603Sdfr
13859603Sdfrstatic struct linker_class link_elf_class = {
13959603Sdfr#if ELF_TARG_CLASS == ELFCLASS32
14059603Sdfr    "elf32",
14159603Sdfr#else
14259603Sdfr    "elf64",
14359603Sdfr#endif
14459603Sdfr    link_elf_methods, sizeof(struct elf_file)
14559603Sdfr};
14659603Sdfr
14759603Sdfrstatic int		parse_dynamic(elf_file_t ef);
14859603Sdfrstatic int		relocate_file(elf_file_t ef);
14959751Speterstatic int		link_elf_preload_parse_symbols(elf_file_t ef);
15059603Sdfr
151131928Smarcel#ifdef GDB
15266719Sjhbstatic void		r_debug_state(struct r_debug *dummy_one,
15366719Sjhb				      struct link_map *dummy_two);
15459603Sdfr
15538514Sdfr/*
15659603Sdfr * A list of loaded modules for GDB to use for loading symbols.
15759603Sdfr */
15859603Sdfrstruct r_debug r_debug;
15959603Sdfr
16066719Sjhb#define GDB_STATE(s)	r_debug.r_state = s; r_debug_state(NULL, NULL);
16159603Sdfr
16259603Sdfr/*
16359603Sdfr * Function for the debugger to set a breakpoint on to gain control.
16459603Sdfr */
165104094Sphkstatic void
16666719Sjhbr_debug_state(struct r_debug *dummy_one __unused,
16766719Sjhb	      struct link_map *dummy_two __unused)
16859603Sdfr{
16959603Sdfr}
17059603Sdfr
171105467Smarcelstatic void
172105467Smarcellink_elf_add_gdb(struct link_map *l)
173105467Smarcel{
174105467Smarcel    struct link_map *prev;
17559603Sdfr
176105468Smarcel    l->l_next = NULL;
177105467Smarcel
178105468Smarcel    if (r_debug.r_map == NULL) {
179105468Smarcel	/* Add first. */
180105468Smarcel	l->l_prev = NULL;
181105468Smarcel	r_debug.r_map = l;
182105468Smarcel    } else {
183105468Smarcel	/* Append to list. */
184105468Smarcel	for (prev = r_debug.r_map; prev->l_next != NULL; prev = prev->l_next)
185105468Smarcel	    ;
186105468Smarcel	l->l_prev = prev;
187105468Smarcel	prev->l_next = l;
188105468Smarcel    }
189105467Smarcel}
190105467Smarcel
191105467Smarcelstatic void
192105467Smarcellink_elf_delete_gdb(struct link_map *l)
193105467Smarcel{
194105467Smarcel    if (l->l_prev == NULL) {
195105468Smarcel	/* Remove first. */
196105467Smarcel	if ((r_debug.r_map = l->l_next) != NULL)
197105467Smarcel	    l->l_next->l_prev = NULL;
198105468Smarcel    } else {
199105468Smarcel	/* Remove any but first. */
200105468Smarcel	if ((l->l_prev->l_next = l->l_next) != NULL)
201105468Smarcel	    l->l_next->l_prev = l->l_prev;
202105467Smarcel    }
203105467Smarcel}
204131928Smarcel#endif /* GDB */
205105467Smarcel
20695228Smarcel#ifdef __ia64__
20795228SmarcelElf_Addr link_elf_get_gp(linker_file_t);
20895228Smarcel#endif
20995228Smarcel
21059603Sdfr/*
21138514Sdfr * The kernel symbol table starts here.
21238514Sdfr */
21338514Sdfrextern struct _dynamic _DYNAMIC;
21438514Sdfr
21538514Sdfrstatic void
216105467Smarcellink_elf_error(const char *s)
217105467Smarcel{
218105467Smarcel    printf("kldload: %s\n", s);
219105467Smarcel}
220105467Smarcel
221105468Smarcel/*
222105468Smarcel * Actions performed after linking/loading both the preloaded kernel and any
223105468Smarcel * modules; whether preloaded or dynamicly loaded.
224105468Smarcel */
225105468Smarcelstatic int
226105468Smarcellink_elf_link_common_finish(linker_file_t lf)
227105468Smarcel{
228131928Smarcel#ifdef GDB
229105468Smarcel    elf_file_t ef = (elf_file_t)lf;
230105468Smarcel    char *newfilename;
231105468Smarcel#endif
232105469Smarcel    int error;
233105468Smarcel
234105469Smarcel    /* Notify MD code that a module is being loaded. */
235105469Smarcel    error = elf_cpu_load_file(lf);
236105469Smarcel    if (error)
237105469Smarcel	return (error);
238105469Smarcel
239131928Smarcel#ifdef GDB
240105468Smarcel    GDB_STATE(RT_ADD);
241105468Smarcel    ef->gdb.l_addr = lf->address;
242111119Simp    newfilename = malloc(strlen(lf->filename) + 1, M_LINKER, M_WAITOK);
243105468Smarcel    strcpy(newfilename, lf->filename);
244105468Smarcel    ef->gdb.l_name = newfilename;
245105468Smarcel    ef->gdb.l_ld = ef->dynamic;
246105468Smarcel    link_elf_add_gdb(&ef->gdb);
247105468Smarcel    GDB_STATE(RT_CONSISTENT);
248105468Smarcel#endif
249105468Smarcel
250105468Smarcel    return (0);
251105468Smarcel}
252105468Smarcel
253105467Smarcelstatic void
25438514Sdfrlink_elf_init(void* arg)
25538514Sdfr{
25640156Speter    Elf_Dyn	*dp;
25740156Speter    caddr_t	modptr, baseptr, sizeptr;
25840156Speter    elf_file_t	ef;
25940156Speter    char	*modname;
26038514Sdfr
26159603Sdfr    linker_add_class(&link_elf_class);
26238514Sdfr
26340156Speter    dp = (Elf_Dyn*) &_DYNAMIC;
26482848Speter    modname = NULL;
265113158Speter    modptr = preload_search_by_type("elf" __XSTRING(__ELF_WORD_SIZE) " kernel");
266113158Speter    if (modptr == NULL)
267113158Speter	modptr = preload_search_by_type("elf kernel");
26882848Speter    if (modptr)
26982848Speter	modname = (char *)preload_search_info(modptr, MODINFO_NAME);
27082848Speter    if (modname == NULL)
27182848Speter	modname = "kernel";
27282848Speter    linker_kernel_file = linker_make_file(modname, &link_elf_class);
27382848Speter    if (linker_kernel_file == NULL)
27482848Speter	panic("link_elf_init: Can't create linker structures for kernel");
275105468Smarcel
27682848Speter    ef = (elf_file_t) linker_kernel_file;
27782848Speter    ef->preloaded = 1;
27882848Speter    ef->address = 0;
27959603Sdfr#ifdef SPARSE_MAPPING
28082848Speter    ef->object = 0;
28159603Sdfr#endif
28282848Speter    ef->dynamic = dp;
28359603Sdfr
28482848Speter    if (dp)
28582848Speter	parse_dynamic(ef);
28682848Speter    linker_kernel_file->address = (caddr_t) KERNBASE;
28782848Speter    linker_kernel_file->size = -(intptr_t)linker_kernel_file->address;
28840156Speter
28982848Speter    if (modptr) {
29082848Speter	ef->modptr = modptr;
29182848Speter	baseptr = preload_search_info(modptr, MODINFO_ADDR);
29282848Speter	if (baseptr)
29382848Speter	    linker_kernel_file->address = *(caddr_t *)baseptr;
29482848Speter	sizeptr = preload_search_info(modptr, MODINFO_SIZE);
29582848Speter	if (sizeptr)
29682848Speter	    linker_kernel_file->size = *(size_t *)sizeptr;
29782848Speter    }
29882848Speter    (void)link_elf_preload_parse_symbols(ef);
29959603Sdfr
300131928Smarcel#ifdef GDB
301105468Smarcel    r_debug.r_map = NULL;
30282848Speter    r_debug.r_brk = r_debug_state;
30382848Speter    r_debug.r_state = RT_CONSISTENT;
304105468Smarcel#endif
30559603Sdfr
306105468Smarcel    (void)link_elf_link_common_finish(linker_kernel_file);
30738514Sdfr}
30838514Sdfr
30940156SpeterSYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0);
31038514Sdfr
31138514Sdfrstatic int
31259751Speterlink_elf_preload_parse_symbols(elf_file_t ef)
31340254Speter{
31440254Speter    caddr_t	pointer;
31540254Speter    caddr_t	ssym, esym, base;
31640254Speter    caddr_t	strtab;
31740254Speter    int		strcnt;
31840254Speter    Elf_Sym*	symtab;
31940254Speter    int		symcnt;
32040254Speter
32140292Speter    if (ef->modptr == NULL)
32240292Speter	return 0;
32340254Speter    pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM);
32440254Speter    if (pointer == NULL)
32540254Speter	return 0;
32640254Speter    ssym = *(caddr_t *)pointer;
32740254Speter    pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM);
32840254Speter    if (pointer == NULL)
32940254Speter	return 0;
33040254Speter    esym = *(caddr_t *)pointer;
33140254Speter
33240254Speter    base = ssym;
33340254Speter
33440254Speter    symcnt = *(long *)base;
33540254Speter    base += sizeof(long);
33640254Speter    symtab = (Elf_Sym *)base;
33740254Speter    base += roundup(symcnt, sizeof(long));
33840254Speter
33940254Speter    if (base > esym || base < ssym) {
34040254Speter	printf("Symbols are corrupt!\n");
34140254Speter	return EINVAL;
34240254Speter    }
34340254Speter
34440254Speter    strcnt = *(long *)base;
34540254Speter    base += sizeof(long);
34640254Speter    strtab = base;
34740254Speter    base += roundup(strcnt, sizeof(long));
34840254Speter
34940254Speter    if (base > esym || base < ssym) {
35040254Speter	printf("Symbols are corrupt!\n");
35140254Speter	return EINVAL;
35240254Speter    }
35340254Speter
35440254Speter    ef->ddbsymtab = symtab;
35540254Speter    ef->ddbsymcnt = symcnt / sizeof(Elf_Sym);
35640254Speter    ef->ddbstrtab = strtab;
35740254Speter    ef->ddbstrcnt = strcnt;
35840254Speter
35940254Speter    return 0;
36040254Speter}
36140254Speter
36240254Speterstatic int
36359603Sdfrparse_dynamic(elf_file_t ef)
36438514Sdfr{
36559603Sdfr    Elf_Dyn *dp;
36639071Sdfr    int plttype = DT_REL;
36738514Sdfr
36838514Sdfr    for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
36938514Sdfr	switch (dp->d_tag) {
37038514Sdfr	case DT_HASH:
37138514Sdfr	{
37238514Sdfr	    /* From src/libexec/rtld-elf/rtld.c */
37380700Sjake	    const Elf_Hashelt *hashtab = (const Elf_Hashelt *)
37438514Sdfr		(ef->address + dp->d_un.d_ptr);
37538514Sdfr	    ef->nbuckets = hashtab[0];
37638514Sdfr	    ef->nchains = hashtab[1];
37738514Sdfr	    ef->buckets = hashtab + 2;
37838514Sdfr	    ef->chains = ef->buckets + ef->nbuckets;
37938514Sdfr	    break;
38038514Sdfr	}
38138514Sdfr	case DT_STRTAB:
38239071Sdfr	    ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr);
38338514Sdfr	    break;
38440254Speter	case DT_STRSZ:
38540254Speter	    ef->strsz = dp->d_un.d_val;
38640254Speter	    break;
38738514Sdfr	case DT_SYMTAB:
38839071Sdfr	    ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr);
38938514Sdfr	    break;
39038514Sdfr	case DT_SYMENT:
39138514Sdfr	    if (dp->d_un.d_val != sizeof(Elf_Sym))
39238514Sdfr		return ENOEXEC;
39339071Sdfr	    break;
39439071Sdfr	case DT_PLTGOT:
39539071Sdfr	    ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr);
39639071Sdfr	    break;
39739071Sdfr	case DT_REL:
39839071Sdfr	    ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr);
39939071Sdfr	    break;
40039071Sdfr	case DT_RELSZ:
40139071Sdfr	    ef->relsize = dp->d_un.d_val;
40239071Sdfr	    break;
40339071Sdfr	case DT_RELENT:
40439071Sdfr	    if (dp->d_un.d_val != sizeof(Elf_Rel))
40539071Sdfr		return ENOEXEC;
40639071Sdfr	    break;
40739071Sdfr	case DT_JMPREL:
40839071Sdfr	    ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr);
40939071Sdfr	    break;
41039071Sdfr	case DT_PLTRELSZ:
41139071Sdfr	    ef->pltrelsize = dp->d_un.d_val;
41239071Sdfr	    break;
41339071Sdfr	case DT_RELA:
41439071Sdfr	    ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr);
41539071Sdfr	    break;
41639071Sdfr	case DT_RELASZ:
41739071Sdfr	    ef->relasize = dp->d_un.d_val;
41839071Sdfr	    break;
41939071Sdfr	case DT_RELAENT:
42039071Sdfr	    if (dp->d_un.d_val != sizeof(Elf_Rela))
42139071Sdfr		return ENOEXEC;
42239071Sdfr	    break;
42339071Sdfr	case DT_PLTREL:
42439071Sdfr	    plttype = dp->d_un.d_val;
42539071Sdfr	    if (plttype != DT_REL && plttype != DT_RELA)
42639071Sdfr		return ENOEXEC;
42739071Sdfr	    break;
428131928Smarcel#ifdef GDB
42959603Sdfr	case DT_DEBUG:
43059603Sdfr	    dp->d_un.d_ptr = (Elf_Addr) &r_debug;
43159603Sdfr	    break;
43259603Sdfr#endif
43338514Sdfr	}
43438514Sdfr    }
43539071Sdfr
43639071Sdfr    if (plttype == DT_RELA) {
43739071Sdfr	ef->pltrela = (const Elf_Rela *) ef->pltrel;
43839071Sdfr	ef->pltrel = NULL;
43939071Sdfr	ef->pltrelasize = ef->pltrelsize;
44039071Sdfr	ef->pltrelsize = 0;
44139071Sdfr    }
44239071Sdfr
44340254Speter    ef->ddbsymtab = ef->symtab;
44440254Speter    ef->ddbsymcnt = ef->nchains;
44540254Speter    ef->ddbstrtab = ef->strtab;
44640254Speter    ef->ddbstrcnt = ef->strsz;
44740254Speter
44838514Sdfr    return 0;
44938514Sdfr}
45038514Sdfr
45138514Sdfrstatic int
45259751Speterlink_elf_link_preload(linker_class_t cls,
45359751Speter		      const char* filename, linker_file_t *result)
45440156Speter{
45540156Speter    caddr_t		modptr, baseptr, sizeptr, dynptr;
45640156Speter    char		*type;
45740156Speter    elf_file_t		ef;
45840156Speter    linker_file_t	lf;
45940156Speter    int			error;
46040156Speter    vm_offset_t		dp;
46140156Speter
46259751Speter    /* Look to see if we have the file preloaded */
46340156Speter    modptr = preload_search_by_name(filename);
46440156Speter    if (modptr == NULL)
46559751Speter	return ENOENT;
46640156Speter
46740156Speter    type = (char *)preload_search_info(modptr, MODINFO_TYPE);
46840156Speter    baseptr = preload_search_info(modptr, MODINFO_ADDR);
46940156Speter    sizeptr = preload_search_info(modptr, MODINFO_SIZE);
47040156Speter    dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC);
471113158Speter    if (type == NULL ||
472113158Speter	(strcmp(type, "elf" __XSTRING(__ELF_WORD_SIZE) " module") != 0 &&
473113158Speter	 strcmp(type, "elf module") != 0))
47440156Speter	return (EFTYPE);
47540156Speter    if (baseptr == NULL || sizeptr == NULL || dynptr == NULL)
47640156Speter	return (EINVAL);
47740156Speter
47859603Sdfr    lf = linker_make_file(filename, &link_elf_class);
47959603Sdfr    if (lf == NULL) {
48059603Sdfr	return ENOMEM;
48159603Sdfr    }
48259603Sdfr
48359603Sdfr    ef = (elf_file_t) lf;
48459603Sdfr    ef->preloaded = 1;
48540292Speter    ef->modptr = modptr;
48640156Speter    ef->address = *(caddr_t *)baseptr;
48740156Speter#ifdef SPARSE_MAPPING
48840156Speter    ef->object = 0;
48940156Speter#endif
49040156Speter    dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr;
49140156Speter    ef->dynamic = (Elf_Dyn *)dp;
49240156Speter    lf->address = ef->address;
49340156Speter    lf->size = *(size_t *)sizeptr;
49440156Speter
49559603Sdfr    error = parse_dynamic(ef);
49640156Speter    if (error) {
497132117Sphk	linker_file_unload(lf, LINKER_UNLOAD_FORCE);
49840156Speter	return error;
49940156Speter    }
500109605Sjake    link_elf_reloc_local(lf);
50159751Speter    *result = lf;
50259751Speter    return (0);
50359751Speter}
50459751Speter
50559751Speterstatic int
50659751Speterlink_elf_link_preload_finish(linker_file_t lf)
50759751Speter{
50859751Speter    elf_file_t		ef;
50959751Speter    int error;
51059751Speter
51159751Speter    ef = (elf_file_t) lf;
51259751Speter#if 0	/* this will be more trouble than it's worth for now */
51359751Speter    for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
51459751Speter	if (dp->d_tag != DT_NEEDED)
51559751Speter	    continue;
51659751Speter	modname = ef->strtab + dp->d_un.d_val;
51759751Speter	error = linker_load_module(modname, lf);
51859751Speter	if (error)
51959751Speter	    goto out;
52040156Speter    }
52159751Speter#endif
52259603Sdfr    error = relocate_file(ef);
52359751Speter    if (error)
52440156Speter	return error;
52559751Speter    (void)link_elf_preload_parse_symbols(ef);
52659603Sdfr
527105468Smarcel    return (link_elf_link_common_finish(lf));
52840156Speter}
52940156Speter
53040156Speterstatic int
531105468Smarcellink_elf_load_file(linker_class_t cls, const char* filename,
532105468Smarcel	linker_file_t* result)
53338514Sdfr{
53438514Sdfr    struct nameidata nd;
53583366Sjulian    struct thread* td = curthread;	/* XXX */
53640962Speter    Elf_Ehdr *hdr;
53740962Speter    caddr_t firstpage;
53839071Sdfr    int nbytes, i;
53939071Sdfr    Elf_Phdr *phdr;
54039071Sdfr    Elf_Phdr *phlimit;
541151430Speter    Elf_Phdr *segs[MAXSEGS];
54239071Sdfr    int nsegs;
54339071Sdfr    Elf_Phdr *phdyn;
54439071Sdfr    Elf_Phdr *phphdr;
54539071Sdfr    caddr_t mapbase;
54639071Sdfr    size_t mapsize;
54739071Sdfr    Elf_Off base_offset;
54839071Sdfr    Elf_Addr base_vaddr;
54939071Sdfr    Elf_Addr base_vlimit;
55038514Sdfr    int error = 0;
55162550Smckusick    int resid, flags;
55238514Sdfr    elf_file_t ef;
55338514Sdfr    linker_file_t lf;
55440292Speter    Elf_Shdr *shdr;
55540292Speter    int symtabindex;
55640292Speter    int symstrindex;
55740292Speter    int symcnt;
55840292Speter    int strcnt;
55938514Sdfr
56079224Sdillon    GIANT_REQUIRED;
56179224Sdillon
56240292Speter    shdr = NULL;
56340292Speter    lf = NULL;
56440292Speter
56583366Sjulian    NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td);
56662550Smckusick    flags = FREAD;
567118094Sphk    error = vn_open(&nd, &flags, 0, -1);
56838514Sdfr    if (error)
56938514Sdfr	return error;
57054655Seivind    NDFREE(&nd, NDF_ONLY_PNBUF);
571107089Srwatson#ifdef MAC
572107089Srwatson    error = mac_check_kld_load(curthread->td_ucred, nd.ni_vp);
573107089Srwatson    if (error) {
574107089Srwatson	firstpage = NULL;
575107089Srwatson	goto out;
576107089Srwatson    }
577107089Srwatson#endif
57838514Sdfr
57938514Sdfr    /*
58039071Sdfr     * Read the elf header from the file.
58138514Sdfr     */
582111119Simp    firstpage = malloc(PAGE_SIZE, M_LINKER, M_WAITOK);
58340962Speter    if (firstpage == NULL) {
58440962Speter	error = ENOMEM;
58540962Speter	goto out;
58640962Speter    }
58740962Speter    hdr = (Elf_Ehdr *)firstpage;
58840962Speter    error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0,
589101941Srwatson		    UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
590101941Srwatson		    &resid, td);
59140962Speter    nbytes = PAGE_SIZE - resid;
59238514Sdfr    if (error)
59338514Sdfr	goto out;
59438514Sdfr
59540962Speter    if (!IS_ELF(*hdr)) {
59639071Sdfr	error = ENOEXEC;
59738514Sdfr	goto out;
59839071Sdfr    }
59938514Sdfr
60040962Speter    if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS
60140962Speter      || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) {
60239071Sdfr	link_elf_error("Unsupported file layout");
60339071Sdfr	error = ENOEXEC;
60439071Sdfr	goto out;
60539071Sdfr    }
60640962Speter    if (hdr->e_ident[EI_VERSION] != EV_CURRENT
60740962Speter      || hdr->e_version != EV_CURRENT) {
60839071Sdfr	link_elf_error("Unsupported file version");
60939071Sdfr	error = ENOEXEC;
61039071Sdfr	goto out;
61139071Sdfr    }
61240962Speter    if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) {
61339071Sdfr	link_elf_error("Unsupported file type");
61439071Sdfr	error = ENOEXEC;
61539071Sdfr	goto out;
61639071Sdfr    }
61740962Speter    if (hdr->e_machine != ELF_TARG_MACH) {
61839071Sdfr	link_elf_error("Unsupported machine");
61939071Sdfr	error = ENOEXEC;
62039071Sdfr	goto out;
62139071Sdfr    }
62239071Sdfr
62338514Sdfr    /*
62439071Sdfr     * We rely on the program header being in the first page.  This is
62539071Sdfr     * not strictly required by the ABI specification, but it seems to
62639071Sdfr     * always true in practice.  And, it simplifies things considerably.
62738514Sdfr     */
62840962Speter    if (!((hdr->e_phentsize == sizeof(Elf_Phdr)) &&
62940962Speter	  (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) &&
63040962Speter	  (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= nbytes)))
63139071Sdfr	link_elf_error("Unreadable program headers");
63239071Sdfr
63338514Sdfr    /*
63439071Sdfr     * Scan the program header entries, and save key information.
63539071Sdfr     *
63639071Sdfr     * We rely on there being exactly two load segments, text and data,
63739071Sdfr     * in that order.
63838514Sdfr     */
63940962Speter    phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff);
64040962Speter    phlimit = phdr + hdr->e_phnum;
64139071Sdfr    nsegs = 0;
64239071Sdfr    phdyn = NULL;
64339071Sdfr    phphdr = NULL;
64439071Sdfr    while (phdr < phlimit) {
64539071Sdfr	switch (phdr->p_type) {
64639071Sdfr
64739071Sdfr	case PT_LOAD:
648151430Speter	    if (nsegs == MAXSEGS) {
64939071Sdfr		link_elf_error("Too many sections");
65039071Sdfr		error = ENOEXEC;
65139071Sdfr		goto out;
65239071Sdfr	    }
653114946Sphk	    /*
654114946Sphk	     * XXX: We just trust they come in right order ??
655114946Sphk	     */
65639071Sdfr	    segs[nsegs] = phdr;
65739071Sdfr	    ++nsegs;
65839071Sdfr	    break;
65939071Sdfr
66039071Sdfr	case PT_PHDR:
66139071Sdfr	    phphdr = phdr;
66239071Sdfr	    break;
66339071Sdfr
66439071Sdfr	case PT_DYNAMIC:
66539071Sdfr	    phdyn = phdr;
66639071Sdfr	    break;
66765503Sbp
66865503Sbp	case PT_INTERP:
66965503Sbp	    link_elf_error("Unsupported file type");
67065503Sbp	    error = ENOEXEC;
67165503Sbp	    goto out;
67239071Sdfr	}
67339071Sdfr
67439071Sdfr	++phdr;
67539071Sdfr    }
67639071Sdfr    if (phdyn == NULL) {
67739071Sdfr	link_elf_error("Object is not dynamically-linked");
67839071Sdfr	error = ENOEXEC;
67938514Sdfr	goto out;
68039071Sdfr    }
681151430Speter    if (nsegs == 0) {
682151430Speter	link_elf_error("No sections");
683114946Sphk	error = ENOEXEC;
684114946Sphk	goto out;
685114946Sphk    }
68638514Sdfr
68738514Sdfr    /*
68839071Sdfr     * Allocate the entire address space of the object, to stake out our
68939071Sdfr     * contiguous region, and to establish the base address for relocation.
69038514Sdfr     */
69139071Sdfr    base_offset = trunc_page(segs[0]->p_offset);
69239071Sdfr    base_vaddr = trunc_page(segs[0]->p_vaddr);
693151430Speter    base_vlimit = round_page(segs[nsegs - 1]->p_vaddr +
694151430Speter	segs[nsegs - 1]->p_memsz);
69539071Sdfr    mapsize = base_vlimit - base_vaddr;
69639071Sdfr
69759603Sdfr    lf = linker_make_file(filename, &link_elf_class);
69859603Sdfr    if (!lf) {
69959603Sdfr	error = ENOMEM;
70059603Sdfr	goto out;
70159603Sdfr    }
70259603Sdfr
70359603Sdfr    ef = (elf_file_t) lf;
70439071Sdfr#ifdef SPARSE_MAPPING
70539071Sdfr    ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT);
70639071Sdfr    if (ef->object == NULL) {
70739071Sdfr	error = ENOMEM;
70838514Sdfr	goto out;
70938514Sdfr    }
71039071Sdfr    ef->address = (caddr_t) vm_map_min(kernel_map);
71139071Sdfr    error = vm_map_find(kernel_map, ef->object, 0,
71239071Sdfr			(vm_offset_t *) &ef->address,
71339071Sdfr			mapsize, 1,
71439071Sdfr			VM_PROT_ALL, VM_PROT_ALL, 0);
71539071Sdfr    if (error) {
71639071Sdfr	vm_object_deallocate(ef->object);
71759603Sdfr	ef->object = 0;
71839071Sdfr	goto out;
71939071Sdfr    }
72039071Sdfr#else
721111119Simp    ef->address = malloc(mapsize, M_LINKER, M_WAITOK);
72259603Sdfr    if (!ef->address) {
72359603Sdfr	error = ENOMEM;
72459603Sdfr	goto out;
72559603Sdfr    }
72639071Sdfr#endif
72739071Sdfr    mapbase = ef->address;
72838514Sdfr
72939071Sdfr    /*
73039071Sdfr     * Read the text and data sections and zero the bss.
73139071Sdfr     */
732151430Speter    for (i = 0; i < nsegs; i++) {
73339071Sdfr	caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr;
73439071Sdfr	error = vn_rdwr(UIO_READ, nd.ni_vp,
73539071Sdfr			segbase, segs[i]->p_filesz, segs[i]->p_offset,
736101941Srwatson			UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
737101941Srwatson			&resid, td);
73839071Sdfr	if (error) {
73939071Sdfr	    goto out;
74039071Sdfr	}
74139071Sdfr	bzero(segbase + segs[i]->p_filesz,
74239071Sdfr	      segs[i]->p_memsz - segs[i]->p_filesz);
743149539Salc
744149539Salc#ifdef SPARSE_MAPPING
745149539Salc	/*
746149539Salc	 * Wire down the pages
747149539Salc	 */
748149544Salc	error = vm_map_wire(kernel_map,
749149539Salc		    (vm_offset_t) segbase,
750149539Salc		    (vm_offset_t) segbase + segs[i]->p_memsz,
751149539Salc		    VM_MAP_WIRE_SYSTEM|VM_MAP_WIRE_NOHOLES);
752149544Salc	if (error != KERN_SUCCESS) {
753149544Salc	    error = ENOMEM;
754149544Salc	    goto out;
755149544Salc	}
756149539Salc#endif
75739071Sdfr    }
75839071Sdfr
75985734Sgreen#ifdef GPROF
76085734Sgreen    /* Update profiling information with the new text segment. */
76185734Sgreen    kmupetext((uintfptr_t)(mapbase + segs[0]->p_vaddr - base_vaddr +
76285734Sgreen	segs[0]->p_memsz));
76385734Sgreen#endif
76485734Sgreen
76559603Sdfr    ef->dynamic = (Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr);
76639071Sdfr
76738514Sdfr    lf->address = ef->address;
76839071Sdfr    lf->size = mapsize;
76938514Sdfr
77059603Sdfr    error = parse_dynamic(ef);
77140292Speter    if (error)
77238514Sdfr	goto out;
773109605Sjake    link_elf_reloc_local(lf);
774109605Sjake
77586469Siedowse    error = linker_load_dependencies(lf);
77640292Speter    if (error)
77740156Speter	goto out;
77859751Speter#if 0	/* this will be more trouble than it's worth for now */
77959751Speter    for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
78059751Speter	if (dp->d_tag != DT_NEEDED)
78159751Speter	    continue;
78259751Speter	modname = ef->strtab + dp->d_un.d_val;
78359751Speter	error = linker_load_module(modname, lf);
78459751Speter	if (error)
78559751Speter	    goto out;
78659751Speter    }
78759751Speter#endif
78859603Sdfr    error = relocate_file(ef);
78940292Speter    if (error)
79040156Speter	goto out;
79140292Speter
79240292Speter    /* Try and load the symbol table if it's present.  (you can strip it!) */
79340962Speter    nbytes = hdr->e_shnum * hdr->e_shentsize;
79440962Speter    if (nbytes == 0 || hdr->e_shoff == 0)
79540292Speter	goto nosyms;
796111119Simp    shdr = malloc(nbytes, M_LINKER, M_WAITOK | M_ZERO);
79740292Speter    if (shdr == NULL) {
79840292Speter	error = ENOMEM;
79940292Speter	goto out;
80040156Speter    }
80140292Speter    error = vn_rdwr(UIO_READ, nd.ni_vp,
80240962Speter		    (caddr_t)shdr, nbytes, hdr->e_shoff,
803101941Srwatson		    UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
804101941Srwatson		    &resid, td);
80540292Speter    if (error)
80640292Speter	goto out;
80740292Speter    symtabindex = -1;
80840292Speter    symstrindex = -1;
80940962Speter    for (i = 0; i < hdr->e_shnum; i++) {
81040292Speter	if (shdr[i].sh_type == SHT_SYMTAB) {
81140292Speter	    symtabindex = i;
81240292Speter	    symstrindex = shdr[i].sh_link;
81340292Speter	}
81440292Speter    }
81540292Speter    if (symtabindex < 0 || symstrindex < 0)
81640292Speter	goto nosyms;
81740156Speter
81840292Speter    symcnt = shdr[symtabindex].sh_size;
819111119Simp    ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK);
82040292Speter    strcnt = shdr[symstrindex].sh_size;
821111119Simp    ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK);
82240292Speter
82340292Speter    if (ef->symbase == NULL || ef->strbase == NULL) {
82440292Speter	error = ENOMEM;
82540292Speter	goto out;
82640292Speter    }
82740292Speter    error = vn_rdwr(UIO_READ, nd.ni_vp,
82840292Speter		    ef->symbase, symcnt, shdr[symtabindex].sh_offset,
829101941Srwatson		    UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
830101941Srwatson		    &resid, td);
83140292Speter    if (error)
83240292Speter	goto out;
83340292Speter    error = vn_rdwr(UIO_READ, nd.ni_vp,
83440292Speter		    ef->strbase, strcnt, shdr[symstrindex].sh_offset,
835101941Srwatson		    UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
836101941Srwatson		    &resid, td);
83740292Speter    if (error)
83840292Speter	goto out;
83940292Speter
84040292Speter    ef->ddbsymcnt = symcnt / sizeof(Elf_Sym);
84140292Speter    ef->ddbsymtab = (const Elf_Sym *)ef->symbase;
84240292Speter    ef->ddbstrcnt = strcnt;
84340292Speter    ef->ddbstrtab = ef->strbase;
84440292Speter
845105468Smarcel    error = link_elf_link_common_finish(lf);
846105468Smarcel    if (error)
847105468Smarcel	goto out;
84859603Sdfr
84940292Speternosyms:
85040292Speter
85138514Sdfr    *result = lf;
85238514Sdfr
85338514Sdfrout:
85440292Speter    if (error && lf)
855132117Sphk	linker_file_unload(lf, LINKER_UNLOAD_FORCE);
85640292Speter    if (shdr)
85740292Speter	free(shdr, M_LINKER);
85840962Speter    if (firstpage)
85940962Speter	free(firstpage, M_LINKER);
86083366Sjulian    VOP_UNLOCK(nd.ni_vp, 0, td);
86191406Sjhb    vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
86238514Sdfr
86338514Sdfr    return error;
86438514Sdfr}
86538514Sdfr
86638514Sdfrstatic void
86740156Speterlink_elf_unload_file(linker_file_t file)
86838514Sdfr{
86959603Sdfr    elf_file_t ef = (elf_file_t) file;
87038514Sdfr
871131928Smarcel#ifdef GDB
87259603Sdfr    if (ef->gdb.l_ld) {
87359603Sdfr	GDB_STATE(RT_DELETE);
87483282Speter	free((void *)(uintptr_t)ef->gdb.l_name, M_LINKER);
87559603Sdfr	link_elf_delete_gdb(&ef->gdb);
87659603Sdfr	GDB_STATE(RT_CONSISTENT);
87759603Sdfr    }
87859603Sdfr#endif
87959603Sdfr
880105469Smarcel    /* Notify MD code that a module is being unloaded. */
881105469Smarcel    elf_cpu_unload_file(file);
882105469Smarcel
88359603Sdfr    if (ef->preloaded) {
88459751Speter	link_elf_unload_preload(file);
88559603Sdfr	return;
88659603Sdfr    }
887105468Smarcel
88839071Sdfr#ifdef SPARSE_MAPPING
88959603Sdfr    if (ef->object) {
89059603Sdfr	vm_map_remove(kernel_map, (vm_offset_t) ef->address,
89159603Sdfr		      (vm_offset_t) ef->address
89259603Sdfr		      + (ef->object->size << PAGE_SHIFT));
89359603Sdfr    }
89439071Sdfr#else
89559603Sdfr    if (ef->address)
89659603Sdfr	free(ef->address, M_LINKER);
89739071Sdfr#endif
89859603Sdfr    if (ef->symbase)
89959603Sdfr	free(ef->symbase, M_LINKER);
90059603Sdfr    if (ef->strbase)
90159603Sdfr	free(ef->strbase, M_LINKER);
90238514Sdfr}
90338514Sdfr
90440156Speterstatic void
90559751Speterlink_elf_unload_preload(linker_file_t file)
90640156Speter{
90740156Speter    if (file->filename)
90840156Speter	preload_delete_name(file->filename);
90940156Speter}
91040156Speter
91139071Sdfrstatic const char *
91240435Spetersymbol_name(elf_file_t ef, Elf_Word r_info)
91338514Sdfr{
91439071Sdfr    const Elf_Sym *ref;
91538514Sdfr
91640435Speter    if (ELF_R_SYM(r_info)) {
91740435Speter	ref = ef->symtab + ELF_R_SYM(r_info);
91840397Speter	return ef->strtab + ref->st_name;
91939071Sdfr    } else
92039071Sdfr	return NULL;
92138514Sdfr}
92238514Sdfr
92338514Sdfrstatic int
92459603Sdfrrelocate_file(elf_file_t ef)
92538514Sdfr{
92639071Sdfr    const Elf_Rel *rellim;
92739071Sdfr    const Elf_Rel *rel;
92839071Sdfr    const Elf_Rela *relalim;
92939071Sdfr    const Elf_Rela *rela;
93040435Speter    const char *symname;
93138514Sdfr
93239071Sdfr    /* Perform relocations without addend if there are any: */
93340435Speter    rel = ef->rel;
93440435Speter    if (rel) {
93543388Sbde	rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
93640435Speter	while (rel < rellim) {
937129282Speter	    if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel, ELF_RELOC_REL,
938129282Speter			  elf_lookup)) {
93995410Smarcel		symname = symbol_name(ef, rel->r_info);
94059744Speter		printf("link_elf: symbol %s undefined\n", symname);
94140435Speter		return ENOENT;
94242200Speter	    }
94340435Speter	    rel++;
94440435Speter	}
94539071Sdfr    }
94638514Sdfr
94739071Sdfr    /* Perform relocations with addend if there are any: */
94840435Speter    rela = ef->rela;
94940435Speter    if (rela) {
95043388Sbde	relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
95140435Speter	while (rela < relalim) {
952129282Speter	    if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela, ELF_RELOC_RELA,
953129282Speter			  elf_lookup)) {
95495410Smarcel		symname = symbol_name(ef, rela->r_info);
95559744Speter		printf("link_elf: symbol %s undefined\n", symname);
95640435Speter		return ENOENT;
95742200Speter	    }
95840435Speter	    rela++;
95940435Speter	}
96039071Sdfr    }
96138514Sdfr
96239071Sdfr    /* Perform PLT relocations without addend if there are any: */
96340435Speter    rel = ef->pltrel;
96440435Speter    if (rel) {
96543388Sbde	rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize);
96640435Speter	while (rel < rellim) {
967129282Speter	    if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rel, ELF_RELOC_REL,
968129282Speter			  elf_lookup)) {
96995410Smarcel		symname = symbol_name(ef, rel->r_info);
97059744Speter		printf("link_elf: symbol %s undefined\n", symname);
97140435Speter		return ENOENT;
97242200Speter	    }
97340435Speter	    rel++;
97440435Speter	}
97539071Sdfr    }
97638514Sdfr
97739071Sdfr    /* Perform relocations with addend if there are any: */
97840435Speter    rela = ef->pltrela;
97940435Speter    if (rela) {
98043388Sbde	relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize);
98140435Speter	while (rela < relalim) {
982129282Speter	    if (elf_reloc(&ef->lf, (Elf_Addr)ef->address, rela, ELF_RELOC_RELA,
983129282Speter			  elf_lookup)) {
98495410Smarcel		symname = symbol_name(ef, rela->r_info);
98559744Speter		printf("link_elf: symbol %s undefined\n", symname);
98640435Speter		return ENOENT;
98742200Speter	    }
98840435Speter	    rela++;
98940435Speter	}
99038514Sdfr    }
99138514Sdfr
99238514Sdfr    return 0;
99338514Sdfr}
99438514Sdfr
99539071Sdfr/*
99639071Sdfr * Hash function for symbol table lookup.  Don't even think about changing
99739071Sdfr * this.  It is specified by the System V ABI.
99839071Sdfr */
99939071Sdfrstatic unsigned long
100039071Sdfrelf_hash(const char *name)
100138514Sdfr{
100239071Sdfr    const unsigned char *p = (const unsigned char *) name;
100339071Sdfr    unsigned long h = 0;
100439071Sdfr    unsigned long g;
100538514Sdfr
100639071Sdfr    while (*p != '\0') {
100739071Sdfr	h = (h << 4) + *p++;
100839071Sdfr	if ((g = h & 0xf0000000) != 0)
100939071Sdfr	    h ^= g >> 24;
101039071Sdfr	h &= ~g;
101139071Sdfr    }
101239071Sdfr    return h;
101338514Sdfr}
101438514Sdfr
1015104094Sphkstatic int
101643301Sdillonlink_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym)
101738514Sdfr{
101859603Sdfr    elf_file_t ef = (elf_file_t) lf;
101939071Sdfr    unsigned long symnum;
102040254Speter    const Elf_Sym* symp;
102140254Speter    const char *strp;
102239071Sdfr    unsigned long hash;
102339071Sdfr    int i;
102438514Sdfr
102540254Speter    /* First, search hashed global symbols */
102639071Sdfr    hash = elf_hash(name);
102739071Sdfr    symnum = ef->buckets[hash % ef->nbuckets];
102839071Sdfr
102939071Sdfr    while (symnum != STN_UNDEF) {
103039071Sdfr	if (symnum >= ef->nchains) {
103139071Sdfr	    printf("link_elf_lookup_symbol: corrupt symbol table\n");
103239071Sdfr	    return ENOENT;
103338514Sdfr	}
103438514Sdfr
103539071Sdfr	symp = ef->symtab + symnum;
103639071Sdfr	if (symp->st_name == 0) {
103739071Sdfr	    printf("link_elf_lookup_symbol: corrupt symbol table\n");
103839071Sdfr	    return ENOENT;
103939071Sdfr	}
104039071Sdfr
104139071Sdfr	strp = ef->strtab + symp->st_name;
104239071Sdfr
104339071Sdfr	if (strcmp(name, strp) == 0) {
104439071Sdfr	    if (symp->st_shndx != SHN_UNDEF ||
104539071Sdfr		(symp->st_value != 0 &&
104639071Sdfr		 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
104743301Sdillon		*sym = (c_linker_sym_t) symp;
104839071Sdfr		return 0;
104939071Sdfr	    } else
105039071Sdfr		return ENOENT;
105139071Sdfr	}
105239071Sdfr
105339071Sdfr	symnum = ef->chains[symnum];
105439071Sdfr    }
105539071Sdfr
105640254Speter    /* If we have not found it, look at the full table (if loaded) */
105740254Speter    if (ef->symtab == ef->ddbsymtab)
105840254Speter	return ENOENT;
105940254Speter
106040254Speter    /* Exhaustive search */
106140254Speter    for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
106240254Speter	strp = ef->ddbstrtab + symp->st_name;
106340254Speter	if (strcmp(name, strp) == 0) {
106440254Speter	    if (symp->st_shndx != SHN_UNDEF ||
106540254Speter		(symp->st_value != 0 &&
106640254Speter		 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
106743301Sdillon		*sym = (c_linker_sym_t) symp;
106840254Speter		return 0;
106940254Speter	    } else
107040254Speter		return ENOENT;
107140254Speter	}
107240254Speter    }
107340254Speter
107439071Sdfr    return ENOENT;
107538514Sdfr}
107638514Sdfr
107740156Speterstatic int
107843309Sdillonlink_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, linker_symval_t* symval)
107938514Sdfr{
108059603Sdfr	elf_file_t ef = (elf_file_t) lf;
108143311Sdillon	const Elf_Sym* es = (const Elf_Sym*) sym;
108238514Sdfr
1083102348Smarcel	if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) {
108440254Speter	    symval->name = ef->strtab + es->st_name;
108540254Speter	    symval->value = (caddr_t) ef->address + es->st_value;
108640254Speter	    symval->size = es->st_size;
108740254Speter	    return 0;
108840254Speter	}
108940254Speter	if (ef->symtab == ef->ddbsymtab)
109040254Speter	    return ENOENT;
1091102348Smarcel	if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
109240254Speter	    symval->name = ef->ddbstrtab + es->st_name;
109340254Speter	    symval->value = (caddr_t) ef->address + es->st_value;
109440254Speter	    symval->size = es->st_size;
109540254Speter	    return 0;
109640254Speter	}
109740254Speter	return ENOENT;
109838514Sdfr}
109938514Sdfr
110038514Sdfrstatic int
110138514Sdfrlink_elf_search_symbol(linker_file_t lf, caddr_t value,
110243301Sdillon		       c_linker_sym_t* sym, long* diffp)
110338514Sdfr{
110459603Sdfr	elf_file_t ef = (elf_file_t) lf;
110555090Sbde	u_long off = (uintptr_t) (void *) value;
110638514Sdfr	u_long diff = off;
110755090Sbde	u_long st_value;
110839071Sdfr	const Elf_Sym* es;
110939071Sdfr	const Elf_Sym* best = 0;
111038514Sdfr	int i;
111138514Sdfr
111240254Speter	for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) {
111338514Sdfr		if (es->st_name == 0)
111438514Sdfr			continue;
111555090Sbde		st_value = es->st_value + (uintptr_t) (void *) ef->address;
111653820Speter		if (off >= st_value) {
111753820Speter			if (off - st_value < diff) {
111853820Speter				diff = off - st_value;
111938514Sdfr				best = es;
112038514Sdfr				if (diff == 0)
112138514Sdfr					break;
112253820Speter			} else if (off - st_value == diff) {
112338514Sdfr				best = es;
112438514Sdfr			}
112538514Sdfr		}
112638514Sdfr	}
112738514Sdfr	if (best == 0)
112838514Sdfr		*diffp = off;
112938514Sdfr	else
113038514Sdfr		*diffp = diff;
113143301Sdillon	*sym = (c_linker_sym_t) best;
113238514Sdfr
113338514Sdfr	return 0;
113438514Sdfr}
113578161Speter
113678161Speter/*
113778161Speter * Look up a linker set on an ELF system.
113878161Speter */
113978161Speterstatic int
114078161Speterlink_elf_lookup_set(linker_file_t lf, const char *name,
114178161Speter		    void ***startp, void ***stopp, int *countp)
114278161Speter{
114378161Speter	c_linker_sym_t sym;
114478161Speter	linker_symval_t symval;
114578161Speter	char *setsym;
114678161Speter	void **start, **stop;
114778161Speter	int len, error = 0, count;
114878161Speter
114978161Speter	len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */
1150111119Simp	setsym = malloc(len, M_LINKER, M_WAITOK);
115178161Speter	if (setsym == NULL)
115278161Speter		return ENOMEM;
115378161Speter
115478161Speter	/* get address of first entry */
115578161Speter	snprintf(setsym, len, "%s%s", "__start_set_", name);
115678161Speter	error = link_elf_lookup_symbol(lf, setsym, &sym);
115778161Speter	if (error)
115878161Speter		goto out;
115978161Speter	link_elf_symbol_values(lf, sym, &symval);
116078161Speter	if (symval.value == 0) {
116178161Speter		error = ESRCH;
116278161Speter		goto out;
116378161Speter	}
116478161Speter	start = (void **)symval.value;
116578161Speter
116678161Speter	/* get address of last entry */
116778161Speter	snprintf(setsym, len, "%s%s", "__stop_set_", name);
116878161Speter	error = link_elf_lookup_symbol(lf, setsym, &sym);
116978161Speter	if (error)
117078161Speter		goto out;
117178161Speter	link_elf_symbol_values(lf, sym, &symval);
117278161Speter	if (symval.value == 0) {
117378161Speter		error = ESRCH;
117478161Speter		goto out;
117578161Speter	}
117678161Speter	stop = (void **)symval.value;
117778161Speter
117878161Speter	/* and the number of entries */
117978161Speter	count = stop - start;
118078161Speter
118178161Speter	/* and copy out */
118278161Speter	if (startp)
118378161Speter		*startp = start;
118478161Speter	if (stopp)
118578161Speter		*stopp = stop;
118678161Speter	if (countp)
118778161Speter		*countp = count;
118878161Speter
118978161Speterout:
119078161Speter	free(setsym, M_LINKER);
119178161Speter	return error;
119278161Speter}
119385736Sgreen
119485736Sgreenstatic int
119585736Sgreenlink_elf_each_function_name(linker_file_t file,
119685736Sgreen  int (*callback)(const char *, void *), void *opaque) {
119785736Sgreen    elf_file_t ef = (elf_file_t)file;
119885736Sgreen    const Elf_Sym* symp;
119985736Sgreen    int i, error;
120085736Sgreen
120185736Sgreen    /* Exhaustive search */
120285736Sgreen    for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
120385736Sgreen	if (symp->st_value != 0 &&
120485736Sgreen	    ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
120585736Sgreen		error = callback(ef->ddbstrtab + symp->st_name, opaque);
120685736Sgreen		if (error)
120785736Sgreen		    return (error);
120885736Sgreen	}
120985736Sgreen    }
121085736Sgreen    return (0);
121185736Sgreen}
121295228Smarcel
121395228Smarcel#ifdef __ia64__
121495228Smarcel/*
121595228Smarcel * Each KLD has its own GP. The GP value for each load module is given by
121695228Smarcel * DT_PLTGOT on ia64. We need GP to construct function descriptors, but
121795228Smarcel * don't have direct access to the ELF file structure. The link_elf_get_gp()
121895228Smarcel * function returns the GP given a pointer to a generic linker file struct.
121995228Smarcel */
122095228SmarcelElf_Addr
122195228Smarcellink_elf_get_gp(linker_file_t lf)
122295228Smarcel{
122395228Smarcel	elf_file_t ef = (elf_file_t)lf;
122495228Smarcel	return (Elf_Addr)ef->got;
122595228Smarcel}
122695228Smarcel#endif
122795410Smarcel
1228104072Sjakeconst Elf_Sym *
1229104072Sjakeelf_get_sym(linker_file_t lf, Elf_Word symidx)
1230104072Sjake{
1231104072Sjake	elf_file_t ef = (elf_file_t)lf;
1232104072Sjake
1233104072Sjake	if (symidx >= ef->nchains)
1234104072Sjake		return (NULL);
1235104072Sjake	return (ef->symtab + symidx);
1236104072Sjake}
1237104072Sjake
1238105147Smarcelconst char *
1239105147Smarcelelf_get_symname(linker_file_t lf, Elf_Word symidx)
1240105147Smarcel{
1241105147Smarcel	elf_file_t ef = (elf_file_t)lf;
1242105147Smarcel	const Elf_Sym *sym;
1243105147Smarcel
1244105147Smarcel	if (symidx >= ef->nchains)
1245105147Smarcel		return (NULL);
1246105147Smarcel	sym = ef->symtab + symidx;
1247105147Smarcel	return (ef->strtab + sym->st_name);
1248105147Smarcel}
1249105147Smarcel
125095410Smarcel/*
125195410Smarcel * Symbol lookup function that can be used when the symbol index is known (ie
125295410Smarcel * in relocations). It uses the symbol index instead of doing a fully fledged
125395410Smarcel * hash table based lookup when such is valid. For example for local symbols.
125495410Smarcel * This is not only more efficient, it's also more correct. It's not always
125595410Smarcel * the case that the symbol can be found through the hash table.
125695410Smarcel */
1257129282Speterstatic Elf_Addr
125895410Smarcelelf_lookup(linker_file_t lf, Elf_Word symidx, int deps)
125995410Smarcel{
126095410Smarcel	elf_file_t ef = (elf_file_t)lf;
126195410Smarcel	const Elf_Sym *sym;
126295410Smarcel	const char *symbol;
126395410Smarcel
126495410Smarcel	/* Don't even try to lookup the symbol if the index is bogus. */
126595410Smarcel	if (symidx >= ef->nchains)
126695410Smarcel		return (0);
126795410Smarcel
126895410Smarcel	sym = ef->symtab + symidx;
126995410Smarcel
127095410Smarcel	/*
127195410Smarcel	 * Don't do a full lookup when the symbol is local. It may even
127295410Smarcel	 * fail because it may not be found through the hash table.
127395410Smarcel	 */
127495410Smarcel	if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
127595410Smarcel		/* Force lookup failure when we have an insanity. */
127695410Smarcel		if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0)
127795410Smarcel			return (0);
127895410Smarcel		return ((Elf_Addr)ef->address + sym->st_value);
127995410Smarcel	}
128095410Smarcel
128195410Smarcel	/*
128295410Smarcel	 * XXX we can avoid doing a hash table based lookup for global
128395410Smarcel	 * symbols as well. This however is not always valid, so we'll
128495410Smarcel	 * just do it the hard way for now. Performance tweaks can
128595410Smarcel	 * always be added.
128695410Smarcel	 */
128795410Smarcel
128895410Smarcel	symbol = ef->strtab + sym->st_name;
128995410Smarcel
129095410Smarcel	/* Force a lookup failure if the symbol name is bogus. */
129195410Smarcel	if (*symbol == 0)
129295410Smarcel		return (0);
129395410Smarcel
129495410Smarcel	return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps));
129595410Smarcel}
1296109605Sjake
1297109605Sjakestatic void
1298109605Sjakelink_elf_reloc_local(linker_file_t lf)
1299109605Sjake{
1300109605Sjake    const Elf_Rel *rellim;
1301109605Sjake    const Elf_Rel *rel;
1302109605Sjake    const Elf_Rela *relalim;
1303109605Sjake    const Elf_Rela *rela;
1304109605Sjake    elf_file_t ef = (elf_file_t)lf;
1305109605Sjake
1306109605Sjake    /* Perform relocations without addend if there are any: */
1307109605Sjake    if ((rel = ef->rel) != NULL) {
1308109605Sjake	rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
1309109605Sjake	while (rel < rellim) {
1310129282Speter	    elf_reloc_local(lf, (Elf_Addr)ef->address, rel, ELF_RELOC_REL,
1311129282Speter			    elf_lookup);
1312109605Sjake	    rel++;
1313109605Sjake	}
1314109605Sjake    }
1315109605Sjake
1316109605Sjake    /* Perform relocations with addend if there are any: */
1317109605Sjake    if ((rela = ef->rela) != NULL) {
1318109605Sjake	relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
1319109605Sjake	while (rela < relalim) {
1320129282Speter	    elf_reloc_local(lf, (Elf_Addr)ef->address, rela, ELF_RELOC_RELA,
1321129282Speter			    elf_lookup);
1322109605Sjake	    rela++;
1323109605Sjake	}
1324109605Sjake    }
1325109605Sjake}
1326