moduleloader.patch
Date: Tue Jun  7 14:45:57 EST 2005
Author: Jeremy Kerr
Title: Add a dynamic kernel module loader, with userspace and build tools
Status: Committed
Index: os/kernel/mem/FRKernelPinned.C
===================================================================
RCS file: /u/kitchawa/cvsroot/kitch-core/os/kernel/mem/FRKernelPinned.C,v
retrieving revision 1.2
diff -u -r1.2 FRKernelPinned.C
--- os/kernel/mem/FRKernelPinned.C	29 Oct 2004 16:30:32 -0000	1.2
+++ os/kernel/mem/FRKernelPinned.C	7 Jun 2005 03:45:48 -0000
@@ -32,7 +32,6 @@
     MetaFRKernelPinned::init();
 }
 
-
 SysStatus
 FRKernelPinned::_Create(ObjectHandle &frOH, uval &kaddr, uval size,
 				__CALLER_PID callerPID)
@@ -78,6 +77,15 @@
 destroy:
     fr->destroy();
     return rc;
+}
+
+SysStatus
+FRKernelPinned::_InitModule(uval initfn)
+{
+    void (*f)(void);
+    f = reinterpret_cast<void (*)(void)>(initfn);
+    f();
+    return 0;
 }
 
 SysStatus
Index: os/kernel/mem/FRKernelPinned.H
===================================================================
RCS file: /u/kitchawa/cvsroot/kitch-core/os/kernel/mem/FRKernelPinned.H,v
retrieving revision 1.3
diff -u -r1.3 FRKernelPinned.H
--- os/kernel/mem/FRKernelPinned.H	1 Apr 2005 06:28:03 -0000	1.3
+++ os/kernel/mem/FRKernelPinned.H	7 Jun 2005 03:45:48 -0000
@@ -59,6 +59,8 @@
 			     __out uval &kaddr,
 			     __in uval size,
 			     __CALLER_PID callerPID);
+
+    static SysStatus _InitModule(__in uval initfn);
 };
 
 #endif /* #ifndef __FRKERNEL_PINNED_H_ */
Index: tools/build/shared/Makefile
===================================================================
RCS file: /u/kitchawa/cvsroot/kitch-core/tools/build/shared/Makefile,v
retrieving revision 1.34
diff -u -r1.34 Makefile
--- tools/build/shared/Makefile	31 Mar 2003 15:48:40 -0000	1.34
+++ tools/build/shared/Makefile	7 Jun 2005 03:45:48 -0000
@@ -9,7 +9,7 @@
 #  $Id: Makefile,v 1.34 2003/03/31 15:48:40 dilma Exp $
 # ############################################################################
 
-SUBDIRS = stubgen mkserv thinwire relocate k42login fstools
+SUBDIRS = stubgen mkserv thinwire relocate k42login fstools genmap
 
 -include Make.config
 include $(MKKITCHTOP)/lib/Makerules.tools
