summaryrefslogtreecommitdiffstats
path: root/sys/boot/common/load_aout.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/boot/common/load_aout.c')
-rw-r--r--sys/boot/common/load_aout.c334
1 files changed, 296 insertions, 38 deletions
diff --git a/sys/boot/common/load_aout.c b/sys/boot/common/load_aout.c
index 45b6328..5c59372 100644
--- a/sys/boot/common/load_aout.c
+++ b/sys/boot/common/load_aout.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aout_freebsd.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $
+ * $Id: load_aout.c,v 1.1 1998/08/31 21:10:42 msmith Exp $
*/
#include <sys/param.h>
@@ -33,10 +33,15 @@
#include <string.h>
#include <machine/bootinfo.h>
#include <stand.h>
+#define _AOUT_INCLUDE_
+#include <nlist.h>
+#include <link.h>
#include "bootstrap.h"
-static int aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr);
+static int aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr, int kernel);
+static vm_offset_t aout_findkldident(struct loaded_module *mp, struct exec *ehdr);
+static int aout_fixupkldmod(struct loaded_module *mp, struct exec *ehdr);
char *aout_kerneltype = "a.out kernel";
char *aout_moduletype = "a.out module";
@@ -49,12 +54,15 @@ char *aout_moduletype = "a.out module";
int
aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
{
- struct loaded_module *mp;
+ struct loaded_module *mp, *kmp;
struct exec ehdr;
int fd;
vm_offset_t addr;
int err, kernel;
+ u_int pad;
+ mp = NULL;
+
/*
* Open the image, read and validate the a.out header
*/
@@ -62,35 +70,42 @@ aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
return(EFTYPE);
if ((fd = open(filename, O_RDONLY)) == -1)
return(errno);
- if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
- return(EFTYPE); /* could be EIO, but may be small file */
- if (N_BADMAG(ehdr))
- return(EFTYPE);
+ if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) {
+ err = EFTYPE; /* could be EIO, but may be small file */
+ goto oerr;
+ }
+ if (N_BADMAG(ehdr)) {
+ err = EFTYPE;
+ goto oerr;
+ }
/*
* Check to see what sort of module we are.
*
* XXX should check N_GETMID()
*/
- mp = mod_findmodule(NULL, NULL);
+ kmp = mod_findmodule(NULL, NULL);
if (N_GETFLAG(ehdr) == (EX_DYNAMIC | EX_PIC)) {
/* Looks like a kld module */
- if (mp == NULL) {
+ if (kmp == NULL) {
printf("aout_loadmodule: can't load module before kernel\n");
- return(EPERM);
+ err = EPERM;
+ goto oerr;
}
- if (strcmp(aout_kerneltype, mp->m_type)) {
- printf("out_loadmodule: can't load module with kernel type '%s'\n", mp->m_type);
- return(EPERM);
+ if (strcmp(aout_kerneltype, kmp->m_type)) {
+ printf("out_loadmodule: can't load module with kernel type '%s'\n", kmp->m_type);
+ err = EPERM;
+ goto oerr;
}
/* Looks OK, got ahead */
kernel = 0;
} else if (N_GETFLAG(ehdr) == 0) {
/* Looks like a kernel */
- if (mp != NULL) {
+ if (kmp != NULL) {
printf("aout_loadmodule: kernel already loaded\n");
- return(EPERM);
+ err = EPERM;
+ goto oerr;
}
/*
* Calculate destination address based on kernel entrypoint
@@ -99,39 +114,56 @@ aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
dest = ehdr.a_entry & 0x100000;
if (dest == 0) {
printf("aout_loadmodule: not a kernel (maybe static binary?)\n");
- return(EPERM);
+ err = EPERM;
+ goto oerr;
}
kernel = 1;
} else {
- return(EFTYPE);
+ err = EFTYPE;
+ goto oerr;
}
/*
* Ok, we think we should handle this.
*/
mp = malloc(sizeof(struct loaded_module));
- mp->m_name = strdup(filename); /* XXX should we prune the name? */
+ mp->m_name = kernel ? strdup(filename) : NULL; /* XXX should we prune the name? */
mp->m_type = strdup(kernel ? aout_kerneltype : aout_moduletype);
- mp->m_args = NULL; /* XXX should we put the bootstrap args here and parse later? */
+ mp->m_args = NULL; /* filled in by parent */
mp->m_metadata = NULL;
- mp->m_addr = addr = dest;
+ /* Page-align the load address */
+ addr = dest;
+ pad = (u_int)addr & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ addr += pad;
+ }
+ mp->m_addr = addr; /* save the aligned load address */
printf("%s at 0x%x\n", filename, addr);
- mp->m_size = aout_loadimage(fd, addr, &ehdr);
+ mp->m_size = aout_loadimage(fd, addr, &ehdr, kernel);
if (mp->m_size == 0)
goto ioerr;
+ /* Handle KLD module data */
+ if (!kernel && ((err = aout_fixupkldmod(mp, &ehdr)) != 0))
+ goto oerr;
+
/* save exec header as metadata */
mod_addmetadata(mp, MODINFOMD_AOUTEXEC, sizeof(struct exec), &ehdr);
/* Load OK, return module pointer */
*result = (struct loaded_module *)mp;
- return(0);
-
+ err = 0;
+ goto out;
+
ioerr:
err = EIO;
- close(fd);
+ oerr:
+ mod_discard(mp);
free(mp);
+ out:
+ close(fd);
return(err);
}
@@ -143,17 +175,17 @@ aout_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
* align the symbol table.
*/
static int
-aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr)
+aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr, int kernel)
{
u_int pad;
vm_offset_t addr;
int ss;
-
+
addr = loadaddr;
lseek(fd, N_TXTOFF(*ehdr), SEEK_SET);
-
+
/* text segment */
- printf("text=0x%lx ", ehdr->a_text);
+ printf(" text=0x%lx ", ehdr->a_text);
if (archsw.arch_readin(fd, addr, ehdr->a_text) != ehdr->a_text)
return(0);
addr += ehdr->a_text;
@@ -164,24 +196,23 @@ aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr)
return(0);
addr += ehdr->a_data;
- /* skip the BSS */
+ /* For kernels, we pad the BSS to a page boundary */
+ if (kernel) {
+ pad = (u_int)ehdr->a_bss & PAGE_MASK;
+ if (pad != 0) {
+ pad = PAGE_SIZE - pad;
+ ehdr->a_bss += pad;
+ }
+ }
printf("bss=0x%lx ", ehdr->a_bss);
addr += ehdr->a_bss;
-
- /* pad to a page boundary */
- pad = (u_int)addr & PAGE_MASK;
- if (pad != 0) {
- pad = PAGE_SIZE - pad;
- addr += pad;
- ehdr->a_bss += pad;
- }
/* symbol table size */
archsw.arch_copyin(&ehdr->a_syms, addr, sizeof(ehdr->a_syms));
addr += sizeof(ehdr->a_syms);
/* symbol table */
- printf("symbols=[0x%x+0x%x+0x%lx", pad, sizeof(ehdr->a_syms), ehdr->a_syms);
+ printf("symbols=[0x%x+0x%lx", sizeof(ehdr->a_syms), ehdr->a_syms);
if (archsw.arch_readin(fd, addr, ehdr->a_syms) != ehdr->a_syms)
return(0);
addr += ehdr->a_syms;
@@ -200,3 +231,230 @@ aout_loadimage(int fd, vm_offset_t loadaddr, struct exec *ehdr)
return(addr - loadaddr);
}
+
+#define AOUT_RELOC(mp, off) ((mp)->m_addr + (vm_offset_t)(off))
+
+/*
+ * The goal here is to find the one symbol in the loaded object
+ * which fits the format "kld_identifier_<something>. If there's
+ * more than one, we fail.
+ */
+static vm_offset_t
+aout_findkldident(struct loaded_module *mp, struct exec *ehdr)
+{
+ /* XXX much of this can go when we can address the load area directly */
+ vm_offset_t sp, ep, cand, stringbase, result;
+ struct _dynamic dynamic;
+ struct section_dispatch_table sdt;
+ struct nzlist nzl;
+ char *np;
+ int match;
+
+ /* Get the _DYNAMIC object, which we assume is first in the data segment */
+ archsw.arch_copyout(AOUT_RELOC(mp, ehdr->a_text), &dynamic, sizeof(dynamic));
+ archsw.arch_copyout(AOUT_RELOC(mp, dynamic.d_un.d_sdt), &sdt, sizeof(struct section_dispatch_table));
+ dynamic.d_un.d_sdt = &sdt; /* fix up SDT pointer */
+ if (dynamic.d_version != LD_VERSION_BSD)
+ return(0);
+ stringbase = AOUT_RELOC(mp, LD_STRINGS(&dynamic));
+
+ /* start pointer */
+ sp = AOUT_RELOC(mp, LD_SYMBOL(&dynamic));
+ /* end pointer */
+ ep = sp + LD_STABSZ(&dynamic);
+
+ /*
+ * Walk the entire table comparing names.
+ */
+ match = 0;
+ result = 0;
+ for (cand = sp; cand < ep; cand += sizeof(struct nzlist)) {
+ /* get the entry, check for a name */
+ archsw.arch_copyout(cand, &nzl, sizeof(struct nzlist));
+ /* is this symbol worth looking at? */
+ if ((nzl.nz_strx == 0) || /* no name */
+ (nzl.nz_value == 0) || /* not a definition */
+ ((nzl.nz_type == N_UNDF+N_EXT) &&
+ (nzl.nz_value != 0) &&
+ (nzl.nz_other == AUX_FUNC))) /* weak function */
+ continue;
+
+ np = strdupout(stringbase + nzl.nz_strx);
+ match = (np[0] == '_') && !strncmp(KLD_IDENT_SYMNAME, np + 1, strlen(KLD_IDENT_SYMNAME));
+ free(np);
+ if (match) {
+ /* duplicates? */
+ if (result)
+ return(0);
+ result = AOUT_RELOC(mp, nzl.nz_value);
+ }
+ }
+ return(result);
+}
+
+/*
+ * Perform extra housekeeping associated with loading a KLD module.
+ *
+ * XXX if this returns an error, it seems the heap becomes corrupted.
+ */
+static int
+aout_fixupkldmod(struct loaded_module *mp, struct exec *ehdr)
+{
+ struct kld_module_identifier kident;
+ struct kld_module_dependancy *kdeps;
+ vm_offset_t vp;
+ size_t dsize;
+
+ /* Find the KLD identifier */
+ if ((vp = aout_findkldident(mp, ehdr)) == 0) {
+ printf("bad a.out module format\n");
+ return(EFTYPE);
+ }
+ archsw.arch_copyout(vp, &kident, sizeof(struct kld_module_identifier));
+
+ /* Name the module using the name from the KLD data */
+ if (mod_findmodule(kident.ki_name, NULL) != NULL) {
+ printf("module '%s' already loaded\n", kident.ki_name);
+ return(EPERM);
+ }
+ mp->m_name = strdup(kident.ki_name);
+
+ /* Save the module identifier */
+ mod_addmetadata(mp, MODINFOMD_KLDIDENT, sizeof(struct kld_module_identifier), &kident);
+
+ /* Look for dependancy data, add to metadata list */
+ if (kident.ki_ndeps > 0) {
+ dsize = kident.ki_ndeps * kident.ki_depsize;
+ kdeps = malloc(dsize);
+ archsw.arch_copyout(AOUT_RELOC(mp, kident.ki_deps), kdeps, dsize);
+ mod_addmetadata(mp, MODINFOMD_KLDDEP, dsize, kdeps);
+ free(kdeps);
+ }
+ return(0);
+}
+
+#if 0
+/************************************************************/
+/* XXX Arbitrary symbol lookup - unused at this point XXX */
+/* */
+/* Code heavily borrowed from kern/link_aout.c (c) DFR */
+/************************************************************/
+
+static long
+symbol_hash_value(struct _dynamic *dynamic, 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(dynamic);
+}
+
+/*
+ * Locate the symbol (name) in the a.out object associated with (mp),
+ * return a vm_offset_t containing the value of the symbol.
+ */
+static vm_offset_t
+aout_findsym(char *name, struct loaded_module *mp)
+{
+ struct module_metadata *md;
+ struct exec *ehdr;
+ struct _dynamic dynamic;
+ struct section_dispatch_table sdt;
+ vm_offset_t hashbase, symbolbase, stringbase, hp, np, cp;
+ struct rrs_hash hash;
+ struct nzlist nzl;
+ char *symbol, *asymbol; /* XXX symbol name limit? */
+ long hashval;
+ vm_offset_t result;
+
+
+ symbol = NULL;
+ asymbol = NULL;
+ result = 0;
+
+ /* Find the exec header */
+ if ((md = mod_findmetadata(mp, MODINFOMD_AOUTEXEC)) == NULL)
+ goto out;
+ ehdr = (struct exec *)md->md_data;
+
+ /* Get the _DYNAMIC object, which we assume is first in the data segment */
+ archsw.arch_copyout(AOUT_RELOC(mp, ehdr->a_text), &dynamic, sizeof(dynamic));
+ archsw.arch_copyout(AOUT_RELOC(mp, dynamic.d_un.d_sdt), &sdt, sizeof(struct section_dispatch_table));
+ dynamic.d_un.d_sdt = &sdt; /* fix up SDT pointer */
+ if ((dynamic.d_version != LD_VERSION_BSD) ||
+ (LD_BUCKETS(&dynamic) == 0))
+ goto out;
+
+ hashbase = AOUT_RELOC(mp, LD_HASH(&dynamic));
+ symbolbase = AOUT_RELOC(mp, LD_SYMBOL(&dynamic));
+ stringbase = AOUT_RELOC(mp, LD_STRINGS(&dynamic));
+
+restart:
+ hashval = symbol_hash_value(&dynamic, name);
+ hp = hashbase + (hashval * sizeof(struct rrs_hash));
+ archsw.arch_copyout(hp, &hash, sizeof(struct rrs_hash));
+ if (hash.rh_symbolnum == -1)
+ goto out;
+
+ while (hp) {
+ np = symbolbase + (hash.rh_symbolnum * sizeof(struct nzlist));
+ archsw.arch_copyout(np, &nzl, sizeof(struct nzlist));
+ cp = stringbase + nzl.nz_strx;
+ if (symbol != NULL)
+ free(symbol);
+ symbol = strdupout(cp);
+ /*
+ * Note: we fake the leading '_' for C symbols.
+ */
+ if (symbol[0] == '_' && !strcmp(symbol + 1, name))
+ break;
+
+ if (hash.rh_next == 0) {
+ hp = 0;
+ } else {
+ hp = hashbase + (hash.rh_next * sizeof(struct rrs_hash));
+ archsw.arch_copyout(hp, &hash, sizeof(struct rrs_hash));
+ }
+ }
+ /* Not found. */
+ if (hp == 0)
+ goto out;
+
+ /*
+ * Check for an aliased symbol, whatever that is.
+ */
+ if (nzl.nz_type == N_INDR+N_EXT) {
+ np += sizeof(struct nzlist);
+ archsw.arch_copyout(np, &nzl, sizeof(struct nzlist));
+ asymbol = strdupout(stringbase + nzl.nz_strx + 1); /* +1 for '_' */
+ goto restart;
+ }
+
+ /*
+ * Check this is an actual definition of the symbol.
+ */
+ if (nzl.nz_value == 0)
+ goto out;
+
+ if (nzl.nz_type == N_UNDF+N_EXT && nzl.nz_value != 0)
+ if (nzl.nz_other == AUX_FUNC)
+ /* weak function */
+ goto out;
+
+ /* Return a vm_offset_t pointing to the object itself */
+ result = AOUT_RELOC(mp, nzl.nz_value);
+
+ out:
+ if (symbol)
+ free(symbol);
+ if (asymbol)
+ free(asymbol);
+ return(result);
+
+}
+
+#endif
OpenPOWER on IntegriCloud