Remove unused variable.
[dragonfly/netmp.git] / sys / kern / link_aout.c
blobacbe7cc0d895496595c1615bf51009375fa970ea
1 /*-
2 * Copyright (c) 1997 Doug Rabson
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 * $FreeBSD: src/sys/kern/link_aout.c,v 1.26 1999/12/24 15:33:36 bde Exp $
27 * $DragonFly: src/sys/kern/link_aout.c,v 1.23 2008/01/05 14:02:38 swildner Exp $
30 #define FREEBSD_AOUT 1
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/types.h>
36 #include <sys/malloc.h>
37 #include <sys/proc.h>
38 #include <sys/nlookup.h>
39 #include <sys/fcntl.h>
40 #include <sys/vnode.h>
41 #include <sys/linker.h>
43 #include <vm/vm_zone.h>
45 #ifndef __ELF__
46 #include <vm/vm.h>
47 #include <vm/pmap.h>
48 #include <machine/vmparam.h>
49 #endif
51 #include <machine/exec.h>
52 #include <sys/imgact_aout.h>
53 #include <machine/reloc.h>
54 #define _AOUT_INCLUDE_
55 #include <sys/nlist_aout.h>
56 #include <sys/link_aout.h>
58 static int link_aout_load_module(const char*, linker_file_t*);
60 static int link_aout_load_file(const char*, linker_file_t*);
62 static int link_aout_lookup_symbol(linker_file_t, const char*,
63 c_linker_sym_t*);
64 static int link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym,
65 linker_symval_t* symval);
66 static int link_aout_search_symbol(linker_file_t lf, caddr_t value,
67 c_linker_sym_t* sym, long* diffp);
68 static void link_aout_unload_file(linker_file_t);
69 static void link_aout_unload_module(linker_file_t);
70 static int link_aout_lookup_set(linker_file_t lf, const char *name,
71 void ***startp, void ***stopp, int *countp);
73 static struct linker_class_ops link_aout_class_ops = {
74 link_aout_load_module,
77 static struct linker_file_ops link_aout_file_ops = {
78 link_aout_lookup_symbol,
79 link_aout_symbol_values,
80 link_aout_search_symbol,
81 link_aout_unload_file,
82 link_aout_lookup_set
84 static struct linker_file_ops link_aout_module_ops = {
85 link_aout_lookup_symbol,
86 link_aout_symbol_values,
87 link_aout_search_symbol,
88 link_aout_unload_module,
89 link_aout_lookup_set
92 typedef struct aout_file {
93 char* address; /* Load address */
94 struct _dynamic* dynamic; /* Symbol table etc. */
95 } *aout_file_t;
97 static int load_dependancies(linker_file_t lf);
98 static int relocate_file(linker_file_t lf);
101 * The kernel symbol table starts here.
103 extern struct _dynamic _DYNAMIC;
105 static void
106 link_aout_init(void* arg)
108 #ifndef __ELF__
109 struct _dynamic* dp = &_DYNAMIC;
110 #endif
112 linker_add_class("a.out", NULL, &link_aout_class_ops);
114 #ifndef __ELF__
115 if (dp) {
116 aout_file_t af;
118 af = kmalloc(sizeof(struct aout_file), M_LINKER, M_NOWAIT | M_ZERO);
119 if (af == NULL)
120 panic("link_aout_init: Can't create linker structures for kernel");
122 af->address = 0;
123 af->dynamic = dp;
124 linker_kernel_file =
125 linker_make_file(kernelname, af, &link_aout_file_ops);
126 if (linker_kernel_file == NULL)
127 panic("link_aout_init: Can't create linker structures for kernel");
128 linker_kernel_file->address = (caddr_t) KERNBASE;
129 linker_kernel_file->size = -(long)linker_kernel_file->address;
130 linker_current_file = linker_kernel_file;
131 linker_kernel_file->flags |= LINKER_FILE_LINKED;
133 #endif
136 SYSINIT(link_aout, SI_BOOT2_KLD, SI_ORDER_THIRD, link_aout_init, 0);
138 static int
139 link_aout_load_module(const char* filename, linker_file_t* result)
141 caddr_t modptr, baseptr;
142 char *type;
143 struct exec *ehdr;
144 aout_file_t af;
145 linker_file_t lf;
146 int error;
148 /* Look to see if we have the module preloaded. */
149 if ((modptr = preload_search_by_name(filename)) == NULL)
150 return(link_aout_load_file(filename, result));
152 /* It's preloaded, check we can handle it and collect information. */
153 if (((type = (char *)preload_search_info(modptr, MODINFO_TYPE)) == NULL) ||
154 strcmp(type, "a.out module") ||
155 ((baseptr = preload_search_info(modptr, MODINFO_ADDR)) == NULL) ||
156 ((ehdr = (struct exec *)preload_search_info(modptr, MODINFO_METADATA | MODINFOMD_AOUTEXEC)) == NULL))
157 return(0); /* we can't handle this */
159 /* Looks like we can handle this one */
160 af = kmalloc(sizeof(struct aout_file), M_LINKER, M_WAITOK | M_ZERO);
161 af->address = baseptr;
163 /* Assume _DYNAMIC is the first data item. */
164 af->dynamic = (struct _dynamic*)(af->address + ehdr->a_text);
165 if (af->dynamic->d_version != LD_VERSION_BSD) {
166 kfree(af, M_LINKER);
167 return(0); /* we can't handle this */
169 af->dynamic->d_un.d_sdt = (struct section_dispatch_table *)
170 ((char *)af->dynamic->d_un.d_sdt + (vm_offset_t)af->address);
172 /* Register with kld */
173 lf = linker_make_file(filename, af, &link_aout_module_ops);
174 if (lf == NULL) {
175 kfree(af, M_LINKER);
176 return(ENOMEM);
178 lf->address = af->address;
179 lf->size = ehdr->a_text + ehdr->a_data + ehdr->a_bss;
181 /* Try to load dependancies */
182 if (((error = load_dependancies(lf)) != 0) ||
183 ((error = relocate_file(lf)) != 0)) {
184 linker_file_unload(lf);
185 return(error);
187 lf->flags |= LINKER_FILE_LINKED;
188 *result = lf;
189 return(0);
192 static int
193 link_aout_load_file(const char* filename, linker_file_t* result)
195 struct nlookupdata nd;
196 struct thread *td = curthread;
197 struct proc *p = td->td_proc;
198 struct vnode *vp;
199 int error = 0;
200 int resid;
201 struct exec header;
202 aout_file_t af;
203 linker_file_t lf;
204 char *pathname;
206 KKASSERT(p != NULL);
208 if (p->p_ucred == NULL) {
209 kprintf("link_aout_load_file: cannot load '%s' from filesystem"
210 " this early\n", filename);
211 return ENOENT;
214 pathname = linker_search_path(filename);
215 if (pathname == NULL)
216 return ENOENT;
217 error = nlookup_init(&nd, pathname, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP);
218 if (error == 0)
219 error = vn_open(&nd, NULL, FREAD, 0);
220 kfree(pathname, M_LINKER);
221 if (error) {
222 nlookup_done(&nd);
223 return error;
225 vp = nd.nl_open_vp;
226 nd.nl_open_vp = NULL;
227 nlookup_done(&nd);
230 * Read the a.out header from the file.
232 error = vn_rdwr(UIO_READ, vp, (void*) &header, sizeof header, 0,
233 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid);
234 if (error)
235 goto out;
237 if (N_BADMAG(header) || !(N_GETFLAG(header) & EX_DYNAMIC))
238 goto out;
241 * We have an a.out file, so make some space to read it in.
243 af = kmalloc(sizeof(struct aout_file), M_LINKER, M_WAITOK | M_ZERO);
244 af->address = kmalloc(header.a_text + header.a_data + header.a_bss,
245 M_LINKER, M_WAITOK);
248 * Read the text and data sections and zero the bss.
250 error = vn_rdwr(UIO_READ, vp, (void*) af->address,
251 header.a_text + header.a_data, 0,
252 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid);
253 if (error)
254 goto out;
255 bzero(af->address + header.a_text + header.a_data, header.a_bss);
258 * Assume _DYNAMIC is the first data item.
260 af->dynamic = (struct _dynamic*) (af->address + header.a_text);
261 if (af->dynamic->d_version != LD_VERSION_BSD) {
262 kfree(af->address, M_LINKER);
263 kfree(af, M_LINKER);
264 goto out;
266 af->dynamic->d_un.d_sdt = (struct section_dispatch_table *)
267 ((char *)af->dynamic->d_un.d_sdt + (vm_offset_t)af->address);
269 lf = linker_make_file(filename, af, &link_aout_file_ops);
270 if (lf == NULL) {
271 kfree(af->address, M_LINKER);
272 kfree(af, M_LINKER);
273 error = ENOMEM;
274 goto out;
276 lf->address = af->address;
277 lf->size = header.a_text + header.a_data + header.a_bss;
279 if ((error = load_dependancies(lf)) != 0
280 || (error = relocate_file(lf)) != 0) {
281 linker_file_unload(lf);
282 goto out;
285 lf->flags |= LINKER_FILE_LINKED;
286 *result = lf;
288 out:
289 vn_unlock(vp);
290 vn_close(vp, FREAD);
292 return error;
295 static void
296 link_aout_unload_file(linker_file_t file)
298 aout_file_t af = file->priv;
300 if (af) {
301 if (af->address)
302 kfree(af->address, M_LINKER);
303 kfree(af, M_LINKER);
307 static void
308 link_aout_unload_module(linker_file_t file)
310 aout_file_t af = file->priv;
312 if (af)
313 kfree(af, M_LINKER);
314 if (file->filename)
315 preload_delete_name(file->filename);
318 #define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off))
320 static int
321 load_dependancies(linker_file_t lf)
323 aout_file_t af = lf->priv;
324 linker_file_t lfdep;
325 long off;
326 struct sod* sodp;
327 char* name;
328 char* filename = 0;
329 int error = 0;
332 * All files are dependant on /kernel.
334 if (linker_kernel_file) {
335 linker_kernel_file->refs++;
336 linker_file_add_dependancy(lf, linker_kernel_file);
339 off = LD_NEED(af->dynamic);
342 * Load the dependancies.
344 while (off != 0) {
345 sodp = AOUT_RELOC(af, struct sod, off);
346 name = AOUT_RELOC(af, char, sodp->sod_name);
348 error = linker_load_file(name, &lfdep);
349 if (error)
350 goto out;
351 error = linker_file_add_dependancy(lf, lfdep);
352 if (error)
353 goto out;
354 off = sodp->sod_next;
357 out:
358 if (filename)
359 kfree(filename, M_TEMP);
360 return error;
364 * XXX i386 dependant.
366 static long
367 read_relocation(struct relocation_info* r, char* addr)
369 int length = r->r_length;
370 if (length == 0)
371 return *(u_char*) addr;
372 else if (length == 1)
373 return *(u_short*) addr;
374 else if (length == 2)
375 return *(u_int*) addr;
376 else
377 kprintf("link_aout: unsupported relocation size %d\n", r->r_length);
378 return 0;
381 static void
382 write_relocation(struct relocation_info* r, char* addr, long value)
384 int length = r->r_length;
385 if (length == 0)
386 *(u_char*) addr = value;
387 else if (length == 1)
388 *(u_short*) addr = value;
389 else if (length == 2)
390 *(u_int*) addr = value;
391 else
392 kprintf("link_aout: unsupported relocation size %d\n", r->r_length);
395 static int
396 relocate_file(linker_file_t lf)
398 aout_file_t af = lf->priv;
399 struct relocation_info* rel;
400 struct relocation_info* erel;
401 struct relocation_info* r;
402 struct nzlist* symbolbase;
403 char* stringbase;
404 struct nzlist* np;
405 char* sym;
406 long relocation;
408 rel = AOUT_RELOC(af, struct relocation_info, LD_REL(af->dynamic));
409 erel = AOUT_RELOC(af, struct relocation_info,
410 LD_REL(af->dynamic) + LD_RELSZ(af->dynamic));
411 symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
412 stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
414 for (r = rel; r < erel; r++) {
415 char* addr;
417 if (r->r_address == 0)
418 break;
420 addr = AOUT_RELOC(af, char, r->r_address);
421 if (r->r_extern) {
422 np = &symbolbase[r->r_symbolnum];
423 sym = &stringbase[np->nz_strx];
425 if (sym[0] != '_') {
426 kprintf("link_aout: bad symbol name %s\n", sym);
427 kprintf("link_aout: symbol %s not found\n", sym);
428 return ENOENT;
429 } else {
430 if (linker_file_lookup_symbol(lf, sym + 1,
431 (np->nz_type != (N_SETV+N_EXT)), (caddr_t *)&relocation)) {
432 kprintf("link_aout: symbol %s not found\n", sym);
433 return ENOENT;
437 relocation += read_relocation(r, addr);
439 if (r->r_jmptable) {
440 kprintf("link_aout: can't cope with jump table relocations\n");
441 continue;
444 if (r->r_pcrel)
445 relocation -= (intptr_t) af->address;
447 if (r->r_copy) {
448 kprintf("link_aout: can't cope with copy relocations\n");
449 continue;
452 write_relocation(r, addr, relocation);
453 } else {
454 write_relocation(r, addr,
455 (intptr_t)(read_relocation(r, addr) + af->address));
460 return 0;
463 static long
464 symbol_hash_value(aout_file_t af, const char* name)
466 long hashval;
467 const char* p;
469 hashval = '_'; /* fake a starting '_' for C symbols */
470 for (p = name; *p; p++)
471 hashval = (hashval << 1) + *p;
473 return (hashval & 0x7fffffff) % LD_BUCKETS(af->dynamic);
477 link_aout_lookup_symbol(linker_file_t file, const char* name,
478 c_linker_sym_t* sym)
480 aout_file_t af = file->priv;
481 long hashval;
482 struct rrs_hash* hashbase;
483 struct nzlist* symbolbase;
484 char* stringbase;
485 struct rrs_hash* hp;
486 struct nzlist* np;
487 char* cp;
489 if (LD_BUCKETS(af->dynamic) == 0)
490 return 0;
492 hashbase = AOUT_RELOC(af, struct rrs_hash, LD_HASH(af->dynamic));
493 symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
494 stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
496 restart:
497 hashval = symbol_hash_value(af, name);
498 hp = &hashbase[hashval];
499 if (hp->rh_symbolnum == -1)
500 return ENOENT;
502 while (hp) {
503 np = (struct nzlist *) &symbolbase[hp->rh_symbolnum];
504 cp = stringbase + np->nz_strx;
506 * Note: we fake the leading '_' for C symbols.
508 if (cp[0] == '_' && !strcmp(cp + 1, name))
509 break;
511 if (hp->rh_next == 0)
512 hp = NULL;
513 else
514 hp = &hashbase[hp->rh_next];
517 if (hp == NULL)
519 * Not found.
521 return ENOENT;
524 * Check for an aliased symbol, whatever that is.
526 if (np->nz_type == N_INDR+N_EXT) {
527 name = stringbase + (++np)->nz_strx + 1; /* +1 for '_' */
528 goto restart;
532 * Check this is an actual definition of the symbol.
534 if (np->nz_value == 0)
535 return ENOENT;
537 if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
538 if (np->nz_other == AUX_FUNC)
539 /* weak function */
540 return ENOENT;
543 *sym = (linker_sym_t) np;
545 return 0;
549 static int
550 link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym,
551 linker_symval_t* symval)
553 aout_file_t af = file->priv;
554 const struct nzlist* np = (const struct nzlist*) sym;
555 char* stringbase;
556 long numsym = LD_STABSZ(af->dynamic) / sizeof(struct nzlist);
557 struct nzlist *symbase;
559 /* Is it one of ours? It could be another module... */
560 symbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
561 if (np < symbase)
562 return ENOENT;
563 if ((np - symbase) > numsym)
564 return ENOENT;
566 stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
568 symval->name = stringbase + np->nz_strx + 1; /* +1 for '_' */
569 if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
570 symval->value = 0;
571 symval->size = np->nz_value;
572 } else {
573 symval->value = AOUT_RELOC(af, char, np->nz_value);
574 symval->size = np->nz_size;
576 return 0;
579 static int
580 link_aout_search_symbol(linker_file_t lf, caddr_t value,
581 c_linker_sym_t* sym, long* diffp)
583 aout_file_t af = lf->priv;
584 u_long off = (uintptr_t) (void *) value;
585 u_long diff = off;
586 u_long sp_nz_value;
587 struct nzlist* sp;
588 struct nzlist* ep;
589 struct nzlist* best = 0;
591 for (sp = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic)),
592 ep = (struct nzlist *) ((caddr_t) sp + LD_STABSZ(af->dynamic));
593 sp < ep; sp++) {
594 if (sp->nz_name == 0)
595 continue;
596 sp_nz_value = sp->nz_value + (uintptr_t) (void *) af->address;
597 if (off >= sp_nz_value) {
598 if (off - sp_nz_value < diff) {
599 diff = off - sp_nz_value;
600 best = sp;
601 if (diff == 0)
602 break;
603 } else if (off - sp_nz_value == diff) {
604 best = sp;
608 if (best == 0)
609 *diffp = off;
610 else
611 *diffp = diff;
612 *sym = (linker_sym_t) best;
614 return 0;
618 * Look up a linker set on an a.out + gnu LD system.
621 struct generic_linker_set {
622 int ls_length;
623 void *ls_items[1];
626 static int
627 link_aout_lookup_set(linker_file_t lf, const char *name,
628 void ***startp, void ***stopp, int *countp)
630 c_linker_sym_t sym;
631 linker_symval_t symval;
632 void **start, **stop;
633 int error, count;
634 struct generic_linker_set *setp;
636 error = link_aout_lookup_symbol(lf, name, &sym);
637 if (error)
638 return error;
639 link_aout_symbol_values(lf, sym, &symval);
640 if (symval.value == 0)
641 return ESRCH;
642 setp = (struct generic_linker_set *)symval.value;
643 count = setp->ls_length;
644 start = &setp->ls_items[0];
645 stop = &setp->ls_items[count];
646 if (startp)
647 *startp = start;
648 if (stopp)
649 *stopp = stop;
650 if (countp)
651 *countp = count;
652 return 0;