Index: tools/build/shared/genmap/Makefile
===================================================================
RCS file: tools/build/shared/genmap/Makefile
diff -N tools/build/shared/genmap/Makefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/build/shared/genmap/Makefile	7 Jun 2005 03:45:48 -0000
@@ -0,0 +1,37 @@
+# ############################################################################
+# K42: (C) Copyright IBM Corp. 2002.
+# All Rights Reserved
+#
+# This file is distributed under the GNU LGPL. You should have
+# received a copy of the License along with K42; see the file LICENSE.html
+# in the top-level directory for more details.
+#
+#  $Id$
+# ############################################################################
+
+default:: targets
+
+-include Make.config
+include $(MKKITCHTOP)/lib/Makerules.tools
+
+GENMAP = genmap 
+
+TARGETS += $(GENMAP)
+
+ifdef IN_OBJ_DIR
+# ############################################################################
+#  rules to be made in object directory
+# ############################################################################
+
+$(GENMAP): genmap.c
+	$(HOST_CC) $(HOST_CFLAGS) $< -o $@
+
+install_targets:: $(TARGETS)
+	$(INSTALL) --mode 0555 $(TARGETS) $(MKTOOLBIN)
+# alternate aix/linux build kludge
+	$(RM) $(TARGETS)
+
+# ############################################################################
+#  end of object directory rules
+# ############################################################################
+endif
Index: tools/build/shared/genmap/genmap.c
===================================================================
RCS file: tools/build/shared/genmap/genmap.c
diff -N tools/build/shared/genmap/genmap.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tools/build/shared/genmap/genmap.c	7 Jun 2005 03:45:49 -0000
@@ -0,0 +1,251 @@
+/******************************************************************************
+ * K42: (C) Copyright IBM Corp. 2005.
+ * All Rights Reserved
+ *
+ * This file is distributed under the GNU LGPL. You should have
+ * received a copy of the license along with K42; see the file LICENSE.html
+ * in the top-level directory for more details.
+ *
+ * $Id$
+ *****************************************************************************/
+/**
+ * @file genmap.c
+ * Tool to generate the symbol table for module relocation
+ */
+#include <stdio.h>
+#include <elf.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <string.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#define Elf_Ehdr	Elf64_Ehdr
+#define Elf_Shdr	Elf64_Shdr
+#define Elf_Rela	Elf64_Rela
+#define Elf_Sym		Elf64_Sym
+#define Elf_Phdr	Elf64_Phdr
+#define Elf_Dyn		Elf64_Dyn
+#define ELF_R_SYM	ELF64_R_SYM
+#define ELF_R_TYPE	ELF64_R_TYPE
+#define ELF_R_INFO	ELF64_R_INFO
+#define ELF_ST_TYPE	ELF64_ST_TYPE
+#define ELF_ST_BIND	ELF64_ST_BIND
+
+union object {
+    char	*buf;
+    Elf_Ehdr	*ehdr;
+};
+
+#define section(obj,n) (((Elf_Shdr *)((obj).buf + bswap((obj).ehdr->e_shoff)))\
+		+ (n))
+#define string(obj,s,n) ((char *)section_addr((obj),(s)) + (n))
+
+#define u64fmt "%016" PRIx64
+
+#if !defined(__BIG_ENDIAN__) && !defined(PLATFORM_AIX)
+#include <byteswap.h>
+#define bswap(x)							\
+({									\
+	typeof(x) y;							\
+	switch (sizeof(x)) {						\
+		/*case 1:	y = x; break;*/				\
+		case 2: y = bswap_16(x); break;				\
+		case 4: y = bswap_32(x); break;				\
+		case 8: y = bswap_64(x); break;				\
+		default:						\
+		assert(0);						\
+	}								\
+	y;								\
+})
+
+#else
+#define bswap(x) (x)
+#endif
+/*
+#define section_name(obj,n) (section((obj),(obj).ehdr->sh_strndx) + \
+                             section((obj),n)->sh_name)
+*/
+
+enum stype {
+    STYPE_DISCARD,
+    STYPE_ADDR,
+    STYPE_OPD
+};
+
+
+enum stype symbol_type(enum stype *section_types, unsigned int index)
+{
+    if (index == SHN_ABS)
+	return STYPE_ADDR;
+
+    if (index == SHN_UNDEF)
+	return STYPE_DISCARD;
+
+    if (index >= SHN_LORESERVE)
+	return STYPE_DISCARD;
+
+    return section_types[index];
+}
+
+enum stype section_type(union object obj, Elf_Shdr *shdr)
+{
+    char *name, *shstrtab;
+
+    shstrtab = obj.buf +
+	    bswap(section(obj,bswap(obj.ehdr->e_shstrndx))->sh_offset);
+    name = shstrtab + bswap(shdr->sh_name);
+    
+    if (!strcmp(shstrtab + bswap(shdr->sh_name), ".opd"))
+	return STYPE_OPD;
+
+    return STYPE_ADDR;
+}
+
+void get_opd(union object obj, unsigned int section, uint64_t addr,
+	uint64_t *opd)
+{
+    Elf_Shdr *shdr = section(obj, section);
+
+    addr -= bswap(shdr->sh_addr);
+    addr += bswap(shdr->sh_offset);
+
+    opd[0] = bswap(((uint64_t *)(obj.buf + addr))[0]);
+    opd[1] = bswap(((uint64_t *)(obj.buf + addr))[1]);
+
+}
+
+
+int print_symtab(union object obj, enum stype *stypes, Elf_Shdr *shdr)
+{
+    Elf_Sym *syms;
+    unsigned int i, nsyms;
+    char *strtab, *shstrtab;
+
+    syms = (Elf_Sym *)(obj.buf + bswap(shdr->sh_offset));
+    strtab = obj.buf + bswap(section(obj, bswap(shdr->sh_link))->sh_offset);
+    shstrtab = obj.buf +
+	    bswap(section(obj,bswap(obj.ehdr->e_shstrndx))->sh_offset);
+    nsyms = bswap(shdr->sh_size) / sizeof(Elf_Sym);
+
+    for (i = 0; i < nsyms; i++) {
+	unsigned short section = bswap(syms[i].st_shndx);
+	enum stype sectype;
+	unsigned char symtype;
+	unsigned char symbind;
+	char *name;
+
+	sectype = symbol_type(stypes, section);
+	symtype = ELF_ST_TYPE(syms[i].st_info);
+	symbind = ELF_ST_BIND(syms[i].st_info);
+
+	name = strtab + bswap(syms[i].st_name);
+
+	if (symbind == STB_LOCAL)
+	    continue;
+
+	if (!name || !*name)
+	    continue;
+	
+	if (sectype == STYPE_ADDR) {
+	    printf("%s 0x" u64fmt "\n",
+		name,
+		bswap(syms[i].st_value));
+
+	} else if (sectype == STYPE_OPD) {
+	    uint64_t opd[2];
+
+	    get_opd(obj, section, bswap(syms[i].st_value), opd);
+
+	    printf("%s 0x" u64fmt " 0x" u64fmt " 0x" u64fmt "\n",
+		name,
+		bswap(syms[i].st_value),
+		opd[0],
+		opd[1]);
+	}
+    }
+
+    return 0;
+}
+
+int print_symtabs(union object obj)
+{
+    Elf_Shdr *shdrs;
+    unsigned int i;
+    enum stype *stypes;
+
+    if (bswap(obj.ehdr->e_shentsize) != sizeof(Elf_Shdr)) {
+	fprintf(stderr, "Elf_Shdr size mismatch %d != %lu\n",
+			bswap(obj.ehdr->e_shentsize),
+			(unsigned long)sizeof(Elf_Shdr));
+	return -ENOEXEC;
+    }
+
+    shdrs = (Elf_Shdr *)(obj.buf + bswap(obj.ehdr->e_shoff));
+
+    if (!(stypes = malloc(bswap(obj.ehdr->e_shnum) * sizeof(enum stype)))) {
+	perror("malloc");
+	return -ENOMEM;
+    }
+
+    for (i = 0; i < bswap(obj.ehdr->e_shnum) ; i++) {
+	stypes[i] = section_type(obj, shdrs + i);
+    }
+
+    for (i = 0; i < bswap(obj.ehdr->e_shnum) ; i++) {
+	if (bswap(shdrs[i].sh_type) == SHT_SYMTAB) {
+	    int rc;
+	    if ((rc = print_symtab(obj, stypes, shdrs + i)))
+		return rc;
+	}
+    }
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    int fd;
+    struct stat statbuf;
+    union object obj;
+    int rc = 0;
+
+    if (argc != 2) {
+	printf("Usage: %s <object>\n", argv[0]);
+	return EXIT_FAILURE;
+    }
+
+    if (!(fd = open(argv[1], O_RDONLY))) {
+	perror("open");
+	return EXIT_FAILURE;
+    }
+
+    if (fstat(fd, &statbuf)) {
+	perror("stat");
+	return EXIT_FAILURE;
+    }
+
+    obj.buf = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+    if (obj.buf == MAP_FAILED) {
+	perror("mmap");
+	return EXIT_FAILURE;
+    }
+
+    rc = print_symtabs(obj);
+
+    if (munmap(obj.buf, statbuf.st_size)) {
+	perror("munmap");
+	return EXIT_FAILURE;
+    }
+
+    return rc;
+}
+
+
Index: usr/Makefile
===================================================================
RCS file: /u/kitchawa/cvsroot/kitch-core/usr/Makefile,v
retrieving revision 1.133
diff -u -r1.133 Makefile
--- usr/Makefile	20 May 2005 20:02:01 -0000	1.133
+++ usr/Makefile	7 Jun 2005 03:45:49 -0000
@@ -9,7 +9,7 @@
 #  $Id: Makefile,v 1.133 2005/05/20 20:02:01 bob Exp $
 # ############################################################################
 
-SUBDIRS =
+SUBDIRS = moduleloader
 
 # set KERNEL=1 if for kernel
 
Index: usr/moduleloader/Loader.C
===================================================================
RCS file: usr/moduleloader/Loader.C
diff -N usr/moduleloader/Loader.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr/moduleloader/Loader.C	7 Jun 2005 03:45:49 -0000
@@ -0,0 +1,360 @@
+/******************************************************************************
+* K42: (C) Copyright IBM Corp. 2005.
+* All Rights Reserved
+*
+* This file is distributed under the GNU LGPL. You should have
+* received a copy of the license along with K42; see the file LICENSE.html
+* in the top-level directory for more details.
+*
+* $Id$
+*****************************************************************************/
+
+#include <sys/sysIncs.H>
+#include "Loader.H"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+
+struct ppc64_plt_entry
+{
+    void *function;
+    void *r2val;
+    void *unused;
+};
+
+Loader::Loader(SymbolResolver *r, void *(*f)(uval, uval &))
+{
+    resolver = r;
+    object.buf = NULL;
+    core = NULL;
+    loadaddr = NULL;
+    symtab = NULL;
+    strtab = NULL;
+    alloc = f;
+}
+
+int Loader::loadModule(char *buf, unsigned int len)
+{
+    uval min_addr, max_addr, align;
+    unsigned int i, rc;
+    Elf_Phdr *phdrs;
+    Elf_Dyn *dyn;
+
+
+    object.buf = buf;
+    objsize = len;
+
+    if (!sanityCheck()) {
+	fprintf(stderr, "Object file failed sanity check\n");
+	return -1;
+    }
+
+    phdrs = (Elf_Phdr *)(object.buf + object.ehdr->e_phoff);
+
+    min_addr = ~0UL;
+    max_addr = 0;
+    align = 1;
+    dyn = NULL;
+    uval dyn_off = 0;
+
+    /* first pass over program headers: retrieve required space and find dynamic
+     * segment */
+    for (i = 0; i < object.ehdr->e_phnum; ++i) {
+	if (phdrs[i].p_type == PT_LOAD) {
+	    if (min_addr > phdrs[i].p_vaddr)
+		min_addr = phdrs[i].p_vaddr;
+	    if (max_addr < phdrs[i].p_vaddr + phdrs[i].p_memsz)
+		max_addr = phdrs[i].p_vaddr + phdrs[i].p_memsz;
+	    if (phdrs[i].p_align > align)
+		align = phdrs[i].p_align;
+	} else if (phdrs[i].p_type == PT_DYNAMIC) {
+	    dyn = (Elf_Dyn *)(object.buf + phdrs[i].p_offset);
+	    dyn_off = phdrs[i].p_offset;
+	}
+    }
+
+    /* Can't continue if no loadable segments or no dynamic info.  */
+    if (min_addr == ~0UL || !dyn) {
+	if (min_addr == ~0UL)
+	    fprintf(stderr, "object has no loadable segments.\n");
+	if (!dyn)
+	    fprintf(stderr, "object has no dynamic segment.\n");
+	return -ENOEXEC;
+    }
+
+    printf("dynamic segment at %p (offset %lx)\n", dyn, dyn_off);
+    printf("address range: %lx -> %lx\n", min_addr, max_addr);
+    printf("align: %ld\n", align);
+
+    if (!(core = (char *)alloc(max_addr - min_addr, kaddr))) {
+	return -ENOMEM;
+    }
+
+    loadaddr = core - min_addr;
+    printf("loadaddr: %p, kaddr: 0x%016lx\n", loadaddr, kaddr);
+
+    /* copy PT_LOAD segments into the object's core */
+    for (i = 0; i < object.ehdr->e_phnum; i++) {
+	void *segstart;
+	if (phdrs[i].p_type != PT_LOAD)
+	    continue;
+
+	segstart = loadaddr + phdrs[i].p_vaddr;
+
+	if (phdrs[i].p_offset + phdrs[i].p_filesz > len) {
+	    fprintf(stderr, "module truncated\n");
+	    free(core);
+	    return -ENOEXEC;
+	}
+	assert(phdrs[i].p_vaddr + phdrs[i].p_memsz <= max_addr);
+
+	printf("copying file (0x%08lx,0x%lx) -> core (0x%08lx,0x%lx)\n",
+		phdrs[i].p_offset, phdrs[i].p_filesz,
+		phdrs[i].p_vaddr, phdrs[i].p_memsz);
+
+	memcpy(segstart, object.buf + phdrs[i].p_offset, phdrs[i].p_filesz);
+    }
+
+    rc = processDynamicSection(dyn);
+
+    return rc;
+}
+
+int Loader::processDynamicSection(Elf_Dyn *dyn)
+{
+    Elf_Rela *rela = NULL;
+    Elf_Rela *jmprel = NULL;
+    unsigned int n_rela = 0, n_pltrel = 0, i;
+    int err;
+
+    /* Scan the dynamic segment for interesting data.  */
+    for (i = 0; dyn[i].d_tag != DT_NULL; i++) {
+	void *addr = loadaddr + dyn[i].d_un.d_ptr;
+
+	switch (dyn[i].d_tag) {
+	case DT_STRTAB:
+	    strtab = (char *)addr;
+	    break;
+	case DT_SYMTAB:
+	    symtab = (Elf_Sym *)addr;
+	    break;
+	case DT_HASH:
+	    /* slightly cheeky - nchain holds the number of symbol table
+	     * entries */
+	    n_sym = *((unsigned int *)addr + 1);
+	    break;
+	case DT_SYMENT:
+	    if (dyn[i].d_un.d_val != sizeof(Elf_Sym)) {
+		fprintf(stderr, "DT_SYMENT size mismatch.\n");
+		return -ENOEXEC;
+	    }
+	    break;
+
+	case DT_RELA:
+	    rela = (Elf_Rela *)addr;
+	    break;
+	case DT_RELASZ:
+	    n_rela = dyn[i].d_un.d_val / sizeof(Elf_Rela);
+	    break;
+	case DT_RELAENT:
+	    if (dyn[i].d_un.d_val != sizeof(Elf_Rela)) {
+		fprintf(stderr, "DT_RELAENT size mismatch.\n");
+		return -ENOEXEC;
+	    }
+	    break;
+
+	case DT_REL:
+	case DT_RELSZ:
+	case DT_RELENT:
+	    fprintf(stderr, "REL relocations not supported on ppc64\n");
+	    return -ENOEXEC;
+	    break;
+
+	case DT_JMPREL:
+	    jmprel = (Elf_Rela *)addr;
+	    break;
+	case DT_PLTREL:
+	    if (dyn[i].d_un.d_val != DT_RELA) {
+		fprintf(stderr, "PLT relocations are not RELA type");
+		return -ENOEXEC;
+	    }
+	    break;
+	case DT_PLTRELSZ:
+	    n_pltrel = dyn[i].d_un.d_val / sizeof(Elf_Rela);
+	    break;
+
+	case DT_INIT:
+	    init = (void (*)(void))((char *)addr - loadaddr + kaddr) ;
+	    printf("INIT at %lx\n", dyn[i].d_un.d_ptr);
+	    break;
+	}
+    }
+
+    /* check for required info */
+    if (!symtab || !strtab || !n_sym || (n_rela && !rela)
+	    || (n_pltrel && !jmprel)) {
+	fprintf(stderr, "Object is missing required sections\n");
+	return -ENOEXEC;
+    }
+
+    if (!init) {
+	fprintf(stderr, "Object has no init function");
+	return -ENOEXEC;
+    }
+    
+    /* process relocations */
+    for (i = 0; i < n_rela; i++) {
+	if ((err = applyRelocation(rela + i)))
+	    return err;
+    }
+
+    for (i = 0; i < n_pltrel; i++) {
+	if ((err = applyRelocation(jmprel + i)))
+	    return err;
+    }
+
+    return 0;
+    
+}
+
+int Loader::applyRelocation(Elf_Rela *rel)
+{
+    Elf_Sym *sym = NULL;
+    unsigned char type;
+    unsigned int symnum;
+    uval value = 0;
+    uint64_t *location;
+    struct SymbolResolver::syment *syment = NULL;
+    
+    location = (uint64_t *)(loadaddr + rel->r_offset);
+        
+    printf("relocation at %p: %lx %lx %lx %p\n", rel,
+	    rel->r_offset, rel->r_info, rel->r_addend, location);
+
+    type = ELF_R_TYPE(rel->r_info);
+    symnum = ELF_R_SYM(rel->r_info);
+    if (symnum) {
+	sym = symtab + symnum;
+	syment = resolve(strtab + sym->st_name);
+	if (!syment) {
+	    fprintf(stderr, "Unknown symbol %s\n", strtab + sym->st_name);
+	    return -ENOENT;
+	}
+	value = syment->value;
+    }
+
+    value += rel->r_addend;
+
+    switch (type) {
+	case R_PPC64_RELATIVE:
+	    *location = (uint64_t)(kaddr + value);
+	    printf("\tRELATIVE: 0x%016lx -> 0x%016lx\n",
+		    rel->r_addend, *location);
+	    break;
+	case R_PPC64_ADDR64:
+	    printf("\tADDR64:   %s -> 0x%016lx + 0x%016lx\n",
+		    strtab + sym->st_name,
+		    rel->r_addend,
+		    value);
+	    *location = value;
+	    break;
+	case R_PPC64_JMP_SLOT:
+	    printf("\tJMP_SLOT: %s -> 0x%016lx + 0x%016lx\n",
+		    strtab + sym->st_name,
+		    rel->r_addend,
+		    value);
+	    if (!syment->funcaddr) {
+		fprintf(stderr, "symbol %s isn't an opd\n",
+				strtab + sym->st_name);
+		return -ENOENT;
+	    }
+	    location[0] = syment->funcaddr;
+	    location[1] = syment->r2value;
+	    /*
+	    memcpy(location, (void *)value,
+			       sizeof(struct ppc64_plt_entry));
+	    */
+	    {
+	    struct ppc64_plt_entry *e = (struct ppc64_plt_entry *)location;
+	    printf("\t%p {0x%016lx, 0x%016lx}\n",
+		    e, (uval)e->function, (uval)e->r2val);
+	    }
+		    
+	    break;
+	default:
+	    printf("\tUnknown relocation type %d\n", type);
+	    return -ENOENT;
+	    break;
+
+    }
+    
+    return 0;
+}
+
+struct SymbolResolver::syment *Loader::resolve(const char *symbol)
+{
+    unsigned int i;
+    SymbolResolver::syment *syment;
+
+    syment = resolver->resolve(symbol);
+    if (syment)
+	return syment;
+
+    /* look it up in the object's own symbol table */
+    for (i = 0; i < n_sym; i++) {
+	char *name = strtab + symtab[i].st_name;
+	if (name && !strcmp(symbol, name)) {
+	    /* @bug leak here! */
+	    printf("found %s in local symtab\n", name);
+	    syment = (SymbolResolver::syment *)
+		malloc(sizeof(SymbolResolver::syment));
+	    syment->name = strdup(symbol);
+	    syment->value = symtab[i].st_value + (uval)loadaddr;
+	    if (ELF_ST_TYPE(symtab[i].st_info) == STT_FUNC) {
+		syment->funcaddr = ((uval *)syment->value)[0];
+		syment->r2value  = ((uval *)syment->value)[1];
+	    }
+	    return syment;
+	}
+
+    }
+    return NULL;
+}
+
+
+int Loader::sanityCheck()
+{
+    if (memcmp(object.ehdr->e_ident, ELFMAG, SELFMAG))
+	return 0;
+
+    if (object.ehdr->e_ident[EI_CLASS] != RELOC_ELFCLASS)
+	return 0;
+
+    if (object.ehdr->e_ident[EI_DATA] != RELOC_ELFDATA)
+	return 0;
+
+    if (object.ehdr->e_ident[EI_VERSION] != EV_CURRENT)
+	return 0;
+
+    if (object.ehdr->e_type != ET_DYN) {
+	fprintf(stderr, "Object file is not a dynamic object\n");
+	return 0;
+    }
+
+    if (object.ehdr->e_machine != RELOC_EM) {
+	fprintf(stderr, "Object file is for incorrect machine\n");
+	return 0;
+    }
+
+    return -1;
+
+}
+
+void (*Loader::getInitFunction())(void)
+{
+    return init;
+}
Index: usr/moduleloader/Loader.H
===================================================================
RCS file: usr/moduleloader/Loader.H
diff -N usr/moduleloader/Loader.H
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr/moduleloader/Loader.H	7 Jun 2005 03:45:49 -0000
@@ -0,0 +1,150 @@
+/******************************************************************************
+ * K42: (C) Copyright IBM Corp. 2005.
+ * All Rights Reserved
+ *
+ * This file is distributed under the GNU LGPL. You should have
+ * received a copy of the license along with K42; see the file LICENSE.html
+ * in the top-level directory for more details.
+ *
+ * $Id$
+ *****************************************************************************/
+
+#ifndef __LOADER_H_
+#define __LOADER_H_
+
+#include "SymbolResolver.H"
+#include <elf.h>
+
+#define ARCH_ppc64 1
+
+#if defined(ARCH_ppc64)
+# define RELOC_ELFCLASS ELFCLASS64
+# define RELOC_ELFDATA  ELFDATA2MSB
+# define RELOC_EM	EM_PPC64
+
+#elif defined(ARCH_x86)
+# define RELOC_ELFCLASS	ELFCLASS32
+# define RELOC_ELFDATA	ELFDATA2LSB
+# define RELOC_EM	EM_386
+
+#else
+# error no arch defined!
+#endif
+
+#if RELOC_ELFCLASS == ELFCLASS64
+#define Elf_Ehdr	Elf64_Ehdr
+#define Elf_Shdr	Elf64_Shdr
+#define Elf_Rela	Elf64_Rela
+#define Elf_Sym		Elf64_Sym
+#define Elf_Phdr	Elf64_Phdr
+#define Elf_Dyn		Elf64_Dyn
+#define ELF_R_SYM	ELF64_R_SYM
+#define ELF_R_TYPE	ELF64_R_TYPE
+#define ELF_R_INFO	ELF64_R_INFO
+#define ELF_ST_TYPE	ELF64_ST_TYPE
+#define Elf_PTYPE	uint64_t
+
+#else
+#define Elf_Ehdr	Elf32_Ehdr
+#define Elf_Shdr	Elf32_Shdr
+#define Elf_Rela	Elf32_Rela
+#define Elf_Sym 	Elf32_Sym
+#define ELF_R_SYM	ELF32_R_SYM
+#define ELF_R_TYPE	ELF32_R_TYPE
+#define ELF_R_INFO	ELF32_R_INFO
+#define Elf_PTYPE	uint32_t
+
+#endif
+
+/**
+ * A class to load and relocate an ELF object.
+ * @todo handle RELOC_REL relocations (not required for ppc64)
+ */
+class Loader {
+public:
+
+    DEFINE_GLOBAL_NEW(Loader);
+
+    /**
+     * Construct a Loader. init() must be called before any other
+     * functions.
+     * @param r A SymbolResolver to look up unresolved strings in the module
+     * @param alloc A function to allocate module memory
+     */
+    Loader(SymbolResolver *r, void *(*alloc)(uval, uval&));
+
+    /**
+     * Initialise the Relocator with an ELF object.
+     * @param buf A pointer to a buffer containing an ELF object
+     * @param len The length of buf
+     * @return zero on success, non-zero on failure
+     */
+    int loadModule(char *buf, unsigned int len);
+
+    /**
+     * Get the entry point for the module
+     * @return the entry point of the loaded module
+     */
+    void (*getInitFunction())(void);
+
+private:
+
+    /**
+     * Reference to the object file in memory, before being processed by the
+     * loader
+     */
+    union {
+	Elf_Ehdr	*ehdr;
+	char		*buf;
+    } object;
+
+    /** size of the object's file */
+    unsigned int	objsize;
+    
+    /** pointer to module loaded in memory */
+    char		*core;
+
+    /** the core's virtual base address */
+    char		*loadaddr;
+
+    /** the object's address in the kernel */
+    uval		kaddr;
+
+    /** the object's symbol table */
+    Elf_Sym		*symtab;
+
+    /** number of symbols in the hash table */
+    unsigned int	n_sym;
+
+    /** the object's string table */
+    char 		*strtab;
+
+    /** the module's entry point */
+    void 		(*init)(void);
+
+    /** the resolver to look up function names */
+    SymbolResolver	*resolver;
+
+    /** a function to allocate kernel memory for the module */
+    void *(*alloc)(uval size, uval &kaddr);
+
+    /**
+     * Perform sanity checks on an ELF object
+     * @return zero on success, non-zero on failure
+     */
+    int sanityCheck();
+
+    /**
+     * Process a module's dynamic section
+     */
+    int processDynamicSection(Elf_Dyn *dyn);
+
+    /**
+     * Process a single relocation
+     */
+    int applyRelocation(Elf_Rela *rel);
+
+    struct SymbolResolver::syment *resolve(const char *symbol);
+};
+
+#endif /* __LOADER_H_ */
Index: usr/moduleloader/Makefile
===================================================================
RCS file: usr/moduleloader/Makefile
diff -N usr/moduleloader/Makefile
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr/moduleloader/Makefile	7 Jun 2005 03:45:49 -0000
@@ -0,0 +1,110 @@
+# ############################################################################
+# K42: (C) Copyright IBM Corp. 2000, 2001.
+# All Rights Reserved
+#
+# This file is distributed under the GNU LGPL. You should have
+# received a copy of the License along with K42; see the file LICENSE.html
+# in the top-level directory for more details.
+#
+#  $Id: Makefile,v 1.122 2004/10/06 14:46:09 azimi Exp $
+# ############################################################################
+
+SUBDIRS =
+
+# set KERNEL=1 if for kernel
+
+KERNEL=0
+-include Make.config
+
+include $(MKKITCHTOP)/lib/Makerules.kitch
+
+default:: targets
+
+OBJSTARGETS += 
+
+USRTARGETS+=$(OBJSTARGETS)
+USRTARGETS+= ModuleLoader
+
+BIN_FILES += Object.so
+
+ifdef IN_OBJ_DIR
+# ############################################################################
+#  rules to be made in object directory
+# ############################################################################
+CPPFLAGS += -isystem $(KITCH_LINUX)
+
+TARGETS  += $(USRTARGETS) $(BIN_FILES)
+
+DYNAMIC_LINK+= $(TARGETS)
+
+CLASSES += 
+
+SERVE	+= 
+
+ROOT_FILES = boot_image.map
+
+boot_image.map: $(MKANCHOR)/$(TARGET_MACHINE)/$(OPTIMIZATION)/os/boot_image.dbg 
+	 $(MKTOOLBIN)/genmap $< > $@
+
+# need to relink if any of these change
+DEPLIBS= $(KITCH_GLIBC)
+NORM_LIBS= $(K42_LDFLAGS) $(K42LIBS)
+
+MODULELOADER_OBJS = Loader.o ModuleLoader.o SymbolResolver.o
+SRCS = Loader.C ModuleLoader.C SymbolResolver.C
+
+MODULE_OBJS = Object.o
+
+OBJS=$(OBJSTARGETS:%=%.o) $(MODULELOADER_OBJS) $(MODULE_OBJS)
+
+# Most of the OBJS are intermediate and will be removed after building,
+# we want to keep them so relinking will not cause the source to be
+# recompiled.
+.SECONDARY: $(OBJS)
+
+# Catch ALL for one object per executable
+%: %.o $(DEPLIBS)	
+	$(LINK.cc) $^ $(NORM_LIBS) -o $@
+	$(STRIP.dbg)
+
+ModuleLoader: $(MODULELOADER_OBJS) $(DEPLIBS)
+	$(LINK.c) $^ $(NORM_LIBS) -o $@
+	$(STRIP.dbg)
+
+Object.so: $(MODULE_OBJS)
+	$(LINK.c) -nostdlib -shared $< -fno-exceptions -o $@
+	
+INST_PROGS =	$(USRTARGETS:%=$(MKKITCHROOT)/kbin/%) \
+		$(BIN_FILES:%=$(MKKITCHROOT)/kbin/%)
+
+INST_FILES =	$(ROOT_FILES:%=$(MKKITCHROOT)/kbin/%)		
+
+# Different patterns for installing script files.
+$(MKKITCHROOT)/kbin/test:
+	$(INSTALL) --mode 0775 -d $@
+
+$(MKKITCHROOT)/kbin/%: $(SRC_DIR_PATH)/%
+	$(INSTALL_INC) $(@D) $(<D) $(<F)
+	$(INSTALL_DSK)
+
+$(INST_FILES): $(MKKITCHROOT)/kbin/%: %
+	$(INSTALL_INC) $(@D) $(<D) $(<F)
+	$(INSTALL_DSK)
+
+$(INST_PROGS): $(MKKITCHROOT)/kbin/%: %
+	$(INSTALL) --mode 0755 $< $(@D)
+	$(INSTALL_DSK)
+
+install_targets:: $(INST_PROGS) $(INST_FILES)
+
+XTRA_CLEAN=	$(CLASSES:%=%.o)	\
+		$(CLASSES:%=%.d)	\
+		$(USRTARGETS:%=%.dbg)
+
+clean::
+	-$(RM) $(XTRA_CLEAN)
+
+# ############################################################################
+#  end of object directory rules
+# ############################################################################
+endif
Index: usr/moduleloader/ModuleLoader.C
===================================================================
RCS file: usr/moduleloader/ModuleLoader.C
diff -N usr/moduleloader/ModuleLoader.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr/moduleloader/ModuleLoader.C	7 Jun 2005 03:45:49 -0000
@@ -0,0 +1,148 @@
+/******************************************************************************
+ * K42: (C) Copyright IBM Corp. 2005.
+ * All Rights Reserved
+ *
+ * This file is distributed under the GNU LGPL. You should have
+ * received a copy of the license along with K42; see the file LICENSE.html
+ * in the top-level directory for more details.
+ *
+ * $Id$
+ *****************************************************************************/
+
+#include <sys/sysIncs.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/ProcessLinuxClient.H>
+#include <stub/StubFRKernelPinned.H>
+#include <stub/StubRegionDefault.H>
+#include <mem/Access.H>
+
+#include "Loader.H"
+#include "SymbolResolver.H"
+
+/* Slurp a file into memory. Pointer must be free()d */
+char *load_file(const char *path, int *len)
+{
+    struct stat statbuf;
+    int fd;
+    char *buf;
+
+    if (stat(path, &statbuf)) {
+	perror("stat");
+	return NULL;
+    }
+
+    if (!(fd = open(path, O_RDONLY))) {
+	perror("open");
+	return NULL;
+    }
+
+    if (!(buf = (char *)malloc(statbuf.st_size))) {
+	perror("malloc");
+	return NULL;
+    }
+
+    *len = statbuf.st_size;
+
+    if (read(fd, buf, statbuf.st_size) != statbuf.st_size) {
+	perror("read");
+	free(buf);
+	return NULL;
+    }
+
+    if (close(fd))
+	perror("close");
+
+    return buf;
+}
+
+/**
+ * Callback to alloc memory for the loaded module
+ */
+void *moduleAlloc(uval size, uval &kaddr)
+{
+    SysStatus rc;
+    ObjectHandle frOH;
+    uval uaddr;
+
+    rc = StubFRKernelPinned::_Create(frOH, kaddr, size);
+    if (_FAILURE(rc)) {
+	printf("FRKernelPinned::_Create() failed\n");
+	return NULL;
+    }
+
+    /* Create a Region to allow the process to reference the memory */
+    rc = StubRegionDefault::_CreateFixedLenExt(uaddr, size, 0, frOH, 0,
+	    AccessMode::writeUserWriteSup, 0, RegionType::UseSame);
+
+    if (_FAILURE(rc)) {
+	printf("_CreateFixedLen() failed: 0x%016lx", rc);
+	return NULL;
+    }
+    
+    printf("moduleAlloc: 0x%016lx -> 0x%016lx\n", uaddr, kaddr);
+
+    return (void *)uaddr;
+
+
+}
+
+int main(int argc, char **argv)
+{
+    Loader *l;
+    SymbolResolver *r;
+    int len;
+    char *buf;
+    uval module_init;
+    SysStatus rc;
+    
+    ProcessLinuxClient::SyscallEnter();
+
+    if (argc != 2) {
+	fprintf(stderr, "Usage: %s <object-file>\n", argv[0]);
+	return EXIT_FAILURE;
+    }
+
+    if (!(buf = load_file(argv[1], &len))) {
+	return EXIT_FAILURE;
+    }
+
+    r = new SymbolResolver();
+
+    if (r->init()) {
+	fprintf(stderr, "Couldn't init resolver\n");
+	return EXIT_FAILURE;
+    }
+
+
+    l = new Loader(r, moduleAlloc);
+
+    if (l->loadModule(buf, len)) {
+	fprintf(stderr, "relocation failed\n");
+	free(buf);
+	return EXIT_FAILURE;
+    }
+
+    module_init = (uval)(l->getInitFunction());
+
+    printf("module entry point: 0x%016lx\n", module_init);
+
+    rc = StubFRKernelPinned::_InitModule(module_init);
+
+    if (_FAILURE(rc)) {
+	printf("FRKernelPinned::_InitModule() failed\n");
+	return EXIT_FAILURE;
+    }
+
+    delete(l);
+    delete(r);
+
+    free(buf);
+
+    return 0;
+}
Index: usr/moduleloader/Object.C
===================================================================
RCS file: usr/moduleloader/Object.C
diff -N usr/moduleloader/Object.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr/moduleloader/Object.C	7 Jun 2005 03:45:49 -0000
@@ -0,0 +1,35 @@
+/******************************************************************************
+ * K42: (C) Copyright IBM Corp. 2005.
+ * All Rights Reserved
+ *
+ * This file is distributed under the GNU LGPL. You should have
+ * received a copy of the license along with K42; see the file LICENSE.html
+ * in the top-level directory for more details.
+ *
+ * $Id$
+ *****************************************************************************/
+
+/**
+ * @file Object.C
+ * A sample dynamically-loadable k42 module.
+ */
+
+/**
+ * @todo fix Makefile so this compiles in a kernel environment
+ */
+#include <sys/sysIncs.H>
+
+/**
+ * Specify an initialisation function for this module. This is a temporary
+ * solution to the 'specify an init function' idea.
+ * @param fn the module's init function
+ */ 
+#define module_init(fn) extern "C" { void _init(void) { fn(); } }
+
+static void test_module(void)
+{
+    err_printf("module loaded!\n");
+}
+
+module_init(test_module);
+
Index: usr/moduleloader/SymbolResolver.C
===================================================================
RCS file: usr/moduleloader/SymbolResolver.C
diff -N usr/moduleloader/SymbolResolver.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr/moduleloader/SymbolResolver.C	7 Jun 2005 03:45:49 -0000
@@ -0,0 +1,110 @@
+/******************************************************************************
+* K42: (C) Copyright IBM Corp. 2005.
+* All Rights Reserved
+*
+* This file is distributed under the GNU LGPL. You should have
+* received a copy of the license along with K42; see the file LICENSE.html
+* in the top-level directory for more details.
+*
+* $Id$
+*****************************************************************************/
+
+#include <sys/sysIncs.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+#include "SymbolResolver.H"
+
+#ifndef MAP_FILE
+#define MAP_FILE "boot_image.map"
+#endif
+
+#define SYM_LEN 256
+
+SymbolResolver::SymbolResolver()
+{
+    symbols = NULL;
+    n_symbols = 0;
+    alloc_symbols = 0;
+}
+
+int SymbolResolver::init()
+{
+    FILE *fd;
+    char name[SYM_LEN];
+    struct syment syment;
+
+    if (!(fd = fopen(MAP_FILE, "r"))) {
+	perror("open");
+	return errno;
+    }
+
+    syment.name = name;
+
+    while (!feof(fd)) {
+	int rc = fscanf(fd, "%s 0x%lx 0x%lx 0x%lx\n",
+		syment.name, &syment.value, &syment.funcaddr, &syment.r2value);
+	if (rc == 0)
+	    break;
+
+	if (rc != 4)
+	    syment.funcaddr = syment.r2value = 0;
+
+	addSymbol(&syment);
+    }
+
+    fclose(fd);
+
+    printf("got %d symbols\n", n_symbols);
+
+    return 0;
+}
+
+struct SymbolResolver::syment *SymbolResolver::resolve(const char *symbol)
+{
+    unsigned int i;
+    for (i = 0; i < n_symbols; i++)
+	if (!strcmp(symbols[i].name, symbol))
+	    return symbols + i;
+    return 0;
+}
+
+void SymbolResolver::dump()
+{
+    unsigned int i;
+    for (i = 0; i < n_symbols; i++) {
+	if (symbols[i].funcaddr)
+	    printf("%s -> %lx\n", symbols[i].name, symbols[i].value);
+	else
+	    printf("%s -> %lx (%lx, %lx)\n", symbols[i].name,
+		    symbols[i].value, symbols[i].funcaddr, symbols[i].r2value);
+    }
+}
+
+#define max(a,b) ((a) > (b) ? (a) : (b))
+
+int SymbolResolver::addSymbol(struct SymbolResolver::syment *syment)
+{
+    if (n_symbols == alloc_symbols) {
+	alloc_symbols = max(alloc_symbols * 2, 256);
+
+	symbols = (struct syment *)realloc(symbols,
+		alloc_symbols * sizeof(struct syment));
+	if (!symbols) {
+	    perror("realloc");
+	    return -1;
+	}
+    }
+
+    symbols[n_symbols].name	= strdup(syment->name);
+    symbols[n_symbols].value	= syment->value;
+    symbols[n_symbols].funcaddr	= syment->funcaddr;
+    symbols[n_symbols].r2value	= syment->r2value;
+    n_symbols++;
+
+    return 0;
+}
+
Index: usr/moduleloader/SymbolResolver.H
===================================================================
RCS file: usr/moduleloader/SymbolResolver.H
diff -N usr/moduleloader/SymbolResolver.H
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ usr/moduleloader/SymbolResolver.H	7 Jun 2005 03:45:49 -0000
@@ -0,0 +1,61 @@
+/******************************************************************************
+* K42: (C) Copyright IBM Corp. 2005.
+* All Rights Reserved
+*
+* This file is distributed under the GNU LGPL. You should have
+* received a copy of the license along with K42; see the file LICENSE.html
+* in the top-level directory for more details.
+*
+* $Id$
+*****************************************************************************/
+
+#ifndef __SYMBOLRESOLVER_H_
+#define __SYMBOLRESOLVER_H_
+
+/**
+ * A class to lookup symbols for object relocation
+ */
+class SymbolResolver {
+
+public:
+
+    struct syment {
+	char *name;
+	uval value;
+	uval funcaddr;
+	uval r2value;
+    };
+
+    DEFINE_GLOBAL_NEW(SymbolResolver);
+
+    /**
+     * Create a Resolver.
+     */
+    SymbolResolver();
+
+    /**
+     * Initialise the resolver. This will load the symbol table, and must be
+     * called before resolve().
+     */
+    int init();
+
+    /**
+     * Return the address of a symbol, or null if the symbol is undefined
+     * @param symbol The name of the symbol to resolve
+     * @return The address of the symbol
+     */
+    struct syment *resolve(const char *symbol);
+
+private:
+
+    struct syment *symbols;
+    unsigned int n_symbols;
+    unsigned int alloc_symbols;
+
+    int addSymbol(struct SymbolResolver::syment *syment);
+
+    void dump(void);
+
+};
+
+#endif /* __SYMBOLRESOLVER_H_ */
