diff options
author | peter <peter@FreeBSD.org> | 1998-10-09 23:18:43 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1998-10-09 23:18:43 +0000 |
commit | 591c24c54274d56f722f9671720fd147c1edd9fe (patch) | |
tree | bbd939f93a78d1e902e00aa29d3eed20635882d3 /sys/boot/common/load_elf.c | |
parent | 1ee0daa7acf1e30ee9c3c8c7fa15e960a150cea9 (diff) | |
download | FreeBSD-src-591c24c54274d56f722f9671720fd147c1edd9fe.zip FreeBSD-src-591c24c54274d56f722f9671720fd147c1edd9fe.tar.gz |
Implement preloading for elf modules
- get dependency info from PT_DYNAMIC's DT_NEEDED tags.
- store MODINFOMD_DYNAMIC for the kernel's later use
setenv kernelname when we have it
Fix firstaddr/lastaddr calculation (duh! :-)
Explicitly skip string table with section names in it.
Diffstat (limited to 'sys/boot/common/load_elf.c')
-rw-r--r-- | sys/boot/common/load_elf.c | 162 |
1 files changed, 129 insertions, 33 deletions
diff --git a/sys/boot/common/load_elf.c b/sys/boot/common/load_elf.c index 42a1573..057e76f 100644 --- a/sys/boot/common/load_elf.c +++ b/sys/boot/common/load_elf.c @@ -24,12 +24,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: load_elf.c,v 1.1 1998/09/30 19:38:26 peter Exp $ + * $Id: load_elf.c,v 1.2 1998/10/02 08:04:56 peter Exp $ */ #include <sys/param.h> #include <sys/exec.h> #include <sys/reboot.h> +#include <sys/linker.h> #include <string.h> #include <machine/bootinfo.h> #include <machine/elf.h> @@ -39,11 +40,7 @@ #include "bootstrap.h" -static int elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t *loadaddr, Elf_Ehdr *ehdr, int kernel); -#if 0 -static vm_offset_t elf_findkldident(struct loaded_module *mp, Elf_Ehdr *ehdr); -static int elf_fixupkldmod(struct loaded_module *mp, Elf_Ehdr *ehdr); -#endif +static int elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t loadaddr, Elf_Ehdr *ehdr, int kernel); char *elf_kerneltype = "elf kernel"; char *elf_moduletype = "elf module"; @@ -59,9 +56,9 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) struct loaded_module *mp, *kmp; Elf_Ehdr ehdr; int fd; - vm_offset_t addr; int err, kernel; u_int pad; + char *s; mp = NULL; @@ -112,11 +109,10 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) kernel = 0; /* Page-align the load address */ - addr = dest; - pad = (u_int)addr & PAGE_MASK; + pad = (u_int)dest & PAGE_MASK; if (pad != 0) { pad = PAGE_SIZE - pad; - addr += pad; + dest += pad; } } else if (ehdr.e_type == ET_EXEC) { /* Looks like a kernel */ @@ -136,7 +132,6 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) } kernel = 1; - addr = dest; } else { err = EFTYPE; goto oerr; @@ -146,22 +141,25 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) * Ok, we think we should handle this. */ mp = mod_allocmodule(); + if (mp == NULL) { + printf("elf_loadmodule: cannot allocate module info\n"); + err = EPERM; + goto out; + } if (kernel) - mp->m_name = strdup(filename); /* XXX should we prune the name? */ + setenv("kernelname", filename, 1); + s = strrchr(filename, '/'); + if (s) + mp->m_name = strdup(s + 1); + else + mp->m_name = strdup(filename); mp->m_type = strdup(kernel ? elf_kerneltype : elf_moduletype); - printf("%s at %p\n", filename, (void *) addr); + printf("%s entry at %p\n", filename, (void *) dest); - mp->m_size = elf_loadimage(mp, fd, &addr, &ehdr, kernel); - if (mp->m_size == 0) + mp->m_size = elf_loadimage(mp, fd, dest, &ehdr, kernel); + if (mp->m_size == 0 || mp->m_addr == 0) goto ioerr; - mp->m_addr = addr; /* save the aligned load address */ - -#if 0 - /* Handle KLD module data */ - if (!kernel && ((err = elf_fixupkldmod(mp, &ehdr)) != 0)) - goto oerr; -#endif /* save exec header as metadata */ mod_addmetadata(mp, MODINFOMD_ELFHDR, sizeof(ehdr), &ehdr); @@ -182,10 +180,10 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result) /* * With the file (fd) open on the image, and (ehdr) containing - * the Elf header, load the image at (addr) + * the Elf header, load the image at (off) */ static int -elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t *addr, +elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t off, Elf_Ehdr *ehdr, int kernel) { int i, j; @@ -195,24 +193,32 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t *addr, int ret; vm_offset_t firstaddr; vm_offset_t lastaddr; - vm_offset_t off; void *buf; size_t resid, chunk; vm_offset_t dest; char *secname; vm_offset_t shdrpos; vm_offset_t ssym, esym; + Elf_Dyn *dp; + int ndp; + int deplen; + char *depdata; + char *s; + int len; + char *strtab; + size_t strsz; + dp = NULL; + shdr = NULL; ret = 0; firstaddr = lastaddr = 0; - if (kernel) + if (kernel) { #ifdef __i386__ off = 0x10000000; /* -0xf0000000 - i386 relocates after locore */ #else off = 0; /* alpha is direct mapped for kernels */ #endif - else - off = *addr; /* load relative to passed address */ + } phdr = malloc(ehdr->e_phnum * sizeof(*phdr)); if (phdr == NULL) @@ -268,9 +274,9 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t *addr, } printf("\n"); - if (firstaddr < (phdr[i].p_vaddr + off)) + if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) firstaddr = phdr[i].p_vaddr + off; - if (lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz)) + if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz)) lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz; } @@ -314,6 +320,9 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t *addr, lastaddr += chunk; lastaddr = roundup(lastaddr, sizeof(long)); for (i = 0; i < ehdr->e_shnum; i++) { + /* Explicitly skip string table for section names */ + if (i == ehdr->e_shstrndx) + continue; switch(shdr[i].sh_type) { /* * These are the symbol tables. Their names are relative to @@ -375,14 +384,101 @@ elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t *addr, archsw.arch_copyin(shdr, lastaddr, sizeof(*ehdr)); esym = lastaddr; - mod_addmetadata(mp, MODINFOMD_ELFSSYM, sizeof(ssym), &ssym); - mod_addmetadata(mp, MODINFOMD_ELFESYM, sizeof(esym), &esym); + mod_addmetadata(mp, MODINFOMD_SSYM, sizeof(ssym), &ssym); + mod_addmetadata(mp, MODINFOMD_ESYM, sizeof(esym), &esym); nosyms: ret = lastaddr - firstaddr; - *addr = firstaddr; + mp->m_addr = firstaddr; + + for (i = 0; i < ehdr->e_phnum; i++) { + if (phdr[i].p_type == PT_DYNAMIC) { + dp = (Elf_Dyn *)(phdr[i].p_vaddr); + mod_addmetadata(mp, MODINFOMD_DYNAMIC, sizeof(dp), &dp); + dp = NULL; + break; + } + } + + if (kernel) /* kernel must not depend on anything */ + goto out; + + ndp = 0; + for (i = 0; i < ehdr->e_phnum; i++) { + if (phdr[i].p_type == PT_DYNAMIC) { + ndp = phdr[i].p_filesz / sizeof(Elf_Dyn); + dp = malloc(phdr[i].p_filesz); + archsw.arch_copyout(phdr[i].p_vaddr + off, dp, phdr[i].p_filesz); + } + } + if (dp == NULL || ndp == 0) + goto out; + strtab = NULL; + strsz = 0; + deplen = 0; + for (i = 0; i < ndp; i++) { + if (dp[i].d_tag == NULL) + break; + switch (dp[i].d_tag) { + case DT_STRTAB: + strtab = (char *)(dp[i].d_un.d_ptr + off); + break; + case DT_STRSZ: + strsz = dp[i].d_un.d_val; + break; + default: + break; + } + } + if (strtab == NULL || strsz == 0) + goto out; + + deplen = 0; + for (i = 0; i < ndp; i++) { + if (dp[i].d_tag == NULL) + break; + switch (dp[i].d_tag) { + case DT_NEEDED: /* count size for dependency list */ + j = dp[i].d_un.d_ptr; + if (j < 1 || j > (strsz - 2)) + continue; /* bad symbol name index */ + deplen += strlenout((vm_offset_t)&strtab[j]) + 1; + break; + default: + break; + } + } + + if (deplen > 0) { + depdata = malloc(deplen); + if (depdata == NULL) + goto out; + s = depdata; + for (i = 0; i < ndp; i++) { + if (dp[i].d_tag == NULL) + break; + switch (dp[i].d_tag) { + case DT_NEEDED: /* dependency list */ + j = dp[i].d_un.d_ptr; + len = strlenout((vm_offset_t)&strtab[j]) + 1; + archsw.arch_copyout((vm_offset_t)&strtab[j], s, len); + s += len; + break; + default: + break; + } + } + if ((s - depdata) > 0) + mod_addmetadata(mp, MODINFOMD_DEPLIST, s - depdata, depdata); + free(depdata); + } + out: + if (dp) + free(dp); + if (shdr) + free(shdr); if (phdr) free(phdr); return ret; |