diff options
Diffstat (limited to 'sys/boot/common/load_elf.c')
-rw-r--r-- | sys/boot/common/load_elf.c | 113 |
1 files changed, 58 insertions, 55 deletions
diff --git a/sys/boot/common/load_elf.c b/sys/boot/common/load_elf.c index ff1f50638ac8a..b2b38c7800b65 100644 --- a/sys/boot/common/load_elf.c +++ b/sys/boot/common/load_elf.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: load_elf.c,v 1.9 1998/10/17 03:06:38 peter Exp $ + * $Id: load_elf.c,v 1.7 1998/10/15 21:56:47 dfr Exp $ */ #include <sys/param.h> @@ -40,7 +40,7 @@ #include "bootstrap.h" -static int elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t loadaddr, Elf_Ehdr *ehdr, int kernel, caddr_t firstpage, int firstlen); +static int elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t loadaddr, Elf_Ehdr *ehdr, Elf_Phdr *phdr, int kernel); char *elf_kerneltype = "elf kernel"; char *elf_moduletype = "elf module"; @@ -54,15 +54,15 @@ int elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) { struct loaded_module *mp, *kmp; - Elf_Ehdr *ehdr; + Elf_Ehdr ehdr; + Elf_Phdr *phdr; int fd; int err, kernel; u_int pad; char *s; - caddr_t firstpage; - int firstlen; mp = NULL; + phdr = NULL; /* * Open the image, read and validate the ELF header @@ -71,26 +71,21 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) return(EFTYPE); if ((fd = open(filename, O_RDONLY)) == -1) return(errno); - firstpage = malloc(PAGE_SIZE); - if (firstpage == NULL) - return(ENOMEM); - firstlen = read(fd, firstpage, PAGE_SIZE); - if (firstlen <= sizeof(ehdr)) { + if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) { err = EFTYPE; /* could be EIO, but may be small file */ goto oerr; } - ehdr = (Elf_Ehdr *)firstpage; /* Is it ELF? */ - if (!IS_ELF(*ehdr)) { + if (!IS_ELF(ehdr)) { err = EFTYPE; goto oerr; } - if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ - ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || - ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ - ehdr->e_version != EV_CURRENT || - ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */ + if (ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ + ehdr.e_ident[EI_DATA] != ELF_TARG_DATA || + ehdr.e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ + ehdr.e_version != EV_CURRENT || + ehdr.e_machine != ELF_TARG_MACH) { /* Machine ? */ err = EFTYPE; goto oerr; } @@ -100,7 +95,7 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) * Check to see what sort of module we are. */ kmp = mod_findmodule(NULL, NULL); - if (ehdr->e_type == ET_DYN) { + if (ehdr.e_type == ET_DYN) { /* Looks like a kld module */ if (kmp == NULL) { printf("elf_loadmodule: can't load module before kernel\n"); @@ -121,7 +116,7 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) pad = PAGE_SIZE - pad; dest += pad; } - } else if (ehdr->e_type == ET_EXEC) { + } else if (ehdr.e_type == ET_EXEC) { /* Looks like a kernel */ if (kmp != NULL) { printf("elf_loadmodule: kernel already loaded\n"); @@ -131,7 +126,7 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) /* * Calculate destination address based on kernel entrypoint */ - dest = (vm_offset_t) ehdr->e_entry; + dest = (vm_offset_t) ehdr.e_entry; if (dest == 0) { printf("elf_loadmodule: not a kernel (maybe static binary?)\n"); err = EPERM; @@ -169,12 +164,36 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) printf("%s ", filename); #endif - mp->m_size = elf_loadimage(mp, fd, dest, ehdr, kernel, firstpage, firstlen); + phdr = malloc(ehdr.e_phnum * sizeof(*phdr)); + if (phdr == NULL) { + err = ENOMEM; + goto out; + } + + if (lseek(fd, ehdr.e_phoff, SEEK_SET) == -1) { + printf("elf_loadexec: lseek for phdr failed\n"); + goto ioerr; + } + if (read(fd, phdr, ehdr.e_phnum * sizeof(*phdr)) != + ehdr.e_phnum * sizeof(*phdr)) { + printf("elf_loadmodule: cannot read program header\n"); + goto ioerr; + } + if (lseek(fd, 0, SEEK_SET) == -1) { + close(fd); + if ((fd = open(filename, O_RDONLY)) == -1) { + printf("elf_loadmodule: cannot reset file position\n"); + mod_discard(mp); + return errno; + } + } + + mp->m_size = elf_loadimage(mp, fd, dest, &ehdr, phdr, kernel); if (mp->m_size == 0 || mp->m_addr == 0) goto ioerr; /* save exec header as metadata */ - mod_addmetadata(mp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); + mod_addmetadata(mp, MODINFOMD_ELFHDR, sizeof(ehdr), &ehdr); /* Load OK, return module pointer */ *result = (struct loaded_module *)mp; @@ -186,8 +205,8 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) oerr: mod_discard(mp); out: - if (firstpage) - free(firstpage); + if (phdr) + free(phdr); close(fd); return(err); } @@ -198,10 +217,9 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) */ static int elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off, - Elf_Ehdr *ehdr, int kernel, caddr_t firstpage, int firstlen) + Elf_Ehdr *ehdr, Elf_Phdr *phdr, int kernel) { int i, j; - Elf_Phdr *phdr; Elf_Shdr *shdr; int ret; vm_offset_t firstaddr; @@ -221,7 +239,6 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off, int symstrindex; int symtabindex; long size; - int fpcopy; dp = NULL; shdr = NULL; @@ -235,12 +252,6 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off, #endif } - if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > firstlen) { - printf("elf_loadimage: program header not within first page\n"); - goto out; - } - phdr = (Elf_Phdr *)(firstpage + ehdr->e_phoff); - for (i = 0; i < ehdr->e_phnum; i++) { /* We want to load PT_LOAD segments only.. */ if (phdr[i].p_type != PT_LOAD) @@ -261,22 +272,15 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off, printf(" "); } #endif - fpcopy = 0; - if (firstlen > phdr[i].p_offset) { - fpcopy = firstlen - phdr[i].p_offset; - archsw.arch_copyin(firstpage + phdr[i].p_offset, - phdr[i].p_vaddr + off, fpcopy); + + if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1) { + printf("\nelf_loadexec: cannot seek\n"); + goto out; } - if (phdr[i].p_filesz > fpcopy) { - if (lseek(fd, phdr[i].p_offset + fpcopy, SEEK_SET) == -1) { - printf("\nelf_loadexec: cannot seek\n"); - goto out; - } - if (archsw.arch_readin(fd, phdr[i].p_vaddr + off + fpcopy, - phdr[i].p_filesz - fpcopy) != phdr[i].p_filesz - fpcopy) { - printf("\nelf_loadexec: archsw.readin failed\n"); - goto out; - } + if (archsw.arch_readin(fd, phdr[i].p_vaddr + off, phdr[i].p_filesz) != + phdr[i].p_filesz) { + printf("\nelf_loadexec: archsw.readin failed\n"); + goto out; } /* clear space from oversized segments; eg: bss */ if (phdr[i].p_filesz < phdr[i].p_memsz) { @@ -323,11 +327,11 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off, if (shdr == NULL) goto nosyms; if (lseek(fd, ehdr->e_shoff, SEEK_SET) == -1) { - printf("\nelf_loadimage: cannot lseek() to section headers"); + printf("\nelf_loadimage: cannot lseek() to section headers\n"); goto nosyms; } if (read(fd, shdr, chunk) != chunk) { - printf("\nelf_loadimage: read section headers failed"); + printf("\nelf_loadimage: read section headers failed\n"); goto nosyms; } symtabindex = -1; @@ -382,7 +386,7 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off, lastaddr += sizeof(long); #ifdef ELF_VERBOSE - printf("\n%s: 0x%lx@0x%lx -> 0x%lx-0x%lx", secname, + printf("%s: 0x%lx@0x%lx -> 0x%lx-0x%lx\n", secname, shdr[i].sh_size, shdr[i].sh_offset, lastaddr, lastaddr + shdr[i].sh_size); #else @@ -392,14 +396,14 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off, #endif if (lseek(fd, shdr[i].sh_offset, SEEK_SET) == -1) { - printf("\nelf_loadimage: could not seek for symbols - skipped!"); + printf("\nelf_loadimage: could not seek for symbols - skipped!\n"); lastaddr = ssym; ssym = 0; goto nosyms; } if (archsw.arch_readin(fd, lastaddr, shdr[i].sh_size) != shdr[i].sh_size) { - printf("\nelf_loadimage: could not read symbols - skipped!"); + printf("\nelf_loadimage: could not read symbols - skipped!\n"); lastaddr = ssym; ssym = 0; goto nosyms; @@ -414,14 +418,13 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off, } esym = lastaddr; #ifndef ELF_VERBOSE - printf("]"); + printf("]\n"); #endif mod_addmetadata(mp, MODINFOMD_SSYM, sizeof(ssym), &ssym); mod_addmetadata(mp, MODINFOMD_ESYM, sizeof(esym), &esym); nosyms: - printf("\n"); ret = lastaddr - firstaddr; mp->m_addr = firstaddr; |