summaryrefslogtreecommitdiffstats
path: root/sys/kern/link_aout.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/link_aout.c')
-rw-r--r--sys/kern/link_aout.c594
1 files changed, 0 insertions, 594 deletions
diff --git a/sys/kern/link_aout.c b/sys/kern/link_aout.c
deleted file mode 100644
index 44e4c28..0000000
--- a/sys/kern/link_aout.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/*-
- * Copyright (c) 1997-2000 Doug Rabson
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifdef __i386__
-
-#define FREEBSD_AOUT 1
-#define _AOUT_INCLUDE_ 1
-
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/systm.h>
-#include <sys/malloc.h>
-#include <sys/proc.h>
-#include <sys/namei.h>
-#include <sys/fcntl.h>
-#include <sys/imgact_aout.h>
-#include <sys/vnode.h>
-#include <sys/linker.h>
-#include <machine/reloc.h>
-
-#include "linker_if.h"
-
-#ifndef __ELF__
-#include <vm/vm.h>
-#include <vm/pmap.h>
-#include <machine/vmparam.h>
-#endif
-
-#include <sys/nlist_aout.h>
-#include <sys/link_aout.h>
-
-typedef struct aout_file {
- struct linker_file lf; /* Common fields */
- int preloaded; /* Was this pre-loader */
- char* address; /* Load address */
- struct _dynamic* dynamic; /* Symbol table etc. */
-} *aout_file_t;
-
-static int link_aout_link_preload(linker_class_t lc,
- const char* modname, linker_file_t*);
-static int link_aout_link_preload_finish(linker_file_t);
-
-static int link_aout_load_file(linker_class_t lc, const char*, linker_file_t*);
-static int link_aout_lookup_symbol(linker_file_t, const char*,
- c_linker_sym_t*);
-static int link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym,
- linker_symval_t* symval);
-static int link_aout_search_symbol(linker_file_t lf, caddr_t value,
- c_linker_sym_t* sym, long* diffp);
-static void link_aout_unload_file(linker_file_t);
-static void link_aout_unload_preload(linker_file_t);
-static int link_aout_lookup_set(linker_file_t, const char*,
- void ***, void ***, int*);
-
-static kobj_method_t link_aout_methods[] = {
- KOBJMETHOD(linker_lookup_symbol, link_aout_lookup_symbol),
- KOBJMETHOD(linker_symbol_values, link_aout_symbol_values),
- KOBJMETHOD(linker_search_symbol, link_aout_search_symbol),
- KOBJMETHOD(linker_unload, link_aout_unload_file),
- KOBJMETHOD(linker_load_file, link_aout_load_file),
- KOBJMETHOD(linker_link_preload, link_aout_link_preload),
- KOBJMETHOD(linker_link_preload_finish, link_aout_link_preload_finish),
- KOBJMETHOD(linker_lookup_set, link_aout_lookup_set),
- { 0, 0 }
-};
-
-static struct linker_class link_aout_class = {
- "a.out", link_aout_methods, sizeof(struct aout_file)
-};
-
-static int relocate_file(aout_file_t af);
-
-/*
- * The kernel symbol table starts here.
- */
-extern struct _dynamic __DYNAMIC;
-
-static void
-link_aout_init(void* arg)
-{
-#ifndef __ELF__
- struct _dynamic* dp = &__DYNAMIC;
-#endif
-
- linker_add_class(&link_aout_class);
-
-#ifndef __ELF__
- if (dp) {
- aout_file_t af;
-
- linker_kernel_file =
- linker_make_file(kernelname, &link_aout_class);
- if (linker_kernel_file == NULL)
- panic("link_aout_init: Can't create linker structures for kernel");
- af = (aout_file_t) linker_kernel_file;
- af->address = 0;
- af->dynamic = dp;
- linker_kernel_file->address = (caddr_t) KERNBASE;
- linker_kernel_file->size = -(long)linker_kernel_file->address;
- }
-#endif
-}
-
-SYSINIT(link_aout, SI_SUB_KLD, SI_ORDER_THIRD, link_aout_init, 0);
-
-static int
-link_aout_link_preload(linker_class_t lc,
- const char* filename, linker_file_t* result)
-{
- caddr_t modptr, baseptr;
- char *type;
- struct exec *ehdr;
- aout_file_t af;
- linker_file_t lf;
-
- /* Look to see if we have the module preloaded. */
- modptr = preload_search_by_name(filename);
- if (modptr == NULL)
- return ENOENT;
-
- if (((type = (char *)preload_search_info(modptr, MODINFO_TYPE)) == NULL) ||
- strcmp(type, "a.out module") ||
- ((baseptr = preload_search_info(modptr, MODINFO_ADDR)) == NULL) ||
- ((ehdr = (struct exec *)preload_search_info(modptr, MODINFO_METADATA | MODINFOMD_AOUTEXEC)) == NULL))
- return(0); /* we can't handle this */
-
- /* Register with kld */
- lf = linker_make_file(filename, &link_aout_class);
- if (lf == NULL) {
- return(ENOMEM);
- }
- af = (aout_file_t) lf;
-
- /* Looks like we can handle this one */
- filename = preload_search_info(modptr, MODINFO_NAME);
- af->preloaded = 1;
- af->address = baseptr;
-
- /* Assume _DYNAMIC is the first data item. */
- af->dynamic = (struct _dynamic*)(af->address + ehdr->a_text);
- if (af->dynamic->d_version != LD_VERSION_BSD) {
- linker_file_unload(lf);
- return(0); /* we can't handle this */
- }
- af->dynamic->d_un.d_sdt = (struct section_dispatch_table *)
- ((char *)af->dynamic->d_un.d_sdt + (vm_offset_t)af->address);
-
- lf->address = af->address;
- lf->size = ehdr->a_text + ehdr->a_data + ehdr->a_bss;
- *result = lf;
- return(0);
-}
-
-static int
-link_aout_link_preload_finish(linker_file_t lf)
-{
- aout_file_t af;
- int error;
-
- af = (aout_file_t) lf;
- error = relocate_file(af);
- if (error) {
- linker_file_unload(lf);
- return(error);
- }
- return(0);
-}
-
-static int
-link_aout_load_file(linker_class_t lc, const char* filename, linker_file_t* result)
-{
- struct nameidata nd;
- struct thread *td = curthread; /* XXX */
- int error = 0;
- int resid, flags;
- struct exec header;
- aout_file_t af;
- linker_file_t lf = 0;
-
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, td);
- flags = FREAD;
- error = vn_open(&nd, &flags, 0);
- if (error)
- return error;
- NDFREE(&nd, NDF_ONLY_PNBUF);
-
- /*
- * Read the a.out header from the file.
- */
- error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &header, sizeof header, 0,
- UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
- &resid, td);
- if (error)
- goto out;
-
- if (N_BADMAG(header) || !(N_GETFLAG(header) & EX_DYNAMIC))
- goto out;
-
- /*
- * We have an a.out file, so make some space to read it in.
- */
- lf = linker_make_file(filename, &link_aout_class);
- if (lf == NULL) {
- error = ENOMEM;
- goto out;
- }
-
- af = (aout_file_t) lf;
- af->address = malloc(header.a_text + header.a_data + header.a_bss,
- M_LINKER, M_WAITOK);
-
- /*
- * Read the text and data sections and zero the bss.
- */
- error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) af->address,
- header.a_text + header.a_data, 0,
- UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, NOCRED,
- &resid, td);
- if (error)
- goto out;
- bzero(af->address + header.a_text + header.a_data, header.a_bss);
-
- /*
- * Assume _DYNAMIC is the first data item.
- */
- af->dynamic = (struct _dynamic*) (af->address + header.a_text);
- if (af->dynamic->d_version != LD_VERSION_BSD) {
- error = ENOEXEC;
- goto out;
- }
- af->dynamic->d_un.d_sdt = (struct section_dispatch_table *)
- ((char *)af->dynamic->d_un.d_sdt + (vm_offset_t)af->address);
-
- lf->address = af->address;
- lf->size = header.a_text + header.a_data + header.a_bss;
-
- error = linker_load_dependencies(lf);
- if (error)
- goto out;
- error = relocate_file(af);
- if (error)
- goto out;
-
- *result = lf;
-
-out:
- if (error && lf)
- linker_file_unload(lf);
- VOP_UNLOCK(nd.ni_vp, 0, td);
- vn_close(nd.ni_vp, FREAD, td->td_ucred, td);
-
- return error;
-}
-
-static void
-link_aout_unload_file(linker_file_t file)
-{
- aout_file_t af = (aout_file_t) file;
-
- if (af->preloaded) {
- link_aout_unload_preload(file);
- return;
- }
-
- if (af->address)
- free(af->address, M_LINKER);
-}
-
-static void
-link_aout_unload_preload(linker_file_t file)
-{
- if (file->filename)
- preload_delete_name(file->filename);
-}
-
-/*
- * XXX i386 dependant.
- */
-static long
-read_relocation(struct relocation_info* r, char* addr)
-{
- int length = r->r_length;
-
- if (length == 0)
- return *(u_char*) addr;
- else if (length == 1)
- return *(u_short*) addr;
- else if (length == 2)
- return *(u_int*) addr;
- else
- printf("link_aout: unsupported relocation size %d\n", r->r_length);
- return 0;
-}
-
-static void
-write_relocation(struct relocation_info* r, char* addr, long value)
-{
- int length = r->r_length;
-
- if (length == 0)
- *(u_char*) addr = value;
- else if (length == 1)
- *(u_short*) addr = value;
- else if (length == 2)
- *(u_int*) addr = value;
- else
- printf("link_aout: unsupported relocation size %d\n", r->r_length);
-}
-
-#define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off))
-
-static int
-relocate_file(aout_file_t af)
-{
- struct relocation_info* rel;
- struct relocation_info* erel;
- struct relocation_info* r;
- struct nzlist* symbolbase;
- char* stringbase;
- struct nzlist* np;
- char* sym;
- long relocation;
-
- rel = AOUT_RELOC(af, struct relocation_info, LD_REL(af->dynamic));
- erel = AOUT_RELOC(af, struct relocation_info,
- LD_REL(af->dynamic) + LD_RELSZ(af->dynamic));
- symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
- stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
-
- for (r = rel; r < erel; r++) {
- char* addr;
-
- if (r->r_address == 0)
- break;
-
- addr = AOUT_RELOC(af, char, r->r_address);
- if (r->r_extern) {
- np = &symbolbase[r->r_symbolnum];
- sym = &stringbase[np->nz_strx];
-
- if (sym[0] != '_') {
- printf("link_aout: bad symbol name %s\n", sym);
- relocation = 0;
- } else
- relocation = (intptr_t)
- linker_file_lookup_symbol(&af->lf, sym + 1,
- np->nz_type != (N_SETV+N_EXT));
- if (!relocation) {
- printf("link_aout: symbol %s not found\n", sym);
- return ENOENT;
- }
-
- relocation += read_relocation(r, addr);
-
- if (r->r_jmptable) {
- printf("link_aout: can't cope with jump table relocations\n");
- continue;
- }
-
- if (r->r_pcrel)
- relocation -= (intptr_t) af->address;
-
- if (r->r_copy) {
- printf("link_aout: can't cope with copy relocations\n");
- continue;
- }
-
- write_relocation(r, addr, relocation);
- } else {
- write_relocation(r, addr,
- (intptr_t)(read_relocation(r, addr) + af->address));
- }
-
- }
-
- return 0;
-}
-
-static long
-symbol_hash_value(aout_file_t af, const char* name)
-{
- long hashval;
- const char* p;
-
- hashval = '_'; /* fake a starting '_' for C symbols */
- for (p = name; *p; p++)
- hashval = (hashval << 1) + *p;
-
- return (hashval & 0x7fffffff) % LD_BUCKETS(af->dynamic);
-}
-
-int
-link_aout_lookup_symbol(linker_file_t file, const char* name,
- c_linker_sym_t* sym)
-{
- aout_file_t af = (aout_file_t) file;
- long hashval;
- struct rrs_hash* hashbase;
- struct nzlist* symbolbase;
- char* stringbase;
- struct rrs_hash* hp;
- struct nzlist* np;
- char* cp;
-
- if (LD_BUCKETS(af->dynamic) == 0)
- return 0;
-
- hashbase = AOUT_RELOC(af, struct rrs_hash, LD_HASH(af->dynamic));
- symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
- stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
-
-restart:
- hashval = symbol_hash_value(af, name);
- hp = &hashbase[hashval];
- if (hp->rh_symbolnum == -1)
- return ENOENT;
-
- while (hp) {
- np = (struct nzlist *) &symbolbase[hp->rh_symbolnum];
- cp = stringbase + np->nz_strx;
- /*
- * Note: we fake the leading '_' for C symbols.
- */
- if (cp[0] == '_' && !strcmp(cp + 1, name))
- break;
-
- if (hp->rh_next == 0)
- hp = NULL;
- else
- hp = &hashbase[hp->rh_next];
- }
-
- if (hp == NULL)
- /*
- * Not found.
- */
- return ENOENT;
-
- /*
- * Check for an aliased symbol, whatever that is.
- */
- if (np->nz_type == N_INDR+N_EXT) {
- name = stringbase + (++np)->nz_strx + 1; /* +1 for '_' */
- goto restart;
- }
-
- /*
- * Check this is an actual definition of the symbol.
- */
- if (np->nz_value == 0)
- return ENOENT;
-
- if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
- if (np->nz_other == AUX_FUNC)
- /* weak function */
- return ENOENT;
- }
-
- *sym = (linker_sym_t) np;
-
- return 0;
-}
-
-
-static int
-link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym,
- linker_symval_t* symval)
-{
- aout_file_t af = (aout_file_t) file;
- const struct nzlist* np = (const struct nzlist*) sym;
- char* stringbase;
- long numsym = LD_STABSZ(af->dynamic) / sizeof(struct nzlist);
- struct nzlist *symbase;
-
- /* Is it one of ours? It could be another module... */
- symbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
- if (np < symbase)
- return ENOENT;
- if ((np - symbase) > numsym)
- return ENOENT;
-
- stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
-
- symval->name = stringbase + np->nz_strx + 1; /* +1 for '_' */
- if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
- symval->value = 0;
- symval->size = np->nz_value;
- } else {
- symval->value = AOUT_RELOC(af, char, np->nz_value);
- symval->size = np->nz_size;
- }
- return 0;
-}
-
-static int
-link_aout_search_symbol(linker_file_t lf, caddr_t value,
- c_linker_sym_t* sym, long* diffp)
-{
- aout_file_t af = (aout_file_t) lf;
- u_long off = (uintptr_t) (void *) value;
- u_long diff = off;
- u_long sp_nz_value;
- struct nzlist* sp;
- struct nzlist* ep;
- struct nzlist* best = 0;
-
- for (sp = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic)),
- ep = (struct nzlist *) ((caddr_t) sp + LD_STABSZ(af->dynamic));
- sp < ep; sp++) {
- if (sp->nz_name == 0)
- continue;
- sp_nz_value = sp->nz_value + (uintptr_t) (void *) af->address;
- if (off >= sp_nz_value) {
- if (off - sp_nz_value < diff) {
- diff = off - sp_nz_value;
- best = sp;
- if (diff == 0)
- break;
- } else if (off - sp_nz_value == diff) {
- best = sp;
- }
- }
- }
- if (best == 0)
- *diffp = off;
- else
- *diffp = diff;
- *sym = (linker_sym_t) best;
-
- return 0;
-}
-
-/*
- * Look up a linker set on an a.out + gnu LD system.
- */
-struct generic_linker_set {
- int ls_length;
- void *ls_items[1];
-};
-static int
-link_aout_lookup_set(linker_file_t lf, const char *name,
- void ***startp, void ***stopp, int *countp)
-{
- c_linker_sym_t sym;
- linker_symval_t symval;
- void **start, **stop;
- int error, count;
- struct generic_linker_set *setp;
-
- error = link_aout_lookup_symbol(lf, name, &sym);
- if (error)
- return error;
- link_aout_symbol_values(lf, sym, &symval);
- if (symval.value == 0)
- return ESRCH;
- setp = (struct generic_linker_set *)symval.value;
- count = setp->ls_length;
- start = &setp->ls_items[0];
- stop = &setp->ls_items[count];
- if (startp)
- *startp = start;
- if (stopp)
- *stopp = stop;
- if (countp)
- *countp = count;
- return 0;
-}
-
-#endif /* __i386__ */
OpenPOWER on IntegriCloud