123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- #include <types.h>
- #include <kern/errno.h>
- #include <lib.h>
- #include <uio.h>
- #include <proc.h>
- #include <current.h>
- #include <addrspace.h>
- #include <vnode.h>
- #include <elf.h>
- static
- int
- load_segment(struct addrspace *as, struct vnode *v,
- off_t offset, vaddr_t vaddr,
- size_t memsize, size_t filesize,
- int is_executable)
- {
- struct iovec iov;
- struct uio u;
- int result;
- if (filesize > memsize) {
- kprintf("ELF: warning: segment filesize > segment memsize\n");
- filesize = memsize;
- }
- DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n",
- (unsigned long) filesize, (unsigned long) vaddr);
- iov.iov_ubase = (userptr_t)vaddr;
- iov.iov_len = memsize;
- u.uio_iov = &iov;
- u.uio_iovcnt = 1;
- u.uio_resid = filesize;
- u.uio_offset = offset;
- u.uio_segflg = is_executable ? UIO_USERISPACE : UIO_USERSPACE;
- u.uio_rw = UIO_READ;
- u.uio_space = as;
- result = VOP_READ(v, &u);
- if (result) {
- return result;
- }
- if (u.uio_resid != 0) {
-
- kprintf("ELF: short read on segment - file truncated?\n");
- return ENOEXEC;
- }
-
- #if 0
- {
- size_t fillamt;
- fillamt = memsize - filesize;
- if (fillamt > 0) {
- DEBUG(DB_EXEC, "ELF: Zero-filling %lu more bytes\n",
- (unsigned long) fillamt);
- u.uio_resid += fillamt;
- result = uiomovezeros(fillamt, &u);
- }
- }
- #endif
-
- return result;
- }
- int
- load_elf(struct vnode *v, vaddr_t *entrypoint)
- {
- Elf_Ehdr eh;
- Elf_Phdr ph;
- int result, i;
- struct iovec iov;
- struct uio ku;
- struct addrspace *as;
- as = curproc_getas();
-
- uio_kinit(&iov, &ku, &eh, sizeof(eh), 0, UIO_READ);
- result = VOP_READ(v, &ku);
- if (result) {
- return result;
- }
- if (ku.uio_resid != 0) {
-
- kprintf("ELF: short read on header - file truncated?\n");
- return ENOEXEC;
- }
-
- if (eh.e_ident[EI_MAG0] != ELFMAG0 ||
- eh.e_ident[EI_MAG1] != ELFMAG1 ||
- eh.e_ident[EI_MAG2] != ELFMAG2 ||
- eh.e_ident[EI_MAG3] != ELFMAG3 ||
- eh.e_ident[EI_CLASS] != ELFCLASS32 ||
- eh.e_ident[EI_DATA] != ELFDATA2MSB ||
- eh.e_ident[EI_VERSION] != EV_CURRENT ||
- eh.e_version != EV_CURRENT ||
- eh.e_type!=ET_EXEC ||
- eh.e_machine!=EM_MACHINE) {
- return ENOEXEC;
- }
-
- for (i=0; i<eh.e_phnum; i++) {
- off_t offset = eh.e_phoff + i*eh.e_phentsize;
- uio_kinit(&iov, &ku, &ph, sizeof(ph), offset, UIO_READ);
- result = VOP_READ(v, &ku);
- if (result) {
- return result;
- }
- if (ku.uio_resid != 0) {
-
- kprintf("ELF: short read on phdr - file truncated?\n");
- return ENOEXEC;
- }
- switch (ph.p_type) {
- case PT_NULL: continue;
- case PT_PHDR: continue;
- case PT_MIPS_REGINFO: continue;
- case PT_LOAD: break;
- default:
- kprintf("loadelf: unknown segment type %d\n",
- ph.p_type);
- return ENOEXEC;
- }
- result = as_define_region(as,
- ph.p_vaddr, ph.p_memsz,
- ph.p_flags & PF_R,
- ph.p_flags & PF_W,
- ph.p_flags & PF_X);
- if (result) {
- return result;
- }
- }
- result = as_prepare_load(as);
- if (result) {
- return result;
- }
-
- for (i=0; i<eh.e_phnum; i++) {
- off_t offset = eh.e_phoff + i*eh.e_phentsize;
- uio_kinit(&iov, &ku, &ph, sizeof(ph), offset, UIO_READ);
- result = VOP_READ(v, &ku);
- if (result) {
- return result;
- }
- if (ku.uio_resid != 0) {
-
- kprintf("ELF: short read on phdr - file truncated?\n");
- return ENOEXEC;
- }
- switch (ph.p_type) {
- case PT_NULL: continue;
- case PT_PHDR: continue;
- case PT_MIPS_REGINFO: continue;
- case PT_LOAD: break;
- default:
- kprintf("loadelf: unknown segment type %d\n",
- ph.p_type);
- return ENOEXEC;
- }
- result = load_segment(as, v, ph.p_offset, ph.p_vaddr,
- ph.p_memsz, ph.p_filesz,
- ph.p_flags & PF_X);
- if (result) {
- return result;
- }
- }
- result = as_complete_load(as);
- if (result) {
- return result;
- }
- *entrypoint = eh.e_entry;
- return 0;
- }
|