2 * Copyright (c) 1997 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
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.13 2004/11/12 00:09:23 dillon Exp $
32 #define FREEBSD_AOUT 1
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
37 #include <sys/types.h>
38 #include <sys/malloc.h>
40 #include <sys/nlookup.h>
41 #include <sys/fcntl.h>
42 #include <sys/vnode.h>
43 #include <sys/linker.h>
45 #include <vm/vm_zone.h>
50 #include <machine/vmparam.h>
53 #include <machine/exec.h>
54 #include <sys/imgact_aout.h>
55 #include <machine/reloc.h>
56 #define _AOUT_INCLUDE_
57 #include <sys/nlist_aout.h>
58 #include <sys/link_aout.h>
60 static int link_aout_load_module(const char*, linker_file_t*);
62 static int link_aout_load_file(const char*, linker_file_t*);
64 static int link_aout_lookup_symbol(linker_file_t, const char*,
66 static int link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym,
67 linker_symval_t* symval);
68 static int link_aout_search_symbol(linker_file_t lf, caddr_t value,
69 c_linker_sym_t* sym, long* diffp);
70 static void link_aout_unload_file(linker_file_t);
71 static void link_aout_unload_module(linker_file_t);
72 static int link_aout_lookup_set(linker_file_t lf, const char *name,
73 void ***startp, void ***stopp, int *countp);
75 static struct linker_class_ops link_aout_class_ops = {
76 link_aout_load_module,
79 static struct linker_file_ops link_aout_file_ops = {
80 link_aout_lookup_symbol,
81 link_aout_symbol_values,
82 link_aout_search_symbol,
83 link_aout_unload_file,
86 static struct linker_file_ops link_aout_module_ops = {
87 link_aout_lookup_symbol,
88 link_aout_symbol_values,
89 link_aout_search_symbol,
90 link_aout_unload_module,
94 typedef struct aout_file {
95 char* address; /* Load address */
96 struct _dynamic* dynamic; /* Symbol table etc. */
99 static int load_dependancies(linker_file_t lf);
100 static int relocate_file(linker_file_t lf);
103 * The kernel symbol table starts here.
105 extern struct _dynamic _DYNAMIC;
108 link_aout_init(void* arg)
111 struct _dynamic* dp = &_DYNAMIC;
114 linker_add_class("a.out", NULL, &link_aout_class_ops);
120 af = malloc(sizeof(struct aout_file), M_LINKER, M_NOWAIT);
122 panic("link_aout_init: Can't create linker structures for kernel");
123 bzero(af, sizeof(*af));
128 linker_make_file(kernelname, af, &link_aout_file_ops);
129 if (linker_kernel_file == NULL)
130 panic("link_aout_init: Can't create linker structures for kernel");
131 linker_kernel_file->address = (caddr_t) KERNBASE;
132 linker_kernel_file->size = -(long)linker_kernel_file->address;
133 linker_current_file = linker_kernel_file;
134 linker_kernel_file->flags |= LINKER_FILE_LINKED;
139 SYSINIT(link_aout, SI_SUB_KLD, SI_ORDER_THIRD, link_aout_init, 0);
142 link_aout_load_module(const char* filename, linker_file_t* result)
144 caddr_t modptr, baseptr;
151 /* Look to see if we have the module preloaded. */
152 if ((modptr = preload_search_by_name(filename)) == NULL)
153 return(link_aout_load_file(filename, result));
155 /* It's preloaded, check we can handle it and collect information. */
156 if (((type = (char *)preload_search_info(modptr, MODINFO_TYPE)) == NULL) ||
157 strcmp(type, "a.out module") ||
158 ((baseptr = preload_search_info(modptr, MODINFO_ADDR)) == NULL) ||
159 ((ehdr = (struct exec *)preload_search_info(modptr, MODINFO_METADATA | MODINFOMD_AOUTEXEC)) == NULL))
160 return(0); /* we can't handle this */
162 /* Looks like we can handle this one */
163 af = malloc(sizeof(struct aout_file), M_LINKER, M_WAITOK);
164 bzero(af, sizeof(*af));
165 af->address = baseptr;
167 /* Assume _DYNAMIC is the first data item. */
168 af->dynamic = (struct _dynamic*)(af->address + ehdr->a_text);
169 if (af->dynamic->d_version != LD_VERSION_BSD) {
171 return(0); /* we can't handle this */
173 af->dynamic->d_un.d_sdt = (struct section_dispatch_table *)
174 ((char *)af->dynamic->d_un.d_sdt + (vm_offset_t)af->address);
176 /* Register with kld */
177 lf = linker_make_file(filename, af, &link_aout_module_ops);
182 lf->address = af->address;
183 lf->size = ehdr->a_text + ehdr->a_data + ehdr->a_bss;
185 /* Try to load dependancies */
186 if (((error = load_dependancies(lf)) != 0) ||
187 ((error = relocate_file(lf)) != 0)) {
188 linker_file_unload(lf);
191 lf->flags |= LINKER_FILE_LINKED;
197 link_aout_load_file(const char* filename, linker_file_t* result)
199 struct nlookupdata nd;
200 struct thread *td = curthread;
201 struct proc *p = td->td_proc;
212 if (p->p_ucred == NULL) {
213 printf("link_aout_load_file: cannot load '%s' from filesystem"
214 " this early\n", filename);
218 pathname = linker_search_path(filename);
219 if (pathname == NULL)
221 error = nlookup_init(&nd, pathname, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP);
223 error = vn_open(&nd, NULL, FREAD, 0);
224 free(pathname, M_LINKER);
230 nd.nl_open_vp = NULL;
234 * Read the a.out header from the file.
236 error = vn_rdwr(UIO_READ, vp, (void*) &header, sizeof header, 0,
237 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td);
241 if (N_BADMAG(header) || !(N_GETFLAG(header) & EX_DYNAMIC))
245 * We have an a.out file, so make some space to read it in.
247 af = malloc(sizeof(struct aout_file), M_LINKER, M_WAITOK);
248 bzero(af, sizeof(*af));
249 af->address = malloc(header.a_text + header.a_data + header.a_bss,
253 * Read the text and data sections and zero the bss.
255 VOP_LEASE(vp, td, p->p_ucred, LEASE_READ);
256 error = vn_rdwr(UIO_READ, vp, (void*) af->address,
257 header.a_text + header.a_data, 0,
258 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, td);
261 bzero(af->address + header.a_text + header.a_data, header.a_bss);
264 * Assume _DYNAMIC is the first data item.
266 af->dynamic = (struct _dynamic*) (af->address + header.a_text);
267 if (af->dynamic->d_version != LD_VERSION_BSD) {
268 free(af->address, M_LINKER);
272 af->dynamic->d_un.d_sdt = (struct section_dispatch_table *)
273 ((char *)af->dynamic->d_un.d_sdt + (vm_offset_t)af->address);
275 lf = linker_make_file(filename, af, &link_aout_file_ops);
277 free(af->address, M_LINKER);
282 lf->address = af->address;
283 lf->size = header.a_text + header.a_data + header.a_bss;
285 if ((error = load_dependancies(lf)) != 0
286 || (error = relocate_file(lf)) != 0) {
287 linker_file_unload(lf);
291 lf->flags |= LINKER_FILE_LINKED;
295 VOP_UNLOCK(vp, 0, td);
296 vn_close(vp, FREAD, td);
302 link_aout_unload_file(linker_file_t file)
304 aout_file_t af = file->priv;
308 free(af->address, M_LINKER);
314 link_aout_unload_module(linker_file_t file)
316 aout_file_t af = file->priv;
321 preload_delete_name(file->filename);
324 #define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off))
327 load_dependancies(linker_file_t lf)
329 aout_file_t af = lf->priv;
338 * All files are dependant on /kernel.
340 if (linker_kernel_file) {
341 linker_kernel_file->refs++;
342 linker_file_add_dependancy(lf, linker_kernel_file);
345 off = LD_NEED(af->dynamic);
348 * Load the dependancies.
351 sodp = AOUT_RELOC(af, struct sod, off);
352 name = AOUT_RELOC(af, char, sodp->sod_name);
354 error = linker_load_file(name, &lfdep);
357 error = linker_file_add_dependancy(lf, lfdep);
360 off = sodp->sod_next;
365 free(filename, M_TEMP);
370 * XXX i386 dependant.
373 read_relocation(struct relocation_info* r, char* addr)
375 int length = r->r_length;
377 return *(u_char*) addr;
378 else if (length == 1)
379 return *(u_short*) addr;
380 else if (length == 2)
381 return *(u_int*) addr;
383 printf("link_aout: unsupported relocation size %d\n", r->r_length);
388 write_relocation(struct relocation_info* r, char* addr, long value)
390 int length = r->r_length;
392 *(u_char*) addr = value;
393 else if (length == 1)
394 *(u_short*) addr = value;
395 else if (length == 2)
396 *(u_int*) addr = value;
398 printf("link_aout: unsupported relocation size %d\n", r->r_length);
402 relocate_file(linker_file_t lf)
404 aout_file_t af = lf->priv;
405 struct relocation_info* rel;
406 struct relocation_info* erel;
407 struct relocation_info* r;
408 struct nzlist* symbolbase;
414 rel = AOUT_RELOC(af, struct relocation_info, LD_REL(af->dynamic));
415 erel = AOUT_RELOC(af, struct relocation_info,
416 LD_REL(af->dynamic) + LD_RELSZ(af->dynamic));
417 symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
418 stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
420 for (r = rel; r < erel; r++) {
423 if (r->r_address == 0)
426 addr = AOUT_RELOC(af, char, r->r_address);
428 np = &symbolbase[r->r_symbolnum];
429 sym = &stringbase[np->nz_strx];
432 printf("link_aout: bad symbol name %s\n", sym);
433 printf("link_aout: symbol %s not found\n", sym);
436 if (linker_file_lookup_symbol(lf, sym + 1,
437 (np->nz_type != (N_SETV+N_EXT)), (caddr_t *)&relocation)) {
438 printf("link_aout: symbol %s not found\n", sym);
443 relocation += read_relocation(r, addr);
446 printf("link_aout: can't cope with jump table relocations\n");
451 relocation -= (intptr_t) af->address;
454 printf("link_aout: can't cope with copy relocations\n");
458 write_relocation(r, addr, relocation);
460 write_relocation(r, addr,
461 (intptr_t)(read_relocation(r, addr) + af->address));
470 symbol_hash_value(aout_file_t af, const char* name)
475 hashval = '_'; /* fake a starting '_' for C symbols */
476 for (p = name; *p; p++)
477 hashval = (hashval << 1) + *p;
479 return (hashval & 0x7fffffff) % LD_BUCKETS(af->dynamic);
483 link_aout_lookup_symbol(linker_file_t file, const char* name,
486 aout_file_t af = file->priv;
488 struct rrs_hash* hashbase;
489 struct nzlist* symbolbase;
495 if (LD_BUCKETS(af->dynamic) == 0)
498 hashbase = AOUT_RELOC(af, struct rrs_hash, LD_HASH(af->dynamic));
499 symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
500 stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
503 hashval = symbol_hash_value(af, name);
504 hp = &hashbase[hashval];
505 if (hp->rh_symbolnum == -1)
509 np = (struct nzlist *) &symbolbase[hp->rh_symbolnum];
510 cp = stringbase + np->nz_strx;
512 * Note: we fake the leading '_' for C symbols.
514 if (cp[0] == '_' && !strcmp(cp + 1, name))
517 if (hp->rh_next == 0)
520 hp = &hashbase[hp->rh_next];
530 * Check for an aliased symbol, whatever that is.
532 if (np->nz_type == N_INDR+N_EXT) {
533 name = stringbase + (++np)->nz_strx + 1; /* +1 for '_' */
538 * Check this is an actual definition of the symbol.
540 if (np->nz_value == 0)
543 if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
544 if (np->nz_other == AUX_FUNC)
549 *sym = (linker_sym_t) np;
556 link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym,
557 linker_symval_t* symval)
559 aout_file_t af = file->priv;
560 const struct nzlist* np = (const struct nzlist*) sym;
562 long numsym = LD_STABSZ(af->dynamic) / sizeof(struct nzlist);
563 struct nzlist *symbase;
565 /* Is it one of ours? It could be another module... */
566 symbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
569 if ((np - symbase) > numsym)
572 stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
574 symval->name = stringbase + np->nz_strx + 1; /* +1 for '_' */
575 if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
577 symval->size = np->nz_value;
579 symval->value = AOUT_RELOC(af, char, np->nz_value);
580 symval->size = np->nz_size;
586 link_aout_search_symbol(linker_file_t lf, caddr_t value,
587 c_linker_sym_t* sym, long* diffp)
589 aout_file_t af = lf->priv;
590 u_long off = (uintptr_t) (void *) value;
595 struct nzlist* best = 0;
597 for (sp = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic)),
598 ep = (struct nzlist *) ((caddr_t) sp + LD_STABSZ(af->dynamic));
600 if (sp->nz_name == 0)
602 sp_nz_value = sp->nz_value + (uintptr_t) (void *) af->address;
603 if (off >= sp_nz_value) {
604 if (off - sp_nz_value < diff) {
605 diff = off - sp_nz_value;
609 } else if (off - sp_nz_value == diff) {
618 *sym = (linker_sym_t) best;
624 * Look up a linker set on an a.out + gnu LD system.
627 struct generic_linker_set {
633 link_aout_lookup_set(linker_file_t lf, const char *name,
634 void ***startp, void ***stopp, int *countp)
637 linker_symval_t symval;
638 void **start, **stop;
640 struct generic_linker_set *setp;
642 error = link_aout_lookup_symbol(lf, name, &sym);
645 link_aout_symbol_values(lf, sym, &symval);
646 if (symval.value == 0)
648 setp = (struct generic_linker_set *)symval.value;
649 count = setp->ls_length;
650 start = &setp->ls_items[0];
651 stop = &setp->ls_items[count];
661 #endif /* !__alpha__ */