link_elf.c revision 103436
138032Speter/*-
2147081Sgshapiro * Copyright (c) 1998-2000 Doug Rabson
364565Sgshapiro * All rights reserved.
438032Speter *
538032Speter * Redistribution and use in source and binary forms, with or without
638032Speter * modification, are permitted provided that the following conditions
738032Speter * are met:
838032Speter * 1. Redistributions of source code must retain the above copyright
938032Speter *    notice, this list of conditions and the following disclaimer.
1038032Speter * 2. Redistributions in binary form must reproduce the above copyright
1138032Speter *    notice, this list of conditions and the following disclaimer in the
12120259Sgshapiro *    documentation and/or other materials provided with the distribution.
1338032Speter *
1438032Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1564565Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1664565Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17147081Sgshapiro * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1864565Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1964565Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2064565Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2164565Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2264565Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338032Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438032Speter * SUCH DAMAGE.
2564565Sgshapiro *
2664565Sgshapiro * $FreeBSD: head/sys/kern/link_elf.c 103436 2002-09-17 01:49:00Z peter $
2764565Sgshapiro */
2864565Sgshapiro
2964565Sgshapiro#include "opt_ddb.h"
3090795Sgshapiro
3164565Sgshapiro#include <sys/param.h>
3238032Speter#include <sys/systm.h>
3338032Speter#include <sys/kernel.h>
3438032Speter#include <sys/lock.h>
3538032Speter#include <sys/malloc.h>
3638032Speter#include <sys/mutex.h>
3738032Speter#include <sys/proc.h>
3838032Speter#include <sys/namei.h>
3938032Speter#include <sys/fcntl.h>
4038032Speter#include <sys/vnode.h>
4138032Speter#include <sys/linker.h>
4238032Speter
4338032Speter#include <machine/elf.h>
4438032Speter#ifdef GPROF
4538032Speter#include <machine/profile.h>
4638032Speter#endif
4738032Speter
4838032Speter#include <vm/vm.h>
4938032Speter#include <vm/vm_param.h>
5038032Speter#ifdef SPARSE_MAPPING
5138032Speter#include <vm/vm_object.h>
5238032Speter#include <vm/vm_kern.h>
5338032Speter#include <vm/vm_extern.h>
5438032Speter#endif
5538032Speter#include <vm/pmap.h>
5638032Speter#include <vm/vm_map.h>
5738032Speter
5838032Speter#include <sys/link_elf.h>
5938032Speter
6038032Speter#include "linker_if.h"
6138032Speter
6238032Spetertypedef struct elf_file {
6364565Sgshapiro    struct linker_file	lf;		/* Common fields */
6438032Speter    int			preloaded;	/* Was file pre-loaded */
6590795Sgshapiro    caddr_t		address;	/* Relocation address */
6638032Speter#ifdef SPARSE_MAPPING
6738032Speter    vm_object_t		object;		/* VM object to hold file pages */
6838032Speter#endif
6938032Speter    Elf_Dyn*		dynamic;	/* Symbol table etc. */
7038032Speter    Elf_Hashelt		nbuckets;	/* DT_HASH info */
7138032Speter    Elf_Hashelt		nchains;
7238032Speter    const Elf_Hashelt*	buckets;
7338032Speter    const Elf_Hashelt*	chains;
7438032Speter    caddr_t		hash;
7538032Speter    caddr_t		strtab;		/* DT_STRTAB */
7638032Speter    int			strsz;		/* DT_STRSZ */
7738032Speter    const Elf_Sym*	symtab;		/* DT_SYMTAB */
7838032Speter    Elf_Addr*		got;		/* DT_PLTGOT */
7938032Speter    const Elf_Rel*	pltrel;		/* DT_JMPREL */
8038032Speter    int			pltrelsize;	/* DT_PLTRELSZ */
8138032Speter    const Elf_Rela*	pltrela;	/* DT_JMPREL */
8238032Speter    int			pltrelasize;	/* DT_PLTRELSZ */
8338032Speter    const Elf_Rel*	rel;		/* DT_REL */
8438032Speter    int			relsize;	/* DT_RELSZ */
8538032Speter    const Elf_Rela*	rela;		/* DT_RELA */
8638032Speter    int			relasize;	/* DT_RELASZ */
8738032Speter    caddr_t		modptr;
8838032Speter    const Elf_Sym*	ddbsymtab;	/* The symbol table we are using */
8938032Speter    long		ddbsymcnt;	/* Number of symbols */
9038032Speter    caddr_t		ddbstrtab;	/* String table */
9138032Speter    long		ddbstrcnt;	/* number of bytes in string table */
9238032Speter    caddr_t		symbase;	/* malloc'ed symbold base */
9338032Speter    caddr_t		strbase;	/* malloc'ed string base */
9438032Speter#ifdef DDB
9538032Speter    struct link_map	gdb;		/* hooks for gdb */
9638032Speter#endif
9738032Speter} *elf_file_t;
9838032Speter
9938032Speterstatic int	link_elf_link_preload(linker_class_t cls,
10038032Speter				      const char*, linker_file_t*);
10138032Speterstatic int	link_elf_link_preload_finish(linker_file_t);
10238032Speterstatic int	link_elf_load_file(linker_class_t, const char*, linker_file_t*);
10338032Speterstatic int	link_elf_lookup_symbol(linker_file_t, const char*,
10490795Sgshapiro				       c_linker_sym_t*);
10538032Speterstatic int	link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*);
10638032Speterstatic int	link_elf_search_symbol(linker_file_t, caddr_t value,
10790795Sgshapiro				       c_linker_sym_t* sym, long* diffp);
10890795Sgshapiro
10938032Speterstatic void	link_elf_unload_file(linker_file_t);
11038032Speterstatic void	link_elf_unload_preload(linker_file_t);
11164565Sgshapirostatic int	link_elf_lookup_set(linker_file_t, const char *,
11290795Sgshapiro				    void ***, void ***, int *);
11390795Sgshapirostatic int	link_elf_each_function_name(linker_file_t,
11438032Speter				int (*)(const char *, void *),
11538032Speter				void *);
11638032Speter
11738032Speterstatic kobj_method_t link_elf_methods[] = {
11890795Sgshapiro    KOBJMETHOD(linker_lookup_symbol,	link_elf_lookup_symbol),
11938032Speter    KOBJMETHOD(linker_symbol_values,	link_elf_symbol_values),
12038032Speter    KOBJMETHOD(linker_search_symbol,	link_elf_search_symbol),
12138032Speter    KOBJMETHOD(linker_unload,		link_elf_unload_file),
12238032Speter    KOBJMETHOD(linker_load_file,	link_elf_load_file),
12338032Speter    KOBJMETHOD(linker_link_preload,	link_elf_link_preload),
12438032Speter    KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish),
12538032Speter    KOBJMETHOD(linker_lookup_set,	link_elf_lookup_set),
12638032Speter    KOBJMETHOD(linker_each_function_name, link_elf_each_function_name),
12738032Speter    { 0, 0 }
12838032Speter};
12938032Speter
13038032Speterstatic struct linker_class link_elf_class = {
13138032Speter#if ELF_TARG_CLASS == ELFCLASS32
13238032Speter    "elf32",
13338032Speter#else
13438032Speter    "elf64",
13538032Speter#endif
13638032Speter    link_elf_methods, sizeof(struct elf_file)
13738032Speter};
13838032Speter
13938032Speterstatic int		parse_dynamic(elf_file_t ef);
14038032Speterstatic int		relocate_file(elf_file_t ef);
14138032Speterstatic int		link_elf_preload_parse_symbols(elf_file_t ef);
14238032Speter
14338032Speter#ifdef DDB
14438032Speterstatic void		r_debug_state(struct r_debug *dummy_one,
14538032Speter				      struct link_map *dummy_two);
14690795Sgshapiro
14764565Sgshapiro/*
14864565Sgshapiro * A list of loaded modules for GDB to use for loading symbols.
14938032Speter */
15038032Speterstruct r_debug r_debug;
15138032Speter
15238032Speter#define GDB_STATE(s)	r_debug.r_state = s; r_debug_state(NULL, NULL);
15338032Speter
15438032Speter/*
15538032Speter * Function for the debugger to set a breakpoint on to gain control.
15638032Speter */
15738032Spetervoid
15838032Speterr_debug_state(struct r_debug *dummy_one __unused,
15938032Speter	      struct link_map *dummy_two __unused)
16038032Speter{
16194337Sgshapiro}
16264565Sgshapiro
16364565Sgshapiro#endif
16464565Sgshapiro
16564565Sgshapiro#ifdef __ia64__
16638032SpeterElf_Addr link_elf_get_gp(linker_file_t);
16764565Sgshapiro#endif
16838032Speter
16964565Sgshapiro/*
17064565Sgshapiro * The kernel symbol table starts here.
17190795Sgshapiro */
17238032Speterextern struct _dynamic _DYNAMIC;
17338032Speter
17438032Speterstatic void
17538032Speterlink_elf_init(void* arg)
17638032Speter{
17738032Speter    Elf_Dyn	*dp;
17838032Speter    caddr_t	modptr, baseptr, sizeptr;
17938032Speter    elf_file_t	ef;
18038032Speter    char	*modname;
18190795Sgshapiro#ifdef DDB
18238032Speter    char *newfilename;
18338032Speter#endif
18438032Speter
18538032Speter    linker_add_class(&link_elf_class);
18638032Speter
18738032Speter    dp = (Elf_Dyn*) &_DYNAMIC;
18890795Sgshapiro    modname = NULL;
18990795Sgshapiro    modptr = preload_search_by_type("elf kernel");
19038032Speter    if (modptr)
19138032Speter	modname = (char *)preload_search_info(modptr, MODINFO_NAME);
19238032Speter    if (modname == NULL)
19338032Speter	modname = "kernel";
19438032Speter    linker_kernel_file = linker_make_file(modname, &link_elf_class);
19538032Speter    if (linker_kernel_file == NULL)
19664565Sgshapiro	panic("link_elf_init: Can't create linker structures for kernel");
19738032Speter
19838032Speter    ef = (elf_file_t) linker_kernel_file;
19938032Speter    ef->preloaded = 1;
20038032Speter    ef->address = 0;
20138032Speter#ifdef SPARSE_MAPPING
20238032Speter    ef->object = 0;
20338032Speter#endif
20438032Speter    ef->dynamic = dp;
20538032Speter
20638032Speter    if (dp)
20738032Speter	parse_dynamic(ef);
20838032Speter    linker_kernel_file->address = (caddr_t) KERNBASE;
20938032Speter    linker_kernel_file->size = -(intptr_t)linker_kernel_file->address;
21038032Speter
21138032Speter    if (modptr) {
21238032Speter	ef->modptr = modptr;
21338032Speter	baseptr = preload_search_info(modptr, MODINFO_ADDR);
21490795Sgshapiro	if (baseptr)
21590795Sgshapiro	    linker_kernel_file->address = *(caddr_t *)baseptr;
21690795Sgshapiro	sizeptr = preload_search_info(modptr, MODINFO_SIZE);
21738032Speter	if (sizeptr)
21838032Speter	    linker_kernel_file->size = *(size_t *)sizeptr;
21964565Sgshapiro    }
22090795Sgshapiro    (void)link_elf_preload_parse_symbols(ef);
22190795Sgshapiro
22238032Speter#ifdef DDB
22364565Sgshapiro    ef->gdb.l_addr = linker_kernel_file->address;
22438032Speter    newfilename = malloc(strlen(modname) + 1, M_LINKER, M_WAITOK);
22538032Speter    strcpy(newfilename, modname);
22638032Speter    ef->gdb.l_name = newfilename;
22738032Speter    ef->gdb.l_ld = dp;
22838032Speter    ef->gdb.l_prev = 0;
22938032Speter    ef->gdb.l_next = 0;
23038032Speter
23138032Speter    r_debug.r_map = &ef->gdb;
23238032Speter    r_debug.r_brk = r_debug_state;
23390795Sgshapiro    r_debug.r_state = RT_CONSISTENT;
23438032Speter
23590795Sgshapiro    r_debug_state(NULL, NULL);	/* say hello to gdb! */
23638032Speter#endif
23738032Speter}
23838032Speter
23938032SpeterSYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0);
24090795Sgshapiro
24138032Speterstatic int
24290795Sgshapirolink_elf_preload_parse_symbols(elf_file_t ef)
24338032Speter{
24438032Speter    caddr_t	pointer;
24538032Speter    caddr_t	ssym, esym, base;
24638032Speter    caddr_t	strtab;
24738032Speter    int		strcnt;
24890795Sgshapiro    Elf_Sym*	symtab;
24990795Sgshapiro    int		symcnt;
25090795Sgshapiro
25190795Sgshapiro    if (ef->modptr == NULL)
25290795Sgshapiro	return 0;
25390795Sgshapiro    pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM);
25438032Speter    if (pointer == NULL)
25590795Sgshapiro	return 0;
25690795Sgshapiro    ssym = *(caddr_t *)pointer;
25790795Sgshapiro    pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM);
25890795Sgshapiro    if (pointer == NULL)
25990795Sgshapiro	return 0;
26090795Sgshapiro    esym = *(caddr_t *)pointer;
26190795Sgshapiro
26290795Sgshapiro    base = ssym;
26390795Sgshapiro
26490795Sgshapiro    symcnt = *(long *)base;
26538032Speter    base += sizeof(long);
26690795Sgshapiro    symtab = (Elf_Sym *)base;
26738032Speter    base += roundup(symcnt, sizeof(long));
26838032Speter
26938032Speter    if (base > esym || base < ssym) {
27090795Sgshapiro	printf("Symbols are corrupt!\n");
27190795Sgshapiro	return EINVAL;
27238032Speter    }
27338032Speter
27438032Speter    strcnt = *(long *)base;
27538032Speter    base += sizeof(long);
27638032Speter    strtab = base;
27738032Speter    base += roundup(strcnt, sizeof(long));
27838032Speter
27938032Speter    if (base > esym || base < ssym) {
28038032Speter	printf("Symbols are corrupt!\n");
28138032Speter	return EINVAL;
28238032Speter    }
28338032Speter
28438032Speter    ef->ddbsymtab = symtab;
28538032Speter    ef->ddbsymcnt = symcnt / sizeof(Elf_Sym);
28638032Speter    ef->ddbstrtab = strtab;
28738032Speter    ef->ddbstrcnt = strcnt;
28838032Speter
28971348Sgshapiro    return 0;
29038032Speter}
29138032Speter
29271348Sgshapirostatic int
29338032Speterparse_dynamic(elf_file_t ef)
29490795Sgshapiro{
29538032Speter    Elf_Dyn *dp;
29690795Sgshapiro    int plttype = DT_REL;
29790795Sgshapiro
29890795Sgshapiro    for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
29990795Sgshapiro	switch (dp->d_tag) {
30090795Sgshapiro	case DT_HASH:
30190795Sgshapiro	{
30290795Sgshapiro	    /* From src/libexec/rtld-elf/rtld.c */
30338032Speter	    const Elf_Hashelt *hashtab = (const Elf_Hashelt *)
30438032Speter		(ef->address + dp->d_un.d_ptr);
30538032Speter	    ef->nbuckets = hashtab[0];
30638032Speter	    ef->nchains = hashtab[1];
30738032Speter	    ef->buckets = hashtab + 2;
30838032Speter	    ef->chains = ef->buckets + ef->nbuckets;
30938032Speter	    break;
31038032Speter	}
31138032Speter	case DT_STRTAB:
31238032Speter	    ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr);
31338032Speter	    break;
31438032Speter	case DT_STRSZ:
31564565Sgshapiro	    ef->strsz = dp->d_un.d_val;
31638032Speter	    break;
31738032Speter	case DT_SYMTAB:
31838032Speter	    ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr);
31938032Speter	    break;
32038032Speter	case DT_SYMENT:
32171348Sgshapiro	    if (dp->d_un.d_val != sizeof(Elf_Sym))
32264565Sgshapiro		return ENOEXEC;
32338032Speter	    break;
32438032Speter	case DT_PLTGOT:
32538032Speter	    ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr);
32690795Sgshapiro	    break;
32790795Sgshapiro	case DT_REL:
32890795Sgshapiro	    ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr);
32990795Sgshapiro	    break;
33090795Sgshapiro	case DT_RELSZ:
33190795Sgshapiro	    ef->relsize = dp->d_un.d_val;
33290795Sgshapiro	    break;
33390795Sgshapiro	case DT_RELENT:
33490795Sgshapiro	    if (dp->d_un.d_val != sizeof(Elf_Rel))
33590795Sgshapiro		return ENOEXEC;
33690795Sgshapiro	    break;
33790795Sgshapiro	case DT_JMPREL:
33890795Sgshapiro	    ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr);
33964565Sgshapiro	    break;
34090795Sgshapiro	case DT_PLTRELSZ:
34164565Sgshapiro	    ef->pltrelsize = dp->d_un.d_val;
34264565Sgshapiro	    break;
34364565Sgshapiro	case DT_RELA:
34464565Sgshapiro	    ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr);
34564565Sgshapiro	    break;
34664565Sgshapiro	case DT_RELASZ:
34738032Speter	    ef->relasize = dp->d_un.d_val;
34838032Speter	    break;
34990795Sgshapiro	case DT_RELAENT:
35064565Sgshapiro	    if (dp->d_un.d_val != sizeof(Elf_Rela))
35138032Speter		return ENOEXEC;
35238032Speter	    break;
35338032Speter	case DT_PLTREL:
35438032Speter	    plttype = dp->d_un.d_val;
35538032Speter	    if (plttype != DT_REL && plttype != DT_RELA)
35638032Speter		return ENOEXEC;
35738032Speter	    break;
35838032Speter#ifdef DDB
35990795Sgshapiro	case DT_DEBUG:
36038032Speter	    dp->d_un.d_ptr = (Elf_Addr) &r_debug;
36138032Speter	    break;
36238032Speter#endif
36338032Speter	}
36438032Speter    }
36538032Speter
36638032Speter    if (plttype == DT_RELA) {
36738032Speter	ef->pltrela = (const Elf_Rela *) ef->pltrel;
36838032Speter	ef->pltrel = NULL;
36938032Speter	ef->pltrelasize = ef->pltrelsize;
37038032Speter	ef->pltrelsize = 0;
37138032Speter    }
37238032Speter
37338032Speter    ef->ddbsymtab = ef->symtab;
37438032Speter    ef->ddbsymcnt = ef->nchains;
37538032Speter    ef->ddbstrtab = ef->strtab;
37638032Speter    ef->ddbstrcnt = ef->strsz;
37738032Speter
37890795Sgshapiro    return 0;
37938032Speter}
38038032Speter
38138032Speterstatic void
38290795Sgshapirolink_elf_error(const char *s)
38390795Sgshapiro{
38438032Speter    printf("kldload: %s\n", s);
38538032Speter}
38638032Speter
38738032Speter#ifdef DDB
38838032Speter
38938032Speterstatic void
39038032Speterlink_elf_add_gdb(struct link_map *l)
39138032Speter{
39294337Sgshapiro    struct link_map *prev;
39338032Speter
39438032Speter    /*
39538032Speter     * Scan to the end of the list.
39638032Speter     */
39738032Speter    for (prev = r_debug.r_map; prev->l_next != NULL; prev = prev->l_next)
39838032Speter	;
39938032Speter
40038032Speter    /* Link in the new entry. */
40138032Speter    l->l_prev = prev;
402141887Sgshapiro    l->l_next = prev->l_next;
40390795Sgshapiro    prev->l_next = l;
404141887Sgshapiro}
405141887Sgshapiro
406141887Sgshapirostatic void
407141887Sgshapirolink_elf_delete_gdb(struct link_map *l)
408141887Sgshapiro{
409141887Sgshapiro    if (l->l_prev == NULL) {
410141887Sgshapiro	if ((r_debug.r_map = l->l_next) != NULL)
411141887Sgshapiro	    l->l_next->l_prev = NULL;
412141887Sgshapiro	return;
413141887Sgshapiro    }
414141887Sgshapiro
415141887Sgshapiro    if ((l->l_prev->l_next = l->l_next) != NULL)
416141887Sgshapiro	l->l_next->l_prev = l->l_prev;
417141887Sgshapiro}
418141887Sgshapiro
419141887Sgshapiro#endif /* DDB */
420141887Sgshapiro
421141887Sgshapirostatic int
422141887Sgshapirolink_elf_link_preload(linker_class_t cls,
423141887Sgshapiro		      const char* filename, linker_file_t *result)
424141887Sgshapiro{
425141887Sgshapiro    caddr_t		modptr, baseptr, sizeptr, dynptr;
426141887Sgshapiro    char		*type;
427141887Sgshapiro    elf_file_t		ef;
428141887Sgshapiro    linker_file_t	lf;
429141887Sgshapiro    int			error;
430141887Sgshapiro    vm_offset_t		dp;
431141887Sgshapiro
432141887Sgshapiro    /* Look to see if we have the file preloaded */
433141887Sgshapiro    modptr = preload_search_by_name(filename);
434141887Sgshapiro    if (modptr == NULL)
435141887Sgshapiro	return ENOENT;
436141887Sgshapiro
437141887Sgshapiro    type = (char *)preload_search_info(modptr, MODINFO_TYPE);
438141887Sgshapiro    baseptr = preload_search_info(modptr, MODINFO_ADDR);
439141887Sgshapiro    sizeptr = preload_search_info(modptr, MODINFO_SIZE);
440141887Sgshapiro    dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC);
441141887Sgshapiro    if (type == NULL || strcmp(type, "elf module") != 0)
442141887Sgshapiro	return (EFTYPE);
443141887Sgshapiro    if (baseptr == NULL || sizeptr == NULL || dynptr == NULL)
444141887Sgshapiro	return (EINVAL);
445141887Sgshapiro
446141887Sgshapiro    lf = linker_make_file(filename, &link_elf_class);
447141887Sgshapiro    if (lf == NULL) {
448141887Sgshapiro	return ENOMEM;
449141887Sgshapiro    }
450141887Sgshapiro
451141887Sgshapiro    ef = (elf_file_t) lf;
452141887Sgshapiro    ef->preloaded = 1;
453141887Sgshapiro    ef->modptr = modptr;
45490795Sgshapiro    ef->address = *(caddr_t *)baseptr;
45590795Sgshapiro#ifdef SPARSE_MAPPING
45690795Sgshapiro    ef->object = 0;
45790795Sgshapiro#endif
45890795Sgshapiro    dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr;
45990795Sgshapiro    ef->dynamic = (Elf_Dyn *)dp;
46090795Sgshapiro    lf->address = ef->address;
46190795Sgshapiro    lf->size = *(size_t *)sizeptr;
46290795Sgshapiro
46390795Sgshapiro    error = parse_dynamic(ef);
46490795Sgshapiro    if (error) {
46590795Sgshapiro	linker_file_unload(lf);
46690795Sgshapiro	return error;
46790795Sgshapiro    }
46890795Sgshapiro    *result = lf;
46990795Sgshapiro    return (0);
47090795Sgshapiro}
47190795Sgshapiro
47290795Sgshapirostatic int
47390795Sgshapirolink_elf_link_preload_finish(linker_file_t lf)
47490795Sgshapiro{
47590795Sgshapiro    elf_file_t		ef;
47690795Sgshapiro    int error;
47790795Sgshapiro#ifdef DDB
47890795Sgshapiro    char *newfilename;
47964565Sgshapiro#endif
48090795Sgshapiro
48190795Sgshapiro    ef = (elf_file_t) lf;
48290795Sgshapiro#if 0	/* this will be more trouble than it's worth for now */
48390795Sgshapiro    for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
48490795Sgshapiro	if (dp->d_tag != DT_NEEDED)
48590795Sgshapiro	    continue;
48690795Sgshapiro	modname = ef->strtab + dp->d_un.d_val;
48764565Sgshapiro	error = linker_load_module(modname, lf);
48864565Sgshapiro	if (error)
48964565Sgshapiro	    goto out;
49064565Sgshapiro    }
49164565Sgshapiro#endif
49264565Sgshapiro    error = relocate_file(ef);
49364565Sgshapiro    if (error)
49464565Sgshapiro	return error;
49564565Sgshapiro    (void)link_elf_preload_parse_symbols(ef);
49664565Sgshapiro
49771348Sgshapiro#ifdef DDB
49890795Sgshapiro    GDB_STATE(RT_ADD);
49964565Sgshapiro    ef->gdb.l_addr = lf->address;
50064565Sgshapiro    newfilename = malloc(strlen(lf->filename) + 1, M_LINKER, M_WAITOK);
50190795Sgshapiro    strcpy(newfilename, lf->filename);
50264565Sgshapiro    ef->gdb.l_name = newfilename;
50364565Sgshapiro    ef->gdb.l_ld = ef->dynamic;
50490795Sgshapiro    link_elf_add_gdb(&ef->gdb);
50564565Sgshapiro    GDB_STATE(RT_CONSISTENT);
50690795Sgshapiro#endif
50738032Speter
50838032Speter    return (0);
50938032Speter}
51038032Speter
51138032Speterstatic int
51238032Speterlink_elf_load_file(linker_class_t cls, const char* filename, linker_file_t* result)
51338032Speter{
51438032Speter    struct nameidata nd;
51538032Speter    struct thread* td = curthread;	/* XXX */
51638032Speter    Elf_Ehdr *hdr;
51738032Speter    caddr_t firstpage;
51838032Speter    int nbytes, i;
51938032Speter    Elf_Phdr *phdr;
52038032Speter    Elf_Phdr *phlimit;
52138032Speter    Elf_Phdr *segs[2];
52238032Speter    int nsegs;
52338032Speter    Elf_Phdr *phdyn;
52438032Speter    Elf_Phdr *phphdr;
52538032Speter    caddr_t mapbase;
52638032Speter    size_t mapsize;
52738032Speter    Elf_Off base_offset;
52838032Speter    Elf_Addr base_vaddr;
52938032Speter    Elf_Addr base_vlimit;
53090795Sgshapiro    int error = 0;
53190795Sgshapiro    int resid, flags;
53290795Sgshapiro    elf_file_t ef;
53390795Sgshapiro    linker_file_t lf;
53490795Sgshapiro    Elf_Shdr *shdr;
53538032Speter    int symtabindex;
53690795Sgshapiro    int symstrindex;
53738032Speter    int symcnt;
53890795Sgshapiro    int strcnt;
53938032Speter#ifdef DDB
54038032Speter    char *newfilename;
54138032Speter#endif
542132946Sgshapiro
54338032Speter    GIANT_REQUIRED;
54438032Speter
54538032Speter    shdr = NULL;
54638032Speter    lf = NULL;
54738032Speter
54838032Speter    NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td);
54938032Speter    flags = FREAD;
55038032Speter    error = vn_open(&nd, &flags, 0);
55138032Speter    if (error)
55238032Speter	return error;
55338032Speter    NDFREE(&nd, NDF_ONLY_PNBUF);
55438032Speter
55538032Speter    /*
55638032Speter     * Read the elf header from the file.
55764565Sgshapiro     */
55838032Speter    firstpage = malloc(PAGE_SIZE, M_LINKER, M_WAITOK);
55938032Speter    if (firstpage == NULL) {
56038032Speter	error = ENOMEM;
56138032Speter	goto out;
56238032Speter    }
56338032Speter    hdr = (Elf_Ehdr *)firstpage;
56438032Speter    error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0,
56538032Speter		    UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
56638032Speter		    &resid, td);
56738032Speter    nbytes = PAGE_SIZE - resid;
56838032Speter    if (error)
56938032Speter	goto out;
57038032Speter
57138032Speter    if (!IS_ELF(*hdr)) {
57290795Sgshapiro	error = ENOEXEC;
57390795Sgshapiro	goto out;
57490795Sgshapiro    }
57590795Sgshapiro
57690795Sgshapiro    if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS
57790795Sgshapiro      || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) {
57890795Sgshapiro	link_elf_error("Unsupported file layout");
57990795Sgshapiro	error = ENOEXEC;
58090795Sgshapiro	goto out;
58171348Sgshapiro    }
58238032Speter    if (hdr->e_ident[EI_VERSION] != EV_CURRENT
58338032Speter      || hdr->e_version != EV_CURRENT) {
58438032Speter	link_elf_error("Unsupported file version");
585132946Sgshapiro	error = ENOEXEC;
586132946Sgshapiro	goto out;
58738032Speter    }
58838032Speter    if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) {
58938032Speter	link_elf_error("Unsupported file type");
59038032Speter	error = ENOEXEC;
59138032Speter	goto out;
59238032Speter    }
59338032Speter    if (hdr->e_machine != ELF_TARG_MACH) {
59438032Speter	link_elf_error("Unsupported machine");
59538032Speter	error = ENOEXEC;
59690795Sgshapiro	goto out;
59738032Speter    }
59838032Speter
59938032Speter    /*
60090795Sgshapiro     * We rely on the program header being in the first page.  This is
60138032Speter     * not strictly required by the ABI specification, but it seems to
60238032Speter     * always true in practice.  And, it simplifies things considerably.
60390795Sgshapiro     */
60438032Speter    if (!((hdr->e_phentsize == sizeof(Elf_Phdr)) &&
605120259Sgshapiro	  (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) &&
606120259Sgshapiro	  (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= nbytes)))
607120259Sgshapiro	link_elf_error("Unreadable program headers");
608120259Sgshapiro
609120259Sgshapiro    /*
610120259Sgshapiro     * Scan the program header entries, and save key information.
611120259Sgshapiro     *
612120259Sgshapiro     * We rely on there being exactly two load segments, text and data,
613120259Sgshapiro     * in that order.
614120259Sgshapiro     */
61538032Speter    phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff);
61638032Speter    phlimit = phdr + hdr->e_phnum;
61738032Speter    nsegs = 0;
61838032Speter    phdyn = NULL;
619120259Sgshapiro    phphdr = NULL;
62038032Speter    while (phdr < phlimit) {
62138032Speter	switch (phdr->p_type) {
62238032Speter
62338032Speter	case PT_LOAD:
62490795Sgshapiro	    if (nsegs == 2) {
62590795Sgshapiro		link_elf_error("Too many sections");
62638032Speter		error = ENOEXEC;
62738032Speter		goto out;
62838032Speter	    }
62938032Speter	    segs[nsegs] = phdr;
63090795Sgshapiro	    ++nsegs;
63190795Sgshapiro	    break;
63290795Sgshapiro
63338032Speter	case PT_PHDR:
63438032Speter	    phphdr = phdr;
63564565Sgshapiro	    break;
63638032Speter
63790795Sgshapiro	case PT_DYNAMIC:
63838032Speter	    phdyn = phdr;
63990795Sgshapiro	    break;
64038032Speter
64138032Speter	case PT_INTERP:
64238032Speter	    link_elf_error("Unsupported file type");
64390795Sgshapiro	    error = ENOEXEC;
64438032Speter	    goto out;
64590795Sgshapiro	}
64638032Speter
64790795Sgshapiro	++phdr;
64838032Speter    }
64990795Sgshapiro    if (phdyn == NULL) {
65038032Speter	link_elf_error("Object is not dynamically-linked");
65138032Speter	error = ENOEXEC;
65238032Speter	goto out;
65338032Speter    }
654132946Sgshapiro
65538032Speter    /*
65690795Sgshapiro     * Allocate the entire address space of the object, to stake out our
65738032Speter     * contiguous region, and to establish the base address for relocation.
65838032Speter     */
65938032Speter    base_offset = trunc_page(segs[0]->p_offset);
660132946Sgshapiro    base_vaddr = trunc_page(segs[0]->p_vaddr);
66138032Speter    base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz);
66238032Speter    mapsize = base_vlimit - base_vaddr;
66338032Speter
66438032Speter    lf = linker_make_file(filename, &link_elf_class);
66538032Speter    if (!lf) {
66638032Speter	error = ENOMEM;
66738032Speter	goto out;
66838032Speter    }
669132946Sgshapiro
670132946Sgshapiro    ef = (elf_file_t) lf;
67138032Speter#ifdef SPARSE_MAPPING
67238032Speter    ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT);
67338032Speter    if (ef->object == NULL) {
67438032Speter	free(ef, M_LINKER);
67538032Speter	error = ENOMEM;
67638032Speter	goto out;
67738032Speter    }
67838032Speter    vm_object_reference(ef->object);
679132946Sgshapiro    ef->address = (caddr_t) vm_map_min(kernel_map);
68038032Speter    error = vm_map_find(kernel_map, ef->object, 0,
68190795Sgshapiro			(vm_offset_t *) &ef->address,
68242580Speter			mapsize, 1,
68338032Speter			VM_PROT_ALL, VM_PROT_ALL, 0);
68438032Speter    if (error) {
68538032Speter	vm_object_deallocate(ef->object);
68638032Speter	ef->object = 0;
68738032Speter	goto out;
68838032Speter    }
68990795Sgshapiro#else
69038032Speter    ef->address = malloc(mapsize, M_LINKER, M_WAITOK);
69138032Speter    if (!ef->address) {
69238032Speter	error = ENOMEM;
69338032Speter	goto out;
69438032Speter    }
69538032Speter#endif
69664565Sgshapiro    mapbase = ef->address;
69738032Speter
69838032Speter    /*
69938032Speter     * Read the text and data sections and zero the bss.
70038032Speter     */
70138032Speter    for (i = 0; i < 2; i++) {
70238032Speter	caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr;
70338032Speter	error = vn_rdwr(UIO_READ, nd.ni_vp,
70438032Speter			segbase, segs[i]->p_filesz, segs[i]->p_offset,
70538032Speter			UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
70638032Speter			&resid, td);
70790795Sgshapiro	if (error) {
70838032Speter	    goto out;
70938032Speter	}
71038032Speter	bzero(segbase + segs[i]->p_filesz,
71138032Speter	      segs[i]->p_memsz - segs[i]->p_filesz);
71238032Speter
71338032Speter#ifdef SPARSE_MAPPING
71438032Speter	/*
71538032Speter	 * Wire down the pages
71638032Speter	 */
71764565Sgshapiro	vm_map_wire(kernel_map,
71838032Speter		    (vm_offset_t) segbase,
71938032Speter		    (vm_offset_t) segbase + segs[i]->p_memsz,
72038032Speter		    FALSE);
72164565Sgshapiro#endif
72238032Speter    }
72398125Sgshapiro
72438032Speter#ifdef GPROF
72538032Speter    /* Update profiling information with the new text segment. */
72638032Speter    kmupetext((uintfptr_t)(mapbase + segs[0]->p_vaddr - base_vaddr +
72738032Speter	segs[0]->p_memsz));
72838032Speter#endif
72990795Sgshapiro
73090795Sgshapiro    ef->dynamic = (Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr);
73138032Speter
73290795Sgshapiro    lf->address = ef->address;
73390795Sgshapiro    lf->size = mapsize;
73438032Speter
73538032Speter    error = parse_dynamic(ef);
73638032Speter    if (error)
73790795Sgshapiro	goto out;
73890795Sgshapiro    error = linker_load_dependencies(lf);
73938032Speter    if (error)
74038032Speter	goto out;
74138032Speter#if 0	/* this will be more trouble than it's worth for now */
74238032Speter    for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
74338032Speter	if (dp->d_tag != DT_NEEDED)
74438032Speter	    continue;
74564565Sgshapiro	modname = ef->strtab + dp->d_un.d_val;
74638032Speter	error = linker_load_module(modname, lf);
74738032Speter	if (error)
74838032Speter	    goto out;
74990795Sgshapiro    }
75038032Speter#endif
75138032Speter    error = relocate_file(ef);
75238032Speter    if (error)
75390795Sgshapiro	goto out;
75490795Sgshapiro
75538032Speter    /* Try and load the symbol table if it's present.  (you can strip it!) */
75638032Speter    nbytes = hdr->e_shnum * hdr->e_shentsize;
75790795Sgshapiro    if (nbytes == 0 || hdr->e_shoff == 0)
75864565Sgshapiro	goto nosyms;
75990795Sgshapiro    shdr = malloc(nbytes, M_LINKER, M_WAITOK | M_ZERO);
76038032Speter    if (shdr == NULL) {
76138032Speter	error = ENOMEM;
76238032Speter	goto out;
76338032Speter    }
76438032Speter    error = vn_rdwr(UIO_READ, nd.ni_vp,
76538032Speter		    (caddr_t)shdr, nbytes, hdr->e_shoff,
76690795Sgshapiro		    UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
76738032Speter		    &resid, td);
76838032Speter    if (error)
76964565Sgshapiro	goto out;
77038032Speter    symtabindex = -1;
77138032Speter    symstrindex = -1;
77290795Sgshapiro    for (i = 0; i < hdr->e_shnum; i++) {
77338032Speter	if (shdr[i].sh_type == SHT_SYMTAB) {
77438032Speter	    symtabindex = i;
77538032Speter	    symstrindex = shdr[i].sh_link;
77638032Speter	}
77738032Speter    }
77838032Speter    if (symtabindex < 0 || symstrindex < 0)
77938032Speter	goto nosyms;
78038032Speter
78138032Speter    symcnt = shdr[symtabindex].sh_size;
78238032Speter    ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK);
78338032Speter    strcnt = shdr[symstrindex].sh_size;
78438032Speter    ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK);
78538032Speter
78638032Speter    if (ef->symbase == NULL || ef->strbase == NULL) {
78738032Speter	error = ENOMEM;
78838032Speter	goto out;
78964565Sgshapiro    }
79038032Speter    error = vn_rdwr(UIO_READ, nd.ni_vp,
79138032Speter		    ef->symbase, symcnt, shdr[symtabindex].sh_offset,
79238032Speter		    UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
79338032Speter		    &resid, td);
79490795Sgshapiro    if (error)
79538032Speter	goto out;
79638032Speter    error = vn_rdwr(UIO_READ, nd.ni_vp,
79738032Speter		    ef->strbase, strcnt, shdr[symstrindex].sh_offset,
79838032Speter		    UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
79938032Speter		    &resid, td);
80038032Speter    if (error)
80138032Speter	goto out;
80238032Speter
80338032Speter    ef->ddbsymcnt = symcnt / sizeof(Elf_Sym);
80490795Sgshapiro    ef->ddbsymtab = (const Elf_Sym *)ef->symbase;
80538032Speter    ef->ddbstrcnt = strcnt;
80638032Speter    ef->ddbstrtab = ef->strbase;
80738032Speter
80838032Speter#ifdef DDB
80990795Sgshapiro    GDB_STATE(RT_ADD);
81038032Speter    ef->gdb.l_addr = lf->address;
81138032Speter    newfilename = malloc(strlen(filename) + 1, M_LINKER, M_WAITOK);
81238032Speter    strcpy(newfilename, filename);
81338032Speter    ef->gdb.l_name = (const char *)newfilename;
81438032Speter    ef->gdb.l_ld = ef->dynamic;
81590795Sgshapiro    link_elf_add_gdb(&ef->gdb);
81638032Speter    GDB_STATE(RT_CONSISTENT);
81738032Speter#endif
81838032Speter
81964565Sgshapironosyms:
82038032Speter
82190795Sgshapiro    *result = lf;
82242580Speter
82338032Speterout:
82438032Speter    if (error && lf)
82538032Speter	linker_file_unload(lf);
82638032Speter    if (shdr)
82738032Speter	free(shdr, M_LINKER);
82890795Sgshapiro    if (firstpage)
82938032Speter	free(firstpage, M_LINKER);
83038032Speter    VOP_UNLOCK(nd.ni_vp, 0, td);
83190795Sgshapiro    vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
83290795Sgshapiro
83338032Speter    return error;
83438032Speter}
83564565Sgshapiro
83638032Speterstatic void
83738032Speterlink_elf_unload_file(linker_file_t file)
83838032Speter{
83964565Sgshapiro    elf_file_t ef = (elf_file_t) file;
84090795Sgshapiro
84190795Sgshapiro#ifdef DDB
84298125Sgshapiro    if (ef->gdb.l_ld) {
84338032Speter	GDB_STATE(RT_DELETE);
84438032Speter	free((void *)(uintptr_t)ef->gdb.l_name, M_LINKER);
84538032Speter	link_elf_delete_gdb(&ef->gdb);
84638032Speter	GDB_STATE(RT_CONSISTENT);
84790795Sgshapiro    }
84890795Sgshapiro#endif
84938032Speter
85038032Speter    if (ef->preloaded) {
85138032Speter	link_elf_unload_preload(file);
85290795Sgshapiro	return;
85364565Sgshapiro    }
85438032Speter#ifdef SPARSE_MAPPING
85538032Speter    if (ef->object) {
85690795Sgshapiro	vm_map_remove(kernel_map, (vm_offset_t) ef->address,
85738032Speter		      (vm_offset_t) ef->address
85838032Speter		      + (ef->object->size << PAGE_SHIFT));
85990795Sgshapiro	vm_object_deallocate(ef->object);
86090795Sgshapiro    }
86164565Sgshapiro#else
86290795Sgshapiro    if (ef->address)
86390795Sgshapiro	free(ef->address, M_LINKER);
86438032Speter#endif
86538032Speter    if (ef->symbase)
86638032Speter	free(ef->symbase, M_LINKER);
86790795Sgshapiro    if (ef->strbase)
86838032Speter	free(ef->strbase, M_LINKER);
86938032Speter}
87038032Speter
87138032Speterstatic void
87238032Speterlink_elf_unload_preload(linker_file_t file)
87338032Speter{
87438032Speter    if (file->filename)
87538032Speter	preload_delete_name(file->filename);
87638032Speter}
87790795Sgshapiro
87890795Sgshapirostatic const char *
87938032Spetersymbol_name(elf_file_t ef, Elf_Word r_info)
88038032Speter{
88138032Speter    const Elf_Sym *ref;
88238032Speter
88390795Sgshapiro    if (ELF_R_SYM(r_info)) {
88490795Sgshapiro	ref = ef->symtab + ELF_R_SYM(r_info);
88564565Sgshapiro	return ef->strtab + ref->st_name;
88664565Sgshapiro    } else
88764565Sgshapiro	return NULL;
88890795Sgshapiro}
88990795Sgshapiro
89064565Sgshapirostatic int
89138032Speterrelocate_file(elf_file_t ef)
89290795Sgshapiro{
89338032Speter    const Elf_Rel *rellim;
89438032Speter    const Elf_Rel *rel;
89564565Sgshapiro    const Elf_Rela *relalim;
89638032Speter    const Elf_Rela *rela;
89738032Speter    const char *symname;
89890795Sgshapiro
89938032Speter    /* Perform relocations without addend if there are any: */
90038032Speter    rel = ef->rel;
90138032Speter    if (rel) {
90238032Speter	rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
90338032Speter	while (rel < rellim) {
90438032Speter	    if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL)) {
90538032Speter		symname = symbol_name(ef, rel->r_info);
90638032Speter		printf("link_elf: symbol %s undefined\n", symname);
90738032Speter		return ENOENT;
90838032Speter	    }
90938032Speter	    rel++;
91038032Speter	}
91138032Speter    }
91238032Speter
91338032Speter    /* Perform relocations with addend if there are any: */
91438032Speter    rela = ef->rela;
91538032Speter    if (rela) {
91638032Speter	relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
91764565Sgshapiro	while (rela < relalim) {
91838032Speter	    if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA)) {
91990795Sgshapiro		symname = symbol_name(ef, rela->r_info);
92038032Speter		printf("link_elf: symbol %s undefined\n", symname);
92138032Speter		return ENOENT;
92238032Speter	    }
92338032Speter	    rela++;
92438032Speter	}
92538032Speter    }
92638032Speter
92738032Speter    /* Perform PLT relocations without addend if there are any: */
92838032Speter    rel = ef->pltrel;
92938032Speter    if (rel) {
93038032Speter	rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize);
93138032Speter	while (rel < rellim) {
93238032Speter	    if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL)) {
93390795Sgshapiro		symname = symbol_name(ef, rel->r_info);
93490795Sgshapiro		printf("link_elf: symbol %s undefined\n", symname);
93538032Speter		return ENOENT;
93638032Speter	    }
93790795Sgshapiro	    rel++;
93890795Sgshapiro	}
93938032Speter    }
94090795Sgshapiro
94138032Speter    /* Perform relocations with addend if there are any: */
94238032Speter    rela = ef->pltrela;
94390795Sgshapiro    if (rela) {
94438032Speter	relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize);
94538032Speter	while (rela < relalim) {
94638032Speter	    if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA)) {
94738032Speter		symname = symbol_name(ef, rela->r_info);
94838032Speter		printf("link_elf: symbol %s undefined\n", symname);
94938032Speter		return ENOENT;
95038032Speter	    }
95138032Speter	    rela++;
95238032Speter	}
95338032Speter    }
95438032Speter
95538032Speter    return 0;
95638032Speter}
95738032Speter
95838032Speter/*
95938032Speter * Hash function for symbol table lookup.  Don't even think about changing
96038032Speter * this.  It is specified by the System V ABI.
96138032Speter */
96238032Speterstatic unsigned long
96338032Speterelf_hash(const char *name)
96438032Speter{
96538032Speter    const unsigned char *p = (const unsigned char *) name;
96638032Speter    unsigned long h = 0;
96738032Speter    unsigned long g;
96838032Speter
96938032Speter    while (*p != '\0') {
97038032Speter	h = (h << 4) + *p++;
97138032Speter	if ((g = h & 0xf0000000) != 0)
97238032Speter	    h ^= g >> 24;
97338032Speter	h &= ~g;
97438032Speter    }
97538032Speter    return h;
97638032Speter}
97738032Speter
97838032Speterint
97938032Speterlink_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym)
98038032Speter{
98138032Speter    elf_file_t ef = (elf_file_t) lf;
98238032Speter    unsigned long symnum;
98390795Sgshapiro    const Elf_Sym* symp;
984132946Sgshapiro    const char *strp;
98538032Speter    unsigned long hash;
98638032Speter    int i;
98738032Speter
98838032Speter    /* First, search hashed global symbols */
98938032Speter    hash = elf_hash(name);
99038032Speter    symnum = ef->buckets[hash % ef->nbuckets];
99138032Speter
99238032Speter    while (symnum != STN_UNDEF) {
99338032Speter	if (symnum >= ef->nchains) {
99438032Speter	    printf("link_elf_lookup_symbol: corrupt symbol table\n");
99538032Speter	    return ENOENT;
99638032Speter	}
99790795Sgshapiro
99890795Sgshapiro	symp = ef->symtab + symnum;
99938032Speter	if (symp->st_name == 0) {
100038032Speter	    printf("link_elf_lookup_symbol: corrupt symbol table\n");
100138032Speter	    return ENOENT;
100238032Speter	}
100390795Sgshapiro
100438032Speter	strp = ef->strtab + symp->st_name;
100538032Speter
100638032Speter	if (strcmp(name, strp) == 0) {
100738032Speter	    if (symp->st_shndx != SHN_UNDEF ||
100838032Speter		(symp->st_value != 0 &&
100938032Speter		 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
101038032Speter		*sym = (c_linker_sym_t) symp;
101138032Speter		return 0;
101238032Speter	    } else
101338032Speter		return ENOENT;
101438032Speter	}
101538032Speter
101638032Speter	symnum = ef->chains[symnum];
101738032Speter    }
101838032Speter
101938032Speter    /* If we have not found it, look at the full table (if loaded) */
102064565Sgshapiro    if (ef->symtab == ef->ddbsymtab)
102138032Speter	return ENOENT;
102238032Speter
102338032Speter    /* Exhaustive search */
102438032Speter    for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
102590795Sgshapiro	strp = ef->ddbstrtab + symp->st_name;
102638032Speter	if (strcmp(name, strp) == 0) {
102738032Speter	    if (symp->st_shndx != SHN_UNDEF ||
102838032Speter		(symp->st_value != 0 &&
102938032Speter		 ELF_ST_TYPE(symp->st_info) == STT_FUNC)) {
103038032Speter		*sym = (c_linker_sym_t) symp;
103138032Speter		return 0;
103238032Speter	    } else
103390795Sgshapiro		return ENOENT;
103490795Sgshapiro	}
103538032Speter    }
103638032Speter
103738032Speter    return ENOENT;
103838032Speter}
103990795Sgshapiro
104038032Speterstatic int
104138032Speterlink_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, linker_symval_t* symval)
104238032Speter{
104390795Sgshapiro	elf_file_t ef = (elf_file_t) lf;
104438032Speter	const Elf_Sym* es = (const Elf_Sym*) sym;
104590795Sgshapiro
104690795Sgshapiro	if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) {
104764565Sgshapiro	    symval->name = ef->strtab + es->st_name;
104838032Speter	    symval->value = (caddr_t) ef->address + es->st_value;
104990795Sgshapiro	    symval->size = es->st_size;
105090795Sgshapiro	    return 0;
105190795Sgshapiro	}
105290795Sgshapiro	if (ef->symtab == ef->ddbsymtab)
105390795Sgshapiro	    return ENOENT;
105490795Sgshapiro	if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
105590795Sgshapiro	    symval->name = ef->ddbstrtab + es->st_name;
105638032Speter	    symval->value = (caddr_t) ef->address + es->st_value;
105790795Sgshapiro	    symval->size = es->st_size;
105890795Sgshapiro	    return 0;
105990795Sgshapiro	}
106038032Speter	return ENOENT;
106190795Sgshapiro}
106290795Sgshapiro
106390795Sgshapirostatic int
106490795Sgshapirolink_elf_search_symbol(linker_file_t lf, caddr_t value,
106590795Sgshapiro		       c_linker_sym_t* sym, long* diffp)
106690795Sgshapiro{
106738032Speter	elf_file_t ef = (elf_file_t) lf;
106890795Sgshapiro	u_long off = (uintptr_t) (void *) value;
106938032Speter	u_long diff = off;
107064565Sgshapiro	u_long st_value;
107138032Speter	const Elf_Sym* es;
107238032Speter	const Elf_Sym* best = 0;
107390795Sgshapiro	int i;
107438032Speter
107538032Speter	for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) {
107638032Speter		if (es->st_name == 0)
107738032Speter			continue;
107838032Speter		st_value = es->st_value + (uintptr_t) (void *) ef->address;
107938032Speter		if (off >= st_value) {
108038032Speter			if (off - st_value < diff) {
108138032Speter				diff = off - st_value;
108238032Speter				best = es;
108338032Speter				if (diff == 0)
108438032Speter					break;
108538032Speter			} else if (off - st_value == diff) {
108638032Speter				best = es;
108738032Speter			}
108838032Speter		}
108938032Speter	}
109038032Speter	if (best == 0)
109138032Speter		*diffp = off;
109238032Speter	else
109338032Speter		*diffp = diff;
109438032Speter	*sym = (c_linker_sym_t) best;
109564565Sgshapiro
109638032Speter	return 0;
109738032Speter}
109838032Speter
109938032Speter/*
1100141862Sgshapiro * Look up a linker set on an ELF system.
110138032Speter */
110238032Speterstatic int
110338032Speterlink_elf_lookup_set(linker_file_t lf, const char *name,
110438032Speter		    void ***startp, void ***stopp, int *countp)
110538032Speter{
110638032Speter	c_linker_sym_t sym;
110738032Speter	linker_symval_t symval;
110838032Speter	char *setsym;
110938032Speter	void **start, **stop;
111038032Speter	int len, error = 0, count;
111138032Speter
111238032Speter	len = strlen(name) + sizeof("__start_set_"); /* sizeof includes \0 */
111390795Sgshapiro	setsym = malloc(len, M_LINKER, M_WAITOK);
111438032Speter	if (setsym == NULL)
111538032Speter		return ENOMEM;
111638032Speter
111738032Speter	/* get address of first entry */
111838032Speter	snprintf(setsym, len, "%s%s", "__start_set_", name);
111990795Sgshapiro	error = link_elf_lookup_symbol(lf, setsym, &sym);
112090795Sgshapiro	if (error)
112138032Speter		goto out;
112238032Speter	link_elf_symbol_values(lf, sym, &symval);
112338032Speter	if (symval.value == 0) {
112438032Speter		error = ESRCH;
112590795Sgshapiro		goto out;
112690795Sgshapiro	}
112790795Sgshapiro	start = (void **)symval.value;
112838032Speter
112998125Sgshapiro	/* get address of last entry */
113038032Speter	snprintf(setsym, len, "%s%s", "__stop_set_", name);
113138032Speter	error = link_elf_lookup_symbol(lf, setsym, &sym);
113238032Speter	if (error)
113338032Speter		goto out;
113490795Sgshapiro	link_elf_symbol_values(lf, sym, &symval);
113590795Sgshapiro	if (symval.value == 0) {
113638032Speter		error = ESRCH;
113738032Speter		goto out;
113890795Sgshapiro	}
113990795Sgshapiro	stop = (void **)symval.value;
114038032Speter
114138032Speter	/* and the number of entries */
114290795Sgshapiro	count = stop - start;
114338032Speter
114438032Speter	/* and copy out */
114538032Speter	if (startp)
114638032Speter		*startp = start;
114738032Speter	if (stopp)
114838032Speter		*stopp = stop;
114964565Sgshapiro	if (countp)
115064565Sgshapiro		*countp = count;
115164565Sgshapiro
115264565Sgshapiroout:
115364565Sgshapiro	free(setsym, M_LINKER);
115464565Sgshapiro	return error;
115590795Sgshapiro}
115664565Sgshapiro
115738032Speterstatic int
115890795Sgshapirolink_elf_each_function_name(linker_file_t file,
115964565Sgshapiro  int (*callback)(const char *, void *), void *opaque) {
116064565Sgshapiro    elf_file_t ef = (elf_file_t)file;
116164565Sgshapiro    const Elf_Sym* symp;
116264565Sgshapiro    int i, error;
116338032Speter
116490795Sgshapiro    /* Exhaustive search */
116564565Sgshapiro    for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
116664565Sgshapiro	if (symp->st_value != 0 &&
116738032Speter	    ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
116877352Sgshapiro		error = callback(ef->ddbstrtab + symp->st_name, opaque);
116977352Sgshapiro		if (error)
117064565Sgshapiro		    return (error);
117164565Sgshapiro	}
117264565Sgshapiro    }
117364565Sgshapiro    return (0);
117490795Sgshapiro}
117564565Sgshapiro
117664565Sgshapiro#ifdef __ia64__
117790795Sgshapiro/*
117864565Sgshapiro * Each KLD has its own GP. The GP value for each load module is given by
117938032Speter * DT_PLTGOT on ia64. We need GP to construct function descriptors, but
118038032Speter * don't have direct access to the ELF file structure. The link_elf_get_gp()
118190795Sgshapiro * function returns the GP given a pointer to a generic linker file struct.
118238032Speter */
118338032SpeterElf_Addr
118438032Speterlink_elf_get_gp(linker_file_t lf)
118538032Speter{
118638032Speter	elf_file_t ef = (elf_file_t)lf;
118790795Sgshapiro	return (Elf_Addr)ef->got;
118864565Sgshapiro}
118938032Speter#endif
119064565Sgshapiro
119190795Sgshapiro/*
119264565Sgshapiro * Symbol lookup function that can be used when the symbol index is known (ie
119364565Sgshapiro * in relocations). It uses the symbol index instead of doing a fully fledged
119438032Speter * hash table based lookup when such is valid. For example for local symbols.
119538032Speter * This is not only more efficient, it's also more correct. It's not always
119664565Sgshapiro * the case that the symbol can be found through the hash table.
119764565Sgshapiro */
119864565SgshapiroElf_Addr
119964565Sgshapiroelf_lookup(linker_file_t lf, Elf_Word symidx, int deps)
120064565Sgshapiro{
120164565Sgshapiro	elf_file_t ef = (elf_file_t)lf;
120238032Speter	const Elf_Sym *sym;
120338032Speter	const char *symbol;
120438032Speter
120538032Speter	/* Don't even try to lookup the symbol if the index is bogus. */
120638032Speter	if (symidx >= ef->nchains)
120738032Speter		return (0);
120838032Speter
120938032Speter	sym = ef->symtab + symidx;
121064565Sgshapiro
121138032Speter	/*
121238032Speter	 * Don't do a full lookup when the symbol is local. It may even
121338032Speter	 * fail because it may not be found through the hash table.
121438032Speter	 */
121538032Speter	if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
121638032Speter		/* Force lookup failure when we have an insanity. */
121738032Speter		if (sym->st_shndx == SHN_UNDEF || sym->st_value == 0)
121838032Speter			return (0);
121938032Speter		return ((Elf_Addr)ef->address + sym->st_value);
122038032Speter	}
1221120259Sgshapiro
122238032Speter	/*
122338032Speter	 * XXX we can avoid doing a hash table based lookup for global
122438032Speter	 * symbols as well. This however is not always valid, so we'll
122538032Speter	 * just do it the hard way for now. Performance tweaks can
122638032Speter	 * always be added.
122738032Speter	 */
122838032Speter
122938032Speter	symbol = ef->strtab + sym->st_name;
123038032Speter
1231120259Sgshapiro	/* Force a lookup failure if the symbol name is bogus. */
123238032Speter	if (*symbol == 0)
123338032Speter		return (0);
123438032Speter
123538032Speter	return ((Elf_Addr)linker_file_lookup_symbol(lf, symbol, deps));
123642580Speter}
123742580Speter