xref: /freebsd/sys/kern/link_elf_obj.c (revision a4f6773848c30617a2008ede091dc8d499967e10)
1a4f67738SDoug Rabson /*-
2a4f67738SDoug Rabson  * Copyright (c) 1998 Doug Rabson
3a4f67738SDoug Rabson  * All rights reserved.
4a4f67738SDoug Rabson  *
5a4f67738SDoug Rabson  * Redistribution and use in source and binary forms, with or without
6a4f67738SDoug Rabson  * modification, are permitted provided that the following conditions
7a4f67738SDoug Rabson  * are met:
8a4f67738SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
9a4f67738SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
10a4f67738SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
11a4f67738SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
12a4f67738SDoug Rabson  *    documentation and/or other materials provided with the distribution.
13a4f67738SDoug Rabson  *
14a4f67738SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a4f67738SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a4f67738SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a4f67738SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a4f67738SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a4f67738SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a4f67738SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a4f67738SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a4f67738SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a4f67738SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a4f67738SDoug Rabson  * SUCH DAMAGE.
25a4f67738SDoug Rabson  *
26a4f67738SDoug Rabson  *	$Id$
27a4f67738SDoug Rabson  */
28a4f67738SDoug Rabson 
29a4f67738SDoug Rabson #include <sys/param.h>
30a4f67738SDoug Rabson #include <sys/kernel.h>
31a4f67738SDoug Rabson #include <sys/systm.h>
32a4f67738SDoug Rabson #include <sys/malloc.h>
33a4f67738SDoug Rabson #include <sys/proc.h>
34a4f67738SDoug Rabson #include <sys/namei.h>
35a4f67738SDoug Rabson #include <sys/fcntl.h>
36a4f67738SDoug Rabson #include <sys/vnode.h>
37a4f67738SDoug Rabson #include <sys/linker.h>
38a4f67738SDoug Rabson #include <machine/elf.h>
39a4f67738SDoug Rabson 
40a4f67738SDoug Rabson static int	link_elf_load_file(const char*, linker_file_t*);
41a4f67738SDoug Rabson static int	link_elf_lookup_symbol(linker_file_t, const char*,
42a4f67738SDoug Rabson 				       linker_sym_t*);
43a4f67738SDoug Rabson static void	link_elf_symbol_values(linker_file_t, linker_sym_t, linker_symval_t*);
44a4f67738SDoug Rabson static int	link_elf_search_symbol(linker_file_t, caddr_t value,
45a4f67738SDoug Rabson 				       linker_sym_t* sym, long* diffp);
46a4f67738SDoug Rabson 
47a4f67738SDoug Rabson static void	link_elf_unload(linker_file_t);
48a4f67738SDoug Rabson 
49a4f67738SDoug Rabson /*
50a4f67738SDoug Rabson  * The file representing the currently running kernel.  This contains
51a4f67738SDoug Rabson  * the global symbol table.
52a4f67738SDoug Rabson  */
53a4f67738SDoug Rabson 
54a4f67738SDoug Rabson linker_file_t linker_kernel_file;
55a4f67738SDoug Rabson 
56a4f67738SDoug Rabson static struct linker_class_ops link_elf_class_ops = {
57a4f67738SDoug Rabson     link_elf_load_file,
58a4f67738SDoug Rabson };
59a4f67738SDoug Rabson 
60a4f67738SDoug Rabson static struct linker_file_ops link_elf_file_ops = {
61a4f67738SDoug Rabson     link_elf_lookup_symbol,
62a4f67738SDoug Rabson     link_elf_symbol_values,
63a4f67738SDoug Rabson     link_elf_search_symbol,
64a4f67738SDoug Rabson     link_elf_unload,
65a4f67738SDoug Rabson };
66a4f67738SDoug Rabson 
67a4f67738SDoug Rabson typedef struct elf_file {
68a4f67738SDoug Rabson     caddr_t		address;	/* Load address */
69a4f67738SDoug Rabson     Elf_Dyn*		dynamic;	/* Symbol table etc. */
70a4f67738SDoug Rabson     Elf_Off		nbuckets;	/* DT_HASH info */
71a4f67738SDoug Rabson     Elf_Off		nchains;
72a4f67738SDoug Rabson     const Elf_Off*	buckets;
73a4f67738SDoug Rabson     const Elf_Off*	chains;
74a4f67738SDoug Rabson     caddr_t		hash;
75a4f67738SDoug Rabson     caddr_t		strtab;		/* DT_STRTAB */
76a4f67738SDoug Rabson     Elf_Sym*		symtab;		/* DT_SYMTAB */
77a4f67738SDoug Rabson } *elf_file_t;
78a4f67738SDoug Rabson 
79a4f67738SDoug Rabson static int		parse_dynamic(linker_file_t lf);
80a4f67738SDoug Rabson static int		load_dependancies(linker_file_t lf);
81a4f67738SDoug Rabson static int		relocate_file(linker_file_t lf);
82a4f67738SDoug Rabson 
83a4f67738SDoug Rabson /*
84a4f67738SDoug Rabson  * The kernel symbol table starts here.
85a4f67738SDoug Rabson  */
86a4f67738SDoug Rabson extern struct _dynamic _DYNAMIC;
87a4f67738SDoug Rabson 
88a4f67738SDoug Rabson static void
89a4f67738SDoug Rabson link_elf_init(void* arg)
90a4f67738SDoug Rabson {
91a4f67738SDoug Rabson     Elf_Dyn* dp = (Elf_Dyn*) &_DYNAMIC;
92a4f67738SDoug Rabson 
93a4f67738SDoug Rabson #if ELF_TARG_CLASS == ELFCLASS32
94a4f67738SDoug Rabson     linker_add_class("elf32", NULL, &link_elf_class_ops);
95a4f67738SDoug Rabson #else
96a4f67738SDoug Rabson     linker_add_class("elf64", NULL, &link_elf_class_ops);
97a4f67738SDoug Rabson #endif
98a4f67738SDoug Rabson 
99a4f67738SDoug Rabson     if (dp) {
100a4f67738SDoug Rabson 	elf_file_t ef;
101a4f67738SDoug Rabson 
102a4f67738SDoug Rabson 	ef = malloc(sizeof(struct elf_file), M_LINKER, M_NOWAIT);
103a4f67738SDoug Rabson 	if (ef == NULL)
104a4f67738SDoug Rabson 	    panic("link_elf_init: Can't create linker structures for kernel");
105a4f67738SDoug Rabson 
106a4f67738SDoug Rabson 	ef->address = 0;
107a4f67738SDoug Rabson 	ef->dynamic = dp;
108a4f67738SDoug Rabson 	linker_kernel_file =
109a4f67738SDoug Rabson 	    linker_make_file(kernelname, ef, &link_elf_file_ops);
110a4f67738SDoug Rabson 	if (linker_kernel_file == NULL)
111a4f67738SDoug Rabson 	    panic("link_elf_init: Can't create linker structures for kernel");
112a4f67738SDoug Rabson 	parse_dynamic(linker_kernel_file);
113a4f67738SDoug Rabson 	/*
114a4f67738SDoug Rabson 	 * XXX there must be a better way of getting these constants.
115a4f67738SDoug Rabson 	 */
116a4f67738SDoug Rabson #ifdef __alpha__
117a4f67738SDoug Rabson 	linker_kernel_file->address = (caddr_t) 0xfffffc0000300000;
118a4f67738SDoug Rabson #else
119a4f67738SDoug Rabson 	linker_kernel_file->address = (caddr_t) 0xf0100000;
120a4f67738SDoug Rabson #endif
121a4f67738SDoug Rabson 	linker_kernel_file->size = -(long)linker_kernel_file->address;
122a4f67738SDoug Rabson 	linker_current_file = linker_kernel_file;
123a4f67738SDoug Rabson     }
124a4f67738SDoug Rabson }
125a4f67738SDoug Rabson 
126a4f67738SDoug Rabson SYSINIT(link_elf, SI_SUB_KMEM, SI_ORDER_THIRD, link_elf_init, 0);
127a4f67738SDoug Rabson 
128a4f67738SDoug Rabson static int
129a4f67738SDoug Rabson parse_dynamic(linker_file_t lf)
130a4f67738SDoug Rabson {
131a4f67738SDoug Rabson     elf_file_t ef = lf->priv;
132a4f67738SDoug Rabson     Elf_Dyn *dp;
133a4f67738SDoug Rabson 
134a4f67738SDoug Rabson     for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
135a4f67738SDoug Rabson 	switch (dp->d_tag) {
136a4f67738SDoug Rabson 	case DT_HASH:
137a4f67738SDoug Rabson 	{
138a4f67738SDoug Rabson 	    /* From src/libexec/rtld-elf/rtld.c */
139a4f67738SDoug Rabson 	    const Elf_Off *hashtab = (const Elf_Off *)
140a4f67738SDoug Rabson 		(ef->address + dp->d_un.d_ptr);
141a4f67738SDoug Rabson 	    ef->nbuckets = hashtab[0];
142a4f67738SDoug Rabson 	    ef->nchains = hashtab[1];
143a4f67738SDoug Rabson 	    ef->buckets = hashtab + 2;
144a4f67738SDoug Rabson 	    ef->chains = ef->buckets + ef->nbuckets;
145a4f67738SDoug Rabson 	    break;
146a4f67738SDoug Rabson 	}
147a4f67738SDoug Rabson 	case DT_STRTAB:
148a4f67738SDoug Rabson 	    ef->strtab = (caddr_t) dp->d_un.d_ptr;
149a4f67738SDoug Rabson 	    break;
150a4f67738SDoug Rabson 	case DT_SYMTAB:
151a4f67738SDoug Rabson 	    ef->symtab = (Elf_Sym*) dp->d_un.d_ptr;
152a4f67738SDoug Rabson 	    break;
153a4f67738SDoug Rabson 	case DT_SYMENT:
154a4f67738SDoug Rabson 	    if (dp->d_un.d_val != sizeof(Elf_Sym))
155a4f67738SDoug Rabson 		return ENOEXEC;
156a4f67738SDoug Rabson 	}
157a4f67738SDoug Rabson     }
158a4f67738SDoug Rabson     return 0;
159a4f67738SDoug Rabson }
160a4f67738SDoug Rabson 
161a4f67738SDoug Rabson static int
162a4f67738SDoug Rabson link_elf_load_file(const char* filename, linker_file_t* result)
163a4f67738SDoug Rabson {
164a4f67738SDoug Rabson #if 0
165a4f67738SDoug Rabson     struct nameidata nd;
166a4f67738SDoug Rabson     struct proc* p = curproc;	/* XXX */
167a4f67738SDoug Rabson     int error = 0;
168a4f67738SDoug Rabson     int resid;
169a4f67738SDoug Rabson     struct exec header;
170a4f67738SDoug Rabson     elf_file_t ef;
171a4f67738SDoug Rabson     linker_file_t lf;
172a4f67738SDoug Rabson 
173a4f67738SDoug Rabson     NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p);
174a4f67738SDoug Rabson     error = vn_open(&nd, FREAD, 0);
175a4f67738SDoug Rabson     if (error)
176a4f67738SDoug Rabson 	return error;
177a4f67738SDoug Rabson 
178a4f67738SDoug Rabson     /*
179a4f67738SDoug Rabson      * Read the a.out header from the file.
180a4f67738SDoug Rabson      */
181a4f67738SDoug Rabson     error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &header, sizeof header, 0,
182a4f67738SDoug Rabson 		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
183a4f67738SDoug Rabson     if (error)
184a4f67738SDoug Rabson 	goto out;
185a4f67738SDoug Rabson 
186a4f67738SDoug Rabson     if (N_BADMAG(header) || !(N_GETFLAG(header) & EX_DYNAMIC))
187a4f67738SDoug Rabson 	goto out;
188a4f67738SDoug Rabson 
189a4f67738SDoug Rabson     /*
190a4f67738SDoug Rabson      * We have an a.out file, so make some space to read it in.
191a4f67738SDoug Rabson      */
192a4f67738SDoug Rabson     ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK);
193a4f67738SDoug Rabson     ef->address = malloc(header.a_text + header.a_data + header.a_bss,
194a4f67738SDoug Rabson 			 M_LINKER, M_WAITOK);
195a4f67738SDoug Rabson 
196a4f67738SDoug Rabson     /*
197a4f67738SDoug Rabson      * Read the text and data sections and zero the bss.
198a4f67738SDoug Rabson      */
199a4f67738SDoug Rabson     error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) ef->address,
200a4f67738SDoug Rabson 		    header.a_text + header.a_data, 0,
201a4f67738SDoug Rabson 		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
202a4f67738SDoug Rabson     if (error)
203a4f67738SDoug Rabson 	goto out;
204a4f67738SDoug Rabson     bzero(ef->address + header.a_text + header.a_data, header.a_bss);
205a4f67738SDoug Rabson 
206a4f67738SDoug Rabson     /*
207a4f67738SDoug Rabson      * Assume _DYNAMIC is the first data item.
208a4f67738SDoug Rabson      */
209a4f67738SDoug Rabson     ef->dynamic = (struct _dynamic*) (ef->address + header.a_text);
210a4f67738SDoug Rabson     if (ef->dynamic->d_version != LD_VERSION_BSD) {
211a4f67738SDoug Rabson 	free(ef->address, M_LINKER);
212a4f67738SDoug Rabson 	free(ef, M_LINKER);
213a4f67738SDoug Rabson 	goto out;
214a4f67738SDoug Rabson     }
215a4f67738SDoug Rabson     (long) ef->dynamic->d_un.d_sdt += ef->address;
216a4f67738SDoug Rabson 
217a4f67738SDoug Rabson     lf = linker_make_file(filename, ef, &link_elf_file_ops);
218a4f67738SDoug Rabson     if (lf == NULL) {
219a4f67738SDoug Rabson 	free(ef->address, M_LINKER);
220a4f67738SDoug Rabson 	free(ef, M_LINKER);
221a4f67738SDoug Rabson 	error = ENOMEM;
222a4f67738SDoug Rabson 	goto out;
223a4f67738SDoug Rabson     }
224a4f67738SDoug Rabson     lf->address = ef->address;
225a4f67738SDoug Rabson     lf->size = header.a_text + header.a_data + header.a_bss;
226a4f67738SDoug Rabson 
227a4f67738SDoug Rabson     if ((error = load_dependancies(lf)) != 0
228a4f67738SDoug Rabson 	|| (error = relocate_file(lf)) != 0) {
229a4f67738SDoug Rabson 	linker_file_unload(lf);
230a4f67738SDoug Rabson 	goto out;
231a4f67738SDoug Rabson     }
232a4f67738SDoug Rabson 
233a4f67738SDoug Rabson     *result = lf;
234a4f67738SDoug Rabson 
235a4f67738SDoug Rabson out:
236a4f67738SDoug Rabson     VOP_UNLOCK(nd.ni_vp, 0, p);
237a4f67738SDoug Rabson     vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
238a4f67738SDoug Rabson 
239a4f67738SDoug Rabson     return error;
240a4f67738SDoug Rabson #else
241a4f67738SDoug Rabson     return ENOEXEC;
242a4f67738SDoug Rabson #endif
243a4f67738SDoug Rabson }
244a4f67738SDoug Rabson 
245a4f67738SDoug Rabson static void
246a4f67738SDoug Rabson link_elf_unload(linker_file_t file)
247a4f67738SDoug Rabson {
248a4f67738SDoug Rabson     elf_file_t ef = file->priv;
249a4f67738SDoug Rabson 
250a4f67738SDoug Rabson     if (ef) {
251a4f67738SDoug Rabson 	if (ef->address)
252a4f67738SDoug Rabson 	    free(ef->address, M_LINKER);
253a4f67738SDoug Rabson 	free(ef, M_LINKER);
254a4f67738SDoug Rabson     }
255a4f67738SDoug Rabson }
256a4f67738SDoug Rabson 
257a4f67738SDoug Rabson #define ELF_RELOC(ef, type, off) (type*) ((ef)->address + (off))
258a4f67738SDoug Rabson 
259a4f67738SDoug Rabson static int
260a4f67738SDoug Rabson load_dependancies(linker_file_t lf)
261a4f67738SDoug Rabson {
262a4f67738SDoug Rabson #if 0
263a4f67738SDoug Rabson     elf_file_t ef = lf->priv;
264a4f67738SDoug Rabson     linker_file_t lfdep;
265a4f67738SDoug Rabson     long off;
266a4f67738SDoug Rabson     struct sod* sodp;
267a4f67738SDoug Rabson     char* name;
268a4f67738SDoug Rabson     char* filename = 0;
269a4f67738SDoug Rabson     int error = 0;
270a4f67738SDoug Rabson 
271a4f67738SDoug Rabson     /*
272a4f67738SDoug Rabson      * All files are dependant on /kernel.
273a4f67738SDoug Rabson      */
274a4f67738SDoug Rabson     linker_kernel_file->refs++;
275a4f67738SDoug Rabson     linker_file_add_dependancy(lf, linker_kernel_file);
276a4f67738SDoug Rabson 
277a4f67738SDoug Rabson     off = LD_NEED(ef->dynamic);
278a4f67738SDoug Rabson 
279a4f67738SDoug Rabson     /*
280a4f67738SDoug Rabson      * Load the dependancies.
281a4f67738SDoug Rabson      */
282a4f67738SDoug Rabson     while (off != 0) {
283a4f67738SDoug Rabson 	sodp = ELF_RELOC(ef, struct sod, off);
284a4f67738SDoug Rabson 	name = ELF_RELOC(ef, char, sodp->sod_name);
285a4f67738SDoug Rabson 
286a4f67738SDoug Rabson 	/*
287a4f67738SDoug Rabson 	 * Prepend pathname if dep is not an absolute filename.
288a4f67738SDoug Rabson 	 */
289a4f67738SDoug Rabson 	if (name[0] != '/') {
290a4f67738SDoug Rabson 	    char* p;
291a4f67738SDoug Rabson 	    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
292a4f67738SDoug Rabson 	    p = lf->filename + strlen(lf->filename) - 1;
293a4f67738SDoug Rabson 	    while (p >= lf->filename && *p != '/')
294a4f67738SDoug Rabson 		p--;
295a4f67738SDoug Rabson 	    if (p >= lf->filename) {
296a4f67738SDoug Rabson 		strncpy(filename, lf->filename, p - lf->filename);
297a4f67738SDoug Rabson 		filename[p - lf->filename] = '\0';
298a4f67738SDoug Rabson 		strcat(filename, "/");
299a4f67738SDoug Rabson 		strcat(filename, name);
300a4f67738SDoug Rabson 		name = filename;
301a4f67738SDoug Rabson 	    }
302a4f67738SDoug Rabson 	}
303a4f67738SDoug Rabson 	error = linker_load_file(name, &lfdep);
304a4f67738SDoug Rabson 	if (error)
305a4f67738SDoug Rabson 	    goto out;
306a4f67738SDoug Rabson 	error = linker_file_add_dependancy(lf, lfdep);
307a4f67738SDoug Rabson 	if (error)
308a4f67738SDoug Rabson 	    goto out;
309a4f67738SDoug Rabson 	off = sodp->sod_next;
310a4f67738SDoug Rabson     }
311a4f67738SDoug Rabson 
312a4f67738SDoug Rabson out:
313a4f67738SDoug Rabson     if (filename)
314a4f67738SDoug Rabson 	free(filename, M_TEMP);
315a4f67738SDoug Rabson     return error;
316a4f67738SDoug Rabson #else
317a4f67738SDoug Rabson     return ENOEXEC;
318a4f67738SDoug Rabson #endif
319a4f67738SDoug Rabson }
320a4f67738SDoug Rabson 
321a4f67738SDoug Rabson #if 0
322a4f67738SDoug Rabson /*
323a4f67738SDoug Rabson  * XXX i386 dependant.
324a4f67738SDoug Rabson  */
325a4f67738SDoug Rabson static long
326a4f67738SDoug Rabson read_relocation(struct relocation_info* r, char* addr)
327a4f67738SDoug Rabson {
328a4f67738SDoug Rabson     int length = r->r_length;
329a4f67738SDoug Rabson     if (length == 0)
330a4f67738SDoug Rabson 	return *(u_char*) addr;
331a4f67738SDoug Rabson     else if (length == 1)
332a4f67738SDoug Rabson 	return *(u_short*) addr;
333a4f67738SDoug Rabson     else if (length == 2)
334a4f67738SDoug Rabson 	return *(u_int*) addr;
335a4f67738SDoug Rabson     else
336a4f67738SDoug Rabson 	printf("link_elf: unsupported relocation size %d\n", r->r_length);
337a4f67738SDoug Rabson     return 0;
338a4f67738SDoug Rabson }
339a4f67738SDoug Rabson 
340a4f67738SDoug Rabson static void
341a4f67738SDoug Rabson write_relocation(struct relocation_info* r, char* addr, long value)
342a4f67738SDoug Rabson {
343a4f67738SDoug Rabson     int length = r->r_length;
344a4f67738SDoug Rabson     if (length == 0)
345a4f67738SDoug Rabson 	*(u_char*) addr = value;
346a4f67738SDoug Rabson     else if (length == 1)
347a4f67738SDoug Rabson 	*(u_short*) addr = value;
348a4f67738SDoug Rabson     else if (length == 2)
349a4f67738SDoug Rabson 	*(u_int*) addr = value;
350a4f67738SDoug Rabson     else
351a4f67738SDoug Rabson 	printf("link_elf: unsupported relocation size %d\n", r->r_length);
352a4f67738SDoug Rabson }
353a4f67738SDoug Rabson 
354a4f67738SDoug Rabson static int
355a4f67738SDoug Rabson relocate_file(linker_file_t lf)
356a4f67738SDoug Rabson {
357a4f67738SDoug Rabson     elf_file_t ef = lf->priv;
358a4f67738SDoug Rabson     struct relocation_info* rel;
359a4f67738SDoug Rabson     struct relocation_info* erel;
360a4f67738SDoug Rabson     struct relocation_info* r;
361a4f67738SDoug Rabson     struct nzlist* symbolbase;
362a4f67738SDoug Rabson     char* stringbase;
363a4f67738SDoug Rabson     struct nzlist* np;
364a4f67738SDoug Rabson     char* sym;
365a4f67738SDoug Rabson     long relocation;
366a4f67738SDoug Rabson 
367a4f67738SDoug Rabson     rel = ELF_RELOC(ef, struct relocation_info, LD_REL(ef->dynamic));
368a4f67738SDoug Rabson     erel = ELF_RELOC(ef, struct relocation_info,
369a4f67738SDoug Rabson 		      LD_REL(ef->dynamic) + LD_RELSZ(ef->dynamic));
370a4f67738SDoug Rabson     symbolbase = ELF_RELOC(ef, struct nzlist, LD_SYMBOL(ef->dynamic));
371a4f67738SDoug Rabson     stringbase = ELF_RELOC(ef, char, LD_STRINGS(ef->dynamic));
372a4f67738SDoug Rabson 
373a4f67738SDoug Rabson     for (r = rel; r < erel; r++) {
374a4f67738SDoug Rabson 	char* addr;
375a4f67738SDoug Rabson 
376a4f67738SDoug Rabson 	if (r->r_address == 0)
377a4f67738SDoug Rabson 	    break;
378a4f67738SDoug Rabson 
379a4f67738SDoug Rabson 	addr = ELF_RELOC(ef, char, r->r_address);
380a4f67738SDoug Rabson 	if (r->r_extern) {
381a4f67738SDoug Rabson 	    np = &symbolbase[r->r_symbolnum];
382a4f67738SDoug Rabson 	    sym = &stringbase[np->nz_strx];
383a4f67738SDoug Rabson 
384a4f67738SDoug Rabson 	    if (sym[0] != '_') {
385a4f67738SDoug Rabson 		printf("link_elf: bad symbol name %s\n", sym);
386a4f67738SDoug Rabson 		relocation = 0;
387a4f67738SDoug Rabson 	    } else
388a4f67738SDoug Rabson 		relocation = (long)
389a4f67738SDoug Rabson 		    linker_file_lookup_symbol(lf, sym + 1,
390a4f67738SDoug Rabson 					      np->nz_type != (N_SETV+N_EXT));
391a4f67738SDoug Rabson 	    if (!relocation) {
392a4f67738SDoug Rabson 		printf("link_elf: symbol %s not found\n", sym);
393a4f67738SDoug Rabson 		return ENOENT;
394a4f67738SDoug Rabson 	    }
395a4f67738SDoug Rabson 
396a4f67738SDoug Rabson 	    relocation += read_relocation(r, addr);
397a4f67738SDoug Rabson 
398a4f67738SDoug Rabson 	    if (r->r_jmptable) {
399a4f67738SDoug Rabson 		printf("link_elf: can't cope with jump table relocations\n");
400a4f67738SDoug Rabson 		continue;
401a4f67738SDoug Rabson 	    }
402a4f67738SDoug Rabson 
403a4f67738SDoug Rabson 	    if (r->r_pcrel)
404a4f67738SDoug Rabson 		relocation -= (long) ef->address;
405a4f67738SDoug Rabson 
406a4f67738SDoug Rabson 	    if (r->r_copy) {
407a4f67738SDoug Rabson 		printf("link_elf: can't cope with copy relocations\n");
408a4f67738SDoug Rabson 		continue;
409a4f67738SDoug Rabson 	    }
410a4f67738SDoug Rabson 
411a4f67738SDoug Rabson 	    write_relocation(r, addr, relocation);
412a4f67738SDoug Rabson 	} else {
413a4f67738SDoug Rabson 	    write_relocation(r, addr,
414a4f67738SDoug Rabson 			     (long)(read_relocation(r, addr) + ef->address));
415a4f67738SDoug Rabson 	}
416a4f67738SDoug Rabson 
417a4f67738SDoug Rabson     }
418a4f67738SDoug Rabson 
419a4f67738SDoug Rabson     return 0;
420a4f67738SDoug Rabson }
421a4f67738SDoug Rabson 
422a4f67738SDoug Rabson static long
423a4f67738SDoug Rabson symbol_hash_value(elf_file_t ef, const char* name)
424a4f67738SDoug Rabson {
425a4f67738SDoug Rabson     long hashval;
426a4f67738SDoug Rabson     const char* p;
427a4f67738SDoug Rabson 
428a4f67738SDoug Rabson     hashval = '_';		/* fake a starting '_' for C symbols */
429a4f67738SDoug Rabson     for (p = name; *p; p++)
430a4f67738SDoug Rabson 	hashval = (hashval << 1) + *p;
431a4f67738SDoug Rabson 
432a4f67738SDoug Rabson     return (hashval & 0x7fffffff) % LD_BUCKETS(ef->dynamic);
433a4f67738SDoug Rabson }
434a4f67738SDoug Rabson 
435a4f67738SDoug Rabson #endif
436a4f67738SDoug Rabson 
437a4f67738SDoug Rabson int
438a4f67738SDoug Rabson link_elf_lookup_symbol(linker_file_t lf, const char* name, linker_sym_t* sym)
439a4f67738SDoug Rabson {
440a4f67738SDoug Rabson 	elf_file_t ef = lf->priv;
441a4f67738SDoug Rabson 	int symcount = ef->nchains;
442a4f67738SDoug Rabson 	Elf_Sym* es;
443a4f67738SDoug Rabson 	int i;
444a4f67738SDoug Rabson 
445a4f67738SDoug Rabson 	/* XXX use hash table */
446a4f67738SDoug Rabson 	for (i = 0, es = ef->symtab; i < ef->nchains; i++, es++) {
447a4f67738SDoug Rabson 		if (es->st_name == 0)
448a4f67738SDoug Rabson 			continue;
449a4f67738SDoug Rabson 		if (!strcmp(ef->strtab + es->st_name, name)) {
450a4f67738SDoug Rabson 			*sym = (linker_sym_t) es;
451a4f67738SDoug Rabson 			return 0;
452a4f67738SDoug Rabson 		}
453a4f67738SDoug Rabson 	}
454a4f67738SDoug Rabson 
455a4f67738SDoug Rabson 	return ENOENT;
456a4f67738SDoug Rabson }
457a4f67738SDoug Rabson 
458a4f67738SDoug Rabson static void
459a4f67738SDoug Rabson link_elf_symbol_values(linker_file_t lf, linker_sym_t sym, linker_symval_t* symval)
460a4f67738SDoug Rabson {
461a4f67738SDoug Rabson 	elf_file_t ef = lf->priv;
462a4f67738SDoug Rabson 	Elf_Sym* es = (Elf_Sym*) sym;
463a4f67738SDoug Rabson 
464a4f67738SDoug Rabson 	symval->name = ef->strtab + es->st_name;
465a4f67738SDoug Rabson 	symval->value = (caddr_t) es->st_value;
466a4f67738SDoug Rabson 	symval->size = es->st_size;
467a4f67738SDoug Rabson }
468a4f67738SDoug Rabson 
469a4f67738SDoug Rabson static int
470a4f67738SDoug Rabson link_elf_search_symbol(linker_file_t lf, caddr_t value,
471a4f67738SDoug Rabson 		       linker_sym_t* sym, long* diffp)
472a4f67738SDoug Rabson {
473a4f67738SDoug Rabson 	elf_file_t ef = lf->priv;
474a4f67738SDoug Rabson 	u_long off = (u_long) value;
475a4f67738SDoug Rabson 	u_long diff = off;
476a4f67738SDoug Rabson 	int symcount = ef->nchains;
477a4f67738SDoug Rabson 	Elf_Sym* es;
478a4f67738SDoug Rabson 	Elf_Sym* best = 0;
479a4f67738SDoug Rabson 	int i;
480a4f67738SDoug Rabson 
481a4f67738SDoug Rabson 	for (i = 0, es = ef->symtab; i < ef->nchains; i++, es++) {
482a4f67738SDoug Rabson 		if (es->st_name == 0)
483a4f67738SDoug Rabson 			continue;
484a4f67738SDoug Rabson 		if (off >= es->st_value) {
485a4f67738SDoug Rabson 			if (off - es->st_value < diff) {
486a4f67738SDoug Rabson 				diff = off - es->st_value;
487a4f67738SDoug Rabson 				best = es;
488a4f67738SDoug Rabson 				if (diff == 0)
489a4f67738SDoug Rabson 					break;
490a4f67738SDoug Rabson 			} else if (off - es->st_value == diff) {
491a4f67738SDoug Rabson 				best = es;
492a4f67738SDoug Rabson 			}
493a4f67738SDoug Rabson 		}
494a4f67738SDoug Rabson 	}
495a4f67738SDoug Rabson 	if (best == 0)
496a4f67738SDoug Rabson 		*diffp = off;
497a4f67738SDoug Rabson 	else
498a4f67738SDoug Rabson 		*diffp = diff;
499a4f67738SDoug Rabson 	*sym = (linker_sym_t) best;
500a4f67738SDoug Rabson 
501a4f67738SDoug Rabson 	return 0;
502a4f67738SDoug Rabson }
503a4f67738SDoug Rabson 
504