? boot/common/old_load_elf_obj.c Index: sys/linker.h =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/sys/linker.h,v retrieving revision 1.38 diff -u -r1.38 linker.h --- sys/linker.h 13 Jul 2004 19:36:59 -0000 1.38 +++ sys/linker.h 16 Aug 2004 01:23:54 -0000 @@ -197,6 +197,7 @@ #define MODINFOMD_HOWTO 0x0007 /* boothowto */ #define MODINFOMD_KERNEND 0x0008 /* kernend */ #endif +#define MODINFOMD_SHDR 0x0009 /* section header table */ #define MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */ #define MODINFOMD_DEPLIST (0x4001 | MODINFOMD_NOCOPY) /* depends on */ Index: kern/kern_linker.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/kern/kern_linker.c,v retrieving revision 1.113 diff -u -r1.113 kern_linker.c --- kern/kern_linker.c 13 Jul 2004 19:36:58 -0000 1.113 +++ kern/kern_linker.c 16 Aug 2004 01:23:54 -0000 @@ -1203,10 +1203,9 @@ lf = NULL; TAILQ_FOREACH(lc, &classes, link) { error = LINKER_LINK_PRELOAD(lc, modname, &lf); - if (error) { - lf = NULL; + if (!error) break; - } + lf = NULL; } if (lf) TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); Index: kern/link_elf_obj.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/kern/link_elf_obj.c,v retrieving revision 1.86 diff -u -r1.86 link_elf_obj.c --- kern/link_elf_obj.c 13 Jul 2004 19:36:58 -0000 1.86 +++ kern/link_elf_obj.c 16 Aug 2004 01:23:54 -0000 @@ -81,6 +81,8 @@ typedef struct elf_file { struct linker_file lf; /* Common fields */ + int preloaded; + caddr_t modptr; caddr_t address; /* Relocation address */ vm_object_t object; /* VM object to hold file pages */ @@ -168,15 +170,223 @@ link_elf_link_preload(linker_class_t cls, const char *filename, linker_file_t *result) { + Elf_Ehdr *hdr; + Elf_Shdr *shdr; + Elf_Sym *es; + void *modptr, *baseptr, *sizeptr; + char *type; + elf_file_t ef; + linker_file_t lf; + Elf_Addr off; + int error, i, j, pb, ra, rl, shstrindex, symstrindex, symtabindex; + + printf("link_elf_link_preload(%s)\n", filename); + + /* Look to see if we have the file preloaded */ + modptr = preload_search_by_name(filename); + if (modptr == NULL) + return ENOENT; + + type = (char *)preload_search_info(modptr, MODINFO_TYPE); + baseptr = preload_search_info(modptr, MODINFO_ADDR); + sizeptr = preload_search_info(modptr, MODINFO_SIZE); + hdr = (Elf_Ehdr *)preload_search_info(modptr, MODINFO_METADATA | + MODINFOMD_ELFHDR); + shdr = (Elf_Shdr *)preload_search_info(modptr, MODINFO_METADATA | + MODINFOMD_SHDR); + if (type == NULL || (strcmp(type, "elf" __XSTRING(__ELF_WORD_SIZE) + " obj module") != 0 && + strcmp(type, "elf obj module") != 0)) { + return (EFTYPE); + } + if (baseptr == NULL || sizeptr == NULL || hdr == NULL || + shdr == NULL) + return (EINVAL); + + lf = linker_make_file(filename, &link_elf_class); + if (lf == NULL) + return (ENOMEM); + + ef = (elf_file_t)lf; + ef->preloaded = 1; + ef->modptr = modptr; + ef->address = *(caddr_t *)baseptr; + lf->address = *(caddr_t *)baseptr; + lf->size = *(size_t *)sizeptr; + + printf("address: %p\n", ef->address); + + printf("hdr: %p\n", hdr); + if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || + hdr->e_ident[EI_DATA] != ELF_TARG_DATA || + hdr->e_ident[EI_VERSION] != EV_CURRENT || + hdr->e_version != EV_CURRENT || + hdr->e_type != ET_REL || + hdr->e_machine != ELF_TARG_MACH) { + error = EFTYPE; + goto out; + } + ef->e_shdr = shdr; + + /* Scan the section header for information and table sizing. */ + symtabindex = -1; + symstrindex = -1; + for (i = 0; i < hdr->e_shnum; i++) { + switch (shdr[i].sh_type) { + case SHT_PROGBITS: + case SHT_NOBITS: + ef->nprogtab++; + break; + case SHT_SYMTAB: + symtabindex = i; + symstrindex = shdr[i].sh_link; + break; + case SHT_REL: + ef->nrel++; + break; + case SHT_RELA: + ef->nrela++; + break; + } + } + + shstrindex = hdr->e_shstrndx; + if (ef->nprogtab == 0 || symstrindex < 0 || + symstrindex >= hdr->e_shnum || + shdr[symstrindex].sh_type != SHT_STRTAB || shstrindex == 0 || + shstrindex >= hdr->e_shnum || + shdr[shstrindex].sh_type != SHT_STRTAB) { + printf("%s: bad/missing section headers\n", filename); + error = ENOEXEC; + goto out; + } + + /* Allocate space for tracking the load chunks */ + if (ef->nprogtab != 0) + ef->progtab = malloc(ef->nprogtab * sizeof(*ef->progtab), + M_LINKER, M_WAITOK | M_ZERO); + if (ef->nrel != 0) + ef->reltab = malloc(ef->nrel * sizeof(*ef->reltab), M_LINKER, + M_WAITOK | M_ZERO); + if (ef->nrela != 0) + ef->relatab = malloc(ef->nrela * sizeof(*ef->relatab), M_LINKER, + M_WAITOK | M_ZERO); + if ((ef->nprogtab != 0 && ef->progtab == NULL) || + (ef->nrel != 0 && ef->reltab == NULL) || + (ef->nrela != 0 && ef->relatab == NULL)) { + error = ENOMEM; + goto out; + } + + /* XXX, relocate the sh_addr fields saved by the loader. */ + off = 0; + for (i = 0; i < hdr->e_shnum; i++) { + if (off == 0 || (shdr[i].sh_addr != 0 && shdr[i].sh_addr < off)) + off = shdr[i].sh_addr; + } + for (i = 0; i < hdr->e_shnum; i++) { + if (shdr[i].sh_addr != 0) + shdr[i].sh_addr = shdr[i].sh_addr - off + + (Elf_Addr)ef->address; + } + + ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); + ef->ddbsymtab = (Elf_Sym *)shdr[symtabindex].sh_addr; + ef->ddbstrcnt = shdr[symstrindex].sh_size; + ef->ddbstrtab = (char *)shdr[symtabindex].sh_addr; + ef->shstrcnt = shdr[shstrindex].sh_size; + ef->shstrtab = (char *)shdr[shstrindex].sh_addr; + + printf("ddbsymcnt %ld ddbsymtab %p, ddbstrcnt %ld ddbstrtab %p\n", + ef->ddbsymcnt, ef->ddbsymtab, ef->ddbstrcnt, ef->ddbstrtab); + printf("shstrcnt %ld shstrtab %p\n", ef->shstrcnt, ef->shstrtab); + + /* Now fill out progtab and the relocation tables. */ + pb = 0; + rl = 0; + ra = 0; + for (i = 0; i < hdr->e_shnum; i++) { + switch (shdr[i].sh_type) { + case SHT_PROGBITS: + case SHT_NOBITS: + ef->progtab[pb].addr = (void *)shdr[i].sh_addr; + if (shdr[i].sh_type == SHT_PROGBITS) + ef->progtab[pb].name = "<>"; + else + ef->progtab[pb].name = "<>"; + ef->progtab[pb].size = shdr[i].sh_size; + ef->progtab[pb].sec = i; + if (ef->shstrtab && shdr[i].sh_name != 0) + ef->progtab[pb].name = + ef->shstrtab + shdr[i].sh_name; + + /* Update all symbol values with the offset. */ + for (j = 0; j < ef->ddbsymcnt; j++) { + es = &ef->ddbsymtab[j]; + if (es->st_shndx != i) + continue; + es->st_value += (Elf_Addr)ef->progtab[pb].addr; + } + pb++; + break; + case SHT_REL: + ef->reltab[rl].rel = (Elf_Rel *)shdr[i].sh_addr; + ef->reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); + ef->reltab[rl].sec = shdr[i].sh_info; + rl++; + break; + case SHT_RELA: + ef->relatab[ra].rela = (Elf_Rela *)shdr[i].sh_addr; + ef->relatab[ra].nrela = + shdr[i].sh_size / sizeof(Elf_Rela); + ef->relatab[ra].sec = shdr[i].sh_info; + ra++; + break; + } + } + if (pb != ef->nprogtab) + panic("lost progbits"); + if (rl != ef->nrel) + panic("lost rel"); + if (ra != ef->nrela) + panic("lost rela"); + + printf("done shdr\n"); + + /* Local intra-module relocations */ + link_elf_reloc_local(lf); + printf("done link_elf_reloc_local\n"); + + *result = lf; + return (0); + +out: /* preload not done this way */ - return (EFTYPE); + linker_file_unload(lf, LINKER_UNLOAD_FORCE); + return (error); } static int link_elf_link_preload_finish(linker_file_t lf) { - /* preload not done this way */ - return (EFTYPE); + elf_file_t ef; + int error; + + printf("link_elf_link_preload_finish\n"); + + ef = (elf_file_t)lf; + error = relocate_file(ef); + if (error) + return error; + + /* Notify MD code that a module is being loaded. */ + error = elf_cpu_load_file(lf); + if (error) + return (error); + + printf("link_elf_link_preload_finish: return 0\n"); + + return (0); } static int @@ -601,11 +811,29 @@ link_elf_unload_file(linker_file_t file) { elf_file_t ef = (elf_file_t) file; + void *sizeptr; + vm_offset_t endp; int i; /* Notify MD code that a module is being unloaded. */ elf_cpu_unload_file(file); + if (ef->preloaded) { + sizeptr = preload_search_info(ef->modptr, MODINFO_SIZE); + endp = (vm_offset_t)*(size_t *)sizeptr + + (vm_offset_t)ef->address; + if (ef->reltab) + free(ef->reltab, M_LINKER); + if (ef->relatab) + free(ef->relatab, M_LINKER); + if (ef->progtab) + free(ef->progtab, M_LINKER); + if (file->filename != NULL) + preload_delete_name(file->filename); + /*vm_map_remove(kernel_map, (vm_offset_t)ef->address, endp);*/ + return; + } + for (i = 0; i < ef->nrel; i++) if (ef->reltab[i].rel) free(ef->reltab[i].rel, M_LINKER); @@ -814,8 +1042,11 @@ void **start, **stop; int i, count; + printf("link_elf_lookup_set: %s\n", name); + /* Relative to section number */ for (i = 0; i < ef->nprogtab; i++) { + printf("link_elf_lookup_set: try %s\n", ef->progtab[i].name); if ((strncmp(ef->progtab[i].name, "set_", 4) == 0) && strcmp(ef->progtab[i].name + 4, name) == 0) { start = (void **)ef->progtab[i].addr; @@ -831,6 +1062,7 @@ return (0); } } + printf("link_elf_lookup_set: not found\n"); return (ESRCH); } Index: boot/common/Makefile.inc =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/boot/common/Makefile.inc,v retrieving revision 1.17 diff -u -r1.17 Makefile.inc --- boot/common/Makefile.inc 7 Feb 2004 11:05:10 -0000 1.17 +++ boot/common/Makefile.inc 16 Aug 2004 01:23:54 -0000 @@ -5,7 +5,7 @@ SRCS+= module.c panic.c .if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" -SRCS+= load_elf32.c load_elf64.c +SRCS+= load_elf32.c load_elf32_obj.c load_elf64.c load_elf64_obj.c .endif .if ${MACHINE_ARCH} == "powerpc" SRCS+= load_elf32.c Index: boot/common/bootstrap.h =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/boot/common/bootstrap.h,v retrieving revision 1.38 diff -u -r1.38 bootstrap.h --- boot/common/bootstrap.h 1 May 2003 03:56:29 -0000 1.38 +++ boot/common/bootstrap.h 16 Aug 2004 01:23:54 -0000 @@ -76,6 +76,9 @@ void hexdump(caddr_t region, size_t len); size_t strlenout(vm_offset_t str); char *strdupout(vm_offset_t str); +void kbzero(vm_offset_t dest, size_t len); +int kpread(int fd, vm_offset_t dest, size_t len, off_t off); +void *preada(int fd, off_t off, size_t len); /* bcache.c */ int bcache_init(u_int nblks, size_t bsize); @@ -233,6 +236,8 @@ /* MI module loaders */ #ifdef __elfN int __elfN(loadfile)(char *filename, u_int64_t dest, struct preloaded_file **result); +int __elfN(obj_loadfile)(char *filename, u_int64_t dest, + struct preloaded_file **result); #endif /* Index: boot/common/load_elf32_obj.c =================================================================== RCS file: boot/common/load_elf32_obj.c diff -N boot/common/load_elf32_obj.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ boot/common/load_elf32_obj.c 16 Aug 2004 01:23:54 -0000 @@ -0,0 +1,6 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 32 + +#include "load_elf_obj.c" Index: boot/common/load_elf64_obj.c =================================================================== RCS file: boot/common/load_elf64_obj.c diff -N boot/common/load_elf64_obj.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ boot/common/load_elf64_obj.c 16 Aug 2004 01:23:54 -0000 @@ -0,0 +1,6 @@ +#include +__FBSDID("$FreeBSD$"); + +#define __ELF_WORD_SIZE 64 + +#include "load_elf_obj.c" Index: boot/common/load_elf_obj.c =================================================================== RCS file: boot/common/load_elf_obj.c diff -N boot/common/load_elf_obj.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ boot/common/load_elf_obj.c 16 Aug 2004 01:23:54 -0000 @@ -0,0 +1,473 @@ +/*- + * Copyright (c) 1998 Michael Smith + * Copyright (c) 1998 Peter Wemm + * 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. + */ + +#include +__FBSDID("$FreeBSD: src/sys/boot/common/load_elf.c,v 1.30 2004/03/11 10:07:24 bde Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#define FREEBSD_ELF +#include + +#include "bootstrap.h" + +#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) + +#if defined(__i386__) && __ELF_WORD_SIZE == 64 +#undef ELF_TARG_CLASS +#undef ELF_TARG_MACH +#define ELF_TARG_CLASS ELFCLASS64 +#define ELF_TARG_MACH EM_X86_64 +#endif + +typedef struct elf_file { + Elf_Ehdr hdr; + Elf_Shdr *e_shdr; + + int shstrindex; /* Index of section name string table */ + + int fd; + vm_offset_t off; +} *elf_file_t; + +static int __elfN(obj_loadimage)(struct preloaded_file *mp, elf_file_t ef, + u_int64_t loadaddr); +static int __elfN(obj_lookup_set)(struct preloaded_file *mp, elf_file_t ef, + const char *name, Elf_Addr *startp, Elf_Addr *stopp, int *countp); +#ifdef __sparc__ +static void __elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, + void *p, void *val, size_t len); +#endif +static int __elfN(obj_parse_modmetadata)(struct preloaded_file *mp, + elf_file_t ef); + +const char *__elfN(obj_kerneltype) = "elf kernel"; +const char *__elfN(obj_moduletype) = "elf obj module"; + +/* + * Attempt to load the file (file) as an ELF module. It will be stored at + * (dest), and a pointer to a module structure describing the loaded object + * will be saved in (result). + */ +int +__elfN(obj_loadfile)(char *filename, u_int64_t dest, + struct preloaded_file **result) +{ + struct preloaded_file *fp, *kfp; + struct elf_file ef; + Elf_Ehdr *hdr; + int err; + ssize_t bytes_read; + + fp = NULL; + bzero(&ef, sizeof(struct elf_file)); + + /* + * Open the image, read and validate the ELF header + */ + if (filename == NULL) /* can't handle nameless */ + return(EFTYPE); + if ((ef.fd = open(filename, O_RDONLY)) == -1) + return(errno); + + hdr = &ef.hdr; + bytes_read = read(ef.fd, hdr, sizeof(*hdr)); + if (bytes_read != sizeof(*hdr)) { + err = EFTYPE; /* could be EIO, but may be small file */ + goto oerr; + } + + /* Is it ELF? */ + if (!IS_ELF(*hdr)) { + err = EFTYPE; + goto oerr; + } + if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ + hdr->e_ident[EI_DATA] != ELF_TARG_DATA || + hdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ + hdr->e_version != EV_CURRENT || + hdr->e_machine != ELF_TARG_MACH || /* Machine ? */ + hdr->e_type != ET_REL) { + err = EFTYPE; + goto oerr; + } + + if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 || + hdr->e_shentsize != sizeof(Elf_Shdr)) { + err = EFTYPE; + goto oerr; + } + + kfp = file_findfile(NULL, NULL); + if (kfp == NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadfile: can't load module before kernel\n"); + err = EPERM; + goto oerr; + } + if (strcmp(__elfN(obj_kerneltype), kfp->f_type)) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadfile: can't load module with kernel type '%s'\n", + kfp->f_type); + err = EPERM; + goto oerr; + } + + /* Page-align the load address */ + dest = roundup(dest, PAGE_SIZE); + + /* + * Ok, we think we should handle this. + */ + fp = file_alloc(); + if (fp == NULL) { + printf("elf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadfile: cannot allocate module info\n"); + err = EPERM; + goto out; + } + fp->f_name = strdup(filename); + fp->f_type = strdup(__elfN(obj_moduletype)); + + printf("%s ", filename); + + fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest); + if (fp->f_size == 0 || fp->f_addr == 0) + goto ioerr; + + /* save exec header as metadata */ + file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr); + + /* Load OK, return module pointer */ + *result = (struct preloaded_file *)fp; + err = 0; + goto out; + +ioerr: + err = EIO; +oerr: + file_discard(fp); +out: + close(ef.fd); + if (ef.e_shdr != NULL) + free(ef.e_shdr); + + return(err); +} + +/* + * With the file (fd) open on the image, and (ehdr) containing + * the Elf header, load the image at (off) + */ +static int +__elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) +{ + Elf_Ehdr *hdr; + Elf_Shdr *shdr; + vm_offset_t firstaddr, lastaddr; + int i, nsym, res, ret, shdrbytes, symstrindex, symtabindex; + + ret = 0; + firstaddr = lastaddr = (vm_offset_t)off; + hdr = &ef->hdr; + ef->off = (vm_offset_t)off; + + /* Read in the section headers. */ + shdrbytes = hdr->e_shnum * hdr->e_shentsize; + shdr = preada(ef->fd, (off_t)hdr->e_shoff, shdrbytes); + if (shdr == NULL) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: read section headers failed\n"); + goto out; + } + ef->e_shdr = shdr; + + /* + * Decide where to load everything, but don't read it yet. + * We store the load address as a non-zero sh_addr value. + * Start with the code/data and bss. + */ + for (i = 0; i < hdr->e_shnum; i++) + shdr[i].sh_addr = 0; + for (i = 0; i < hdr->e_shnum; i++) { + switch (shdr[i].sh_type) { + case SHT_PROGBITS: + case SHT_NOBITS: + lastaddr = roundup(lastaddr, shdr[i].sh_addralign); + /* Might as well clear the bss now. */ + if (shdr[i].sh_type == SHT_NOBITS) { + kbzero(lastaddr, shdr[i].sh_size); + } else { + shdr[i].sh_addr = (Elf_Addr)lastaddr; + } + lastaddr += shdr[i].sh_size; + break; + } + } + + /* Symbols. */ + nsym = 0; + symtabindex = 0; + for (i = 0; i < hdr->e_shnum; i++) { + switch (shdr[i].sh_type) { + case SHT_SYMTAB: + nsym++; + symtabindex = i; + shdr[i].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[i].sh_size; + break; + } + } + if (nsym != 1) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: file has no valid symbol table\n"); + goto out; + } + lastaddr = roundup(lastaddr, shdr[symtabindex].sh_addralign); + shdr[symtabindex].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[symtabindex].sh_size; + + symstrindex = shdr[symtabindex].sh_link; + if (symstrindex < 0 || symstrindex >= hdr->e_shnum || + shdr[symstrindex].sh_type != SHT_STRTAB) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: file has invalid symbol strings\n"); + goto out; + } + lastaddr = roundup(lastaddr, shdr[symstrindex].sh_addralign); + shdr[symstrindex].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[symstrindex].sh_size; + + /* Section names. */ + if (hdr->e_shstrndx == 0 || hdr->e_shstrndx >= hdr->e_shnum || + shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: file has no section names\n"); + goto out; + } + ef->shstrindex = hdr->e_shstrndx; + lastaddr = roundup(lastaddr, shdr[ef->shstrindex].sh_addralign); + shdr[ef->shstrindex].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[ef->shstrindex].sh_size; + + /* Relocation tables. */ + for (i = 0; i < hdr->e_shnum; i++) { + switch (shdr[i].sh_type) { + case SHT_REL: + case SHT_RELA: + lastaddr = roundup(lastaddr, shdr[i].sh_addralign); + shdr[i].sh_addr = (Elf_Addr)lastaddr; + lastaddr += shdr[i].sh_size; + break; + } + } + + /* Now read it all in. */ + for (i = 0; i < hdr->e_shnum; i++) { + if (shdr[i].sh_addr == 0) + continue; + if (kpread(ef->fd, (vm_offset_t)shdr[i].sh_addr, + shdr[i].sh_size, (off_t)shdr[i].sh_offset) != 0) { + printf("\nelf" __XSTRING(__ELF_WORD_SIZE) + "_obj_loadimage: read failed\n"); + goto out; + } + } + + file_addmetadata(fp, MODINFOMD_SHDR, shdrbytes, shdr); + + res = __elfN(obj_parse_modmetadata)(fp, ef); + if (res != 0) + goto out; + + ret = lastaddr - firstaddr; + fp->f_addr = firstaddr; + printf("[0x%jx@0x%jx]", (uintmax_t)ret, (uintmax_t)fp->f_addr); + +out: + printf("\n"); + return ret; +} + +#if defined(__i386__) && __ELF_WORD_SIZE == 64 +struct mod_metadata64 { + int md_version; /* structure version MDTV_* */ + int md_type; /* type of entry MDT_* */ + u_int64_t md_data; /* specific data */ + u_int64_t md_cval; /* common string label */ +}; +#endif + +int +__elfN(obj_parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef) +{ + struct mod_metadata md; +#if defined(__i386__) && __ELF_WORD_SIZE == 64 + struct mod_metadata64 md64; +#endif + struct mod_depend *mdepend; + struct mod_version mver; + char *s; + int modcnt, minfolen; + Elf_Addr v, p, p_stop; + + if (__elfN(obj_lookup_set)(fp, ef, "modmetadata_set", &p, &p_stop, + &modcnt) != 0) + return ENOENT; + + modcnt = 0; + while (p < p_stop) { + COPYOUT(p, &v, sizeof(v)); +#ifdef __sparc64__ + __elfN(obj_reloc_ptr)(fp, ef, p, &v, sizeof(v)); +#else + v += ef->off; +#endif +#if defined(__i386__) && __ELF_WORD_SIZE == 64 + COPYOUT(v, &md64, sizeof(md64)); + md.md_version = md64.md_version; + md.md_type = md64.md_type; + md.md_cval = (const char *)(uintptr_t)(md64.md_cval + ef->off); + md.md_data = (void *)(uintptr_t)(md64.md_data + ef->off); +#else + COPYOUT(v, &md, sizeof(md)); +#ifdef __sparc64__ + __elfN(obj_reloc_ptr)(fp, ef, v, &md, sizeof(md)); +#else + md.md_cval += ef->off; + md.md_data += ef->off; +#endif +#endif + p += sizeof(Elf_Addr); + switch(md.md_type) { + case MDT_DEPEND: + s = strdupout((vm_offset_t)md.md_cval); + minfolen = sizeof(*mdepend) + strlen(s) + 1; + mdepend = malloc(minfolen); + if (mdepend == NULL) + return ENOMEM; + COPYOUT((vm_offset_t)md.md_data, mdepend, + sizeof(*mdepend)); + strcpy((char*)(mdepend + 1), s); + free(s); + file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen, + mdepend); + free(mdepend); + break; + case MDT_VERSION: + s = strdupout((vm_offset_t)md.md_cval); + COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver)); + file_addmodule(fp, s, mver.mv_version, NULL); + free(s); + modcnt++; + break; + } + } + return 0; +} + +static int +__elfN(obj_lookup_set)(struct preloaded_file *fp, elf_file_t ef, + const char* name, Elf_Addr *startp, Elf_Addr *stopp, int *countp) +{ + Elf_Ehdr *hdr; + Elf_Shdr *shdr; + char *p; + vm_offset_t shstrtab; + int i; + + hdr = &ef->hdr; + shdr = ef->e_shdr; + shstrtab = shdr[ef->shstrindex].sh_addr; + + for (i = 0; i < hdr->e_shnum; i++) { + if (shdr[i].sh_type != SHT_PROGBITS) + continue; + if (shdr[i].sh_name == 0) + continue; + p = strdupout(shstrtab + shdr[i].sh_name); + if (strncmp(p, "set_", 4) == 0 && strcmp(p + 4, name) == 0) { + *startp = shdr[i].sh_addr; + *stopp = shdr[i].sh_addr + shdr[i].sh_size; + *countp = (*stopp - *startp) / sizeof(Elf_Addr); + free(p); + return (0); + } + free(p); + } + + return (ESRCH); +} + +#ifdef __sparc__ +/* + * Apply any intra-module relocations to the value. *p is the load address + * of the value and val/len is the value to be modified. This does NOT modify + * the image in-place, because this is done by kern_linker later on. + */ +static void +__elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, + void *p, void *val, size_t len) +{ + Elf_Ehdr *hdr; + Elf_Shdr *shdr; + Elf_Addr off = (Elf_Addr)p, word; + Elf_Addr base; + Elf_Rela r, *rbase; + int i, j, nrela; + + hdr = &ef->hdr; + shdr = ef->e_shdr; + + for (i = 0; i < hdr->e_shnum; i++) { + if (shdr[i].sh_type != SHT_RELA) + continue; + rbase = (Elf_Rela *)shdr[i].sh_addr; + base = shdr[shdr[i].sh_info].sh_addr; + if (base == 0 || rbase == NULL) + continue; + nrela = shdr[i].sh_size / sizeof(Elf_Rela); + for (j = 0; j < nrela; j++) { + COPYOUT(rbase + j, &r, sizeof(r)); + + if (r.r_offset + base >= off && + r.r_offset + base < off + len && + ELF_R_TYPE(r.r_info) == R_SPARC_RELATIVE) { + word = base + r.r_addend; + bcopy(&word, (char *)val + (r.r_offset + base - + off), sizeof(word)); + } + } + } +} +#endif Index: boot/common/misc.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/boot/common/misc.c,v retrieving revision 1.8 diff -u -r1.8 misc.c --- boot/common/misc.c 25 Aug 2003 23:30:41 -0000 1.8 +++ boot/common/misc.c 16 Aug 2004 01:23:54 -0000 @@ -27,6 +27,8 @@ #include __FBSDID("$FreeBSD: src/sys/boot/common/misc.c,v 1.8 2003/08/25 23:30:41 obrien Exp $"); +#include +#include #include #include #include @@ -91,6 +93,77 @@ break; } return(result); +} + +/* Zero a region in kernel space. */ +void +kbzero(vm_offset_t dest, size_t len) +{ + char failbuf[128]; + void *buf; + size_t bufsize, chunk, resid; + + bufsize = PAGE_SIZE; + buf = malloc(bufsize); + if (buf == NULL) { + /* XXX, can't fail. */ + buf = failbuf; + bufsize = sizeof(failbuf); + } + bzero(buf, bufsize); + resid = len; + while (resid > 0) { + chunk = min(bufsize, resid); + archsw.arch_copyin(buf, dest, chunk); + resid -= chunk; + dest += chunk; + } + if (buf != (void *)failbuf) + free(buf); +} + +/* Read the specified part of a file to kernel space. */ +int +kpread(int fd, vm_offset_t dest, size_t len, off_t off) +{ + ssize_t nread; + + if (lseek(fd, off, SEEK_SET) == -1) { + printf("\nlseek failed\n"); + return (-1); + } + nread = archsw.arch_readin(fd, dest, len); + if (nread != len) { + printf("\nreadin failed\n"); + return (-1); + } + return (0); +} + +/* Read the specified part of a file to a malloced buffer. */ +void * +preada(int fd, off_t off, size_t len) +{ + void *buf; + ssize_t nread; + + buf = malloc(len); + if (buf == NULL) { + printf("\nmalloc(%d) failed\n", (int)len); + return (NULL); + } + if (lseek(fd, off, SEEK_SET) == -1) { + printf("\nlseek failed\n"); + free(buf); + return (NULL); + } + nread = read(fd, buf, len); + if (nread != len) { + printf("\nread failed\n"); + free(buf); + return (NULL); + } + return (buf); } /* Index: boot/i386/libi386/elf32_freebsd.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/boot/i386/libi386/elf32_freebsd.c,v retrieving revision 1.13 diff -u -r1.13 elf32_freebsd.c --- boot/i386/libi386/elf32_freebsd.c 25 Aug 2003 23:28:31 -0000 1.13 +++ boot/i386/libi386/elf32_freebsd.c 16 Aug 2004 01:23:54 -0000 @@ -40,8 +40,10 @@ #include "btxv86.h" static int elf32_exec(struct preloaded_file *amp); +static int elf32_obj_exec(struct preloaded_file *amp); struct file_format i386_elf = { elf32_loadfile, elf32_exec }; +struct file_format i386_elf_obj = { elf32_obj_loadfile, elf32_obj_exec }; /* * There is an a.out kernel and one or more a.out modules loaded. @@ -73,4 +75,10 @@ __exec((void *)entry, boothowto, bootdev, 0, 0, 0, bootinfop, modulep, kernend); panic("exec returned"); +} + +static int +elf32_obj_exec(struct preloaded_file *fp) +{ + return (EFTYPE); } Index: boot/i386/libi386/elf64_freebsd.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/boot/i386/libi386/elf64_freebsd.c,v retrieving revision 1.14 diff -u -r1.14 elf64_freebsd.c --- boot/i386/libi386/elf64_freebsd.c 25 Aug 2003 23:28:31 -0000 1.14 +++ boot/i386/libi386/elf64_freebsd.c 16 Aug 2004 01:23:54 -0000 @@ -41,8 +41,10 @@ #include "btxv86.h" static int elf64_exec(struct preloaded_file *amp); +static int elf64_obj_exec(struct preloaded_file *amp); struct file_format amd64_elf = { elf64_loadfile, elf64_exec }; +struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; #define PG_V 0x001 #define PG_RW 0x002 @@ -115,4 +117,10 @@ __exec((void *)VTOP(amd64_tramp), modulep, kernend); panic("exec returned"); +} + +static int +elf64_obj_exec(struct preloaded_file *fp) +{ + return (EFTYPE); } Index: boot/i386/loader/conf.c =================================================================== RCS file: /dump/FreeBSD-CVS/src/sys/boot/i386/loader/conf.c,v retrieving revision 1.24 diff -u -r1.24 conf.c --- boot/i386/loader/conf.c 25 Aug 2003 23:28:32 -0000 1.24 +++ boot/i386/loader/conf.c 16 Aug 2004 01:23:54 -0000 @@ -83,11 +83,15 @@ * rather than reading the file go first. */ extern struct file_format i386_elf; +extern struct file_format i386_elf_obj; extern struct file_format amd64_elf; +extern struct file_format amd64_elf_obj; struct file_format *file_formats[] = { &i386_elf, + &i386_elf_obj, &amd64_elf, + &amd64_elf_obj, NULL };