bool load(std::istream &in, Memory& mem, addr_t img_base) { if (virt_sz > 0) { addr_t sect_addr_va = img_base + virt_addr; int prot = get_prot(charac); mem.alloc_protect(sect_addr_va , virt_sz, prot | Memory::Write); //TODO check for file_sz > virt_sz (explained in spec) if (file_sz > 0) { std::istream::streampos pos_orig = in.tellg(); if (pos_orig == std::istream::pos_type(std::istream::off_type(-1))) return false; in.seekg(file_pos, std::ios_base::beg); // TODO is "bad()" the right thing to check? if (in.bad()) return false; char *sect_data = new char[file_sz]; in.read(sect_data, file_sz); if (std::size_t(in.gcount()) < file_sz) { delete[] sect_data; return false; } // perhaps change "write" interface to accept const char * to // avoid this copying madness? mem.write(sect_addr_va, std::string(sect_data, file_sz)); delete[] sect_data; if (!(prot & Memory::Write)) mem.alloc_protect(sect_addr_va, virt_sz, prot); in.seekg(pos_orig); if (in.bad()) return false; } } return true; }
void *elf_file_load_ram(int pid, char *pfile) { elf64_hdr *pelf_header; elf64_phdr *prog_hdr; void *seg_addr; void *elf_offset; int ph; uintptr_t start, end; int sizeof_phdrs; int err; pelf_header = (elf64_hdr *)pfile; if (strncmp((const char *)pelf_header->e_ident, "\x7f" "ELF", 4)) { anvil_syslog(0, "Incorrect ELF identifier\n"); return NULL; } if (pelf_header->e_ident[4] != 2) { anvil_syslog(0, "Elf file is not 64 bit\n"); return NULL; } if (pelf_header->e_type != 2) { anvil_syslog(0, "Elf file is not executable\n"); return NULL; } if (pelf_header->e_phnum > 3) { anvil_syslog(0, "Elf file has too many segments\n"); return NULL; } //anvil_syslog(0, "Elf OK\n"); sizeof_phdrs = pelf_header->e_phentsize * pelf_header->e_phnum; prog_hdr = (elf64_phdr *)((char *)pelf_header + pelf_header->e_phoff); for (ph=0; ph<pelf_header->e_phnum; ++ph) { int prot; if (prog_hdr->p_type != 1) { anvil_syslog(0, "Elf file segment is not loadable\n"); return NULL; } prot = get_prot(prog_hdr->p_flags); /* We found a loadable segment so create a mapping */ start = prog_hdr->p_vaddr; end = start + prog_hdr->p_memsz; start &= ~0xfff; end = __PAGEROUND(end); if (_Mmap(0, 0, end - start, PROT_READ, MAP_ANON, -1, 0, &seg_addr) != 0) { anvil_syslog(0, "Out of memory\n"); return NULL; } //anvil_syslog(0, "seg_addr = %016lx\n", seg_addr); /* Find where, in the elf image the section is */ elf_offset = (void *)(pfile + prog_hdr->p_offset); //anvil_syslog(0, "File image addr = %08x\n", elf_offset); /* The segment is zero filled by the _Mmap system call */ //anvil_syslog(0, "%016lx %016lx %016lx\n", // seg_addr + prog_hdr->p_vaddr - start, // elf_offset, // prog_hdr->p_filesz); memcpy(seg_addr + prog_hdr->p_vaddr - start, elf_offset, prog_hdr->p_filesz); //anvil_syslog(0, "_Vmm_send: %d %016lx %016lx %018x\n", // pid, start, seg_addr, end - start); _Vmm_send(pid, (void *)start, seg_addr, end - start, prot); prog_hdr = (elf64_phdr *) ((uint64_t)prog_hdr + pelf_header->e_phentsize); } return (void *)pelf_header->e_entry; }
int se_virtual_protect(void* address, size_t size, uint32_t prot) { return !mprotect(address, size, (int)get_prot(prot)); }
void *elf_file_load(int pid, int fd) { elf64_hdr elf_header; elf64_hdr *pelf_header; elf64_phdr *pprog_hdr; void *seg_addr; void *elf_offset; int ph; uintptr_t start, end; int sizeof_phdrs; int err; char *p; char *interp_name; elf64_dyn *dyn_seg; int ndyn_items; int interp_fd; uintptr_t entry_offs; int prot; interp_name = NULL; dyn_seg = NULL; entry_offs = 0; if (read(fd, &elf_header, sizeof(elf_header)) != sizeof(elf_header)) { anvil_syslog(0, "Bad ELF header\n"); while (1); } pelf_header = &elf_header; if (strncmp((const char *)pelf_header->e_ident, "\x7f" "ELF", 4)) { anvil_syslog(0, "Incorrect ELF identifier\n"); return NULL; } if (pelf_header->e_ident[4] != 2) { anvil_syslog(0, "Elf file is not 64 bit\n"); return NULL; } if (pelf_header->e_type != 2) { anvil_syslog(0, "Elf file is not executable\n"); return NULL; } // if (pelf_header->e_phnum > 3) { // anvil_syslog(0, "Elf file has too many segments\n"); // return NULL; // } //anvil_syslog(0, "Elf OK\n"); sizeof_phdrs = pelf_header->e_phentsize * pelf_header->e_phnum; pprog_hdr = (elf64_phdr *)alloca(sizeof_phdrs); memset(pprog_hdr, 0, sizeof_phdrs); if (pread(fd, pprog_hdr, sizeof_phdrs, elf_header.e_phoff) == -1) { anvil_syslog(0, "Bad prog_hdr header\n"); while (1); } for (ph=0; ph<pelf_header->e_phnum; ++ph) { switch (pprog_hdr->p_type) { case PT_LOAD: if (pprog_hdr->p_type != 1) { anvil_syslog(0, "Elf file segment is not loadable\n"); return NULL; } prot = get_prot(pprog_hdr->p_flags); /* We found a loadable segment so create a mapping */ start = pprog_hdr->p_vaddr; end = start + pprog_hdr->p_memsz; start &= ~0xfff; end = __PAGEROUND(end); //anvil_syslog(0, "\nstart=%016lx end=%016lx\n", start, end); /* Make a mapping in the address of the exec-svr */ if (_Mmap(0, 0, end - start, PROT_READ, MAP_ANON, -1, 0, &seg_addr) != 0) { anvil_syslog(0, "Out of memory\n"); return NULL; } /* * seg_addr (from the mmap call) is the address in the * exec-svr where we will load the section */ /* Load the segment from the file */ //anvil_syslog(0, "pread to %016lx %016lx\n", pprog_hdr->p_filesz, pprog_hdr->p_offset); if (pread(fd, seg_addr + pprog_hdr->p_vaddr - start, pprog_hdr->p_filesz, pprog_hdr->p_offset) == -1) { anvil_syslog(0, "Bad load of segment\n"); while (1); } /* Send it to the new process space */ //anvil_syslog(0, "_Vmm_send: %d %016lx %016lx %018x\n", // pid, start, seg_addr, end - start); _Vmm_send(pid, (void *)start, seg_addr, end - start, prot); break; case PT_INTERP: /* * Just record the name of the interpreter. We'll load it in * a minute */ //anvil_syslog(0, "PT_INTERP %d\n", pprog_hdr->p_filesz); interp_name = alloca(pprog_hdr->p_filesz + 1); if (pread(fd, interp_name, pprog_hdr->p_filesz, pprog_hdr->p_offset) == -1) { anvil_syslog(0, "Bad load of interp\n"); while (1); } interp_name[pprog_hdr->p_filesz] = 0; //anvil_syslog(0, "PT_INTERP is %s\n", interp_name); break; case PT_DYNAMIC: /* */ //anvil_syslog(0, "PT_DYNAMIC\n"); dyn_seg = alloca(pprog_hdr->p_filesz); if (pread(fd, dyn_seg, pprog_hdr->p_filesz, pprog_hdr->p_offset) == -1) { anvil_syslog(0, "Bad load of dyn_seg\n"); while (1); } ndyn_items = pprog_hdr->p_filesz / sizeof(elf64_dyn); //anvil_syslog(0, "PT_DYNAMIC %d items\n", ndyn_items); /* Now parse the dyn seg */ while (ndyn_items) { //anvil_syslog(0, " items %d %016lx\n", dyn_seg->d_tag, dyn_seg->d_un.d_ptr); ++dyn_seg; --ndyn_items; } break; case PT_TLS: // anvil_syslog(0, "PT_TLS\n"); // anvil_syslog(0, "p_type %016lx\n",pprog_hdr->p_type); // anvil_syslog(0, "p_flags %016lx\n",pprog_hdr->p_flags); // anvil_syslog(0, "p_offset %016lx\n",pprog_hdr->p_offset); // anvil_syslog(0, "p_vaddr %016lx\n",pprog_hdr->p_vaddr); // anvil_syslog(0, "p_paddr %016lx\n",pprog_hdr->p_paddr); // anvil_syslog(0, "p_filesz %016lx\n",pprog_hdr->p_filesz); // anvil_syslog(0, "p_memsz %016lx\n",pprog_hdr->p_memsz); // anvil_syslog(0, "p_align %016lx\n",pprog_hdr->p_align); //*ptls_bss_len += pprog_hdr->p_memsz; break; default: anvil_syslog(0, "Unknown Load type %d\n", pprog_hdr->p_type); break; } pprog_hdr = (elf64_phdr *) ((uint64_t)pprog_hdr + pelf_header->e_phentsize); } if (interp_name != NULL) { interp_name = "/lib/libc.so"; //anvil_syslog(0, "Loading interpreter %s\n", interp_name); if ((interp_fd = open(interp_name, 0, 0)) == -1) { anvil_syslog(0, "Couldn't open interpreter %s\n", interp_name); return NULL; } /* * Now load the interpreter into memory. The interpreter should be * entirely PIC so we can load it anywhere. */ if (read(interp_fd, &elf_header, sizeof(elf_header)) != sizeof(elf_header)) { anvil_syslog(0, "Bad ELF header\n"); while (1); } pelf_header = &elf_header; if (strncmp((const char *)pelf_header->e_ident, "\x7f" "ELF", 4)) { anvil_syslog(0, "Interp: Incorrect ELF identifier\n"); return NULL; } if (pelf_header->e_ident[4] != 2) { anvil_syslog(0, "Interp: Elf file is not 64 bit\n"); return NULL; } if (pelf_header->e_type != 3) { anvil_syslog(0, "Interp: Elf file is not a so\n"); return NULL; } anvil_syslog(0, "Interp OK\n"); sizeof_phdrs = pelf_header->e_phentsize * pelf_header->e_phnum; pprog_hdr = (elf64_phdr *)alloca(sizeof_phdrs); memset(pprog_hdr, 0, sizeof_phdrs); if (pread(interp_fd, pprog_hdr, sizeof_phdrs, elf_header.e_phoff) == -1) { anvil_syslog(0, "Interp: Bad prog_hdr header\n"); while (1); } for (ph=0; ph<pelf_header->e_phnum; ++ph) { switch (pprog_hdr->p_type) { case PT_LOAD: if (pprog_hdr->p_type != 1) { anvil_syslog(0, "Interp: Elf file segment is not loadable\n"); return NULL; } prot = get_prot(pprog_hdr->p_flags); /* We found a loadable segment so create a mapping */ start = pprog_hdr->p_vaddr; end = start + pprog_hdr->p_memsz; start &= ~0xfff; end = __PAGEROUND(end); //anvil_syslog(0, "\nstart=%016lx end=%016lx\n", start, end); /* Make a mapping in the address of the exec-svr */ if (_Mmap(0, 0, end - start, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON, -1, 0, &seg_addr) != 0) { anvil_syslog(0, "Interp: Out of memory\n"); return NULL; } /* * seg_addr (from the mmap call) is the address in the * exec-svr where we will load the section */ /* Load the segment from the file */ //anvil_syslog(0, "pread to %016lx %016lx\n", pprog_hdr->p_filesz, pprog_hdr->p_offset); if (pread(interp_fd, seg_addr + pprog_hdr->p_vaddr - start, pprog_hdr->p_filesz, pprog_hdr->p_offset) == -1) { anvil_syslog(0, "Interp: Bad load of segment\n"); while (1); } /* Send it to the new process space */ //anvil_syslog(0, "_Vmm_send: %d %016lx %016lx %018x\n", // pid, start, seg_addr, end - start); _Vmm_send(pid, (void *)start+0x100000000, seg_addr, end - start, prot); break; default: anvil_syslog(0, "Unknown Load type %d\n", pprog_hdr->p_type); break; } pprog_hdr = (elf64_phdr *) ((uint64_t)pprog_hdr + pelf_header->e_phentsize); } entry_offs += 0x100000000; close(interp_fd); } //anvil_syslog(0, "Start address at %016lx\n", elf_header.e_entry+entry_offs); return (void *)elf_header.e_entry + entry_offs; }
void load_elf(const char* fn, elf_info* info) { file_t* file = file_open(fn, O_RDONLY, 0); if (IS_ERR_VALUE(file)) goto fail; Elf_Ehdr eh; ssize_t ehdr_size = file_pread(file, &eh, sizeof(eh), 0); if (ehdr_size < (ssize_t)sizeof(eh) || !(eh.e_ident[0] == '\177' && eh.e_ident[1] == 'E' && eh.e_ident[2] == 'L' && eh.e_ident[3] == 'F')) goto fail; #if __riscv_xlen == 64 assert(IS_ELF64(eh)); #else assert(IS_ELF32(eh)); #endif #ifndef __riscv_compressed assert(!(eh.e_flags & EF_RISCV_RVC)); #endif size_t phdr_size = eh.e_phnum * sizeof(Elf_Phdr); if (phdr_size > info->phdr_size) goto fail; ssize_t ret = file_pread(file, (void*)info->phdr, phdr_size, eh.e_phoff); if (ret < (ssize_t)phdr_size) goto fail; info->phnum = eh.e_phnum; info->phent = sizeof(Elf_Phdr); Elf_Phdr* ph = (typeof(ph))info->phdr; // compute highest VA in ELF uintptr_t max_vaddr = 0; for (int i = 0; i < eh.e_phnum; i++) if (ph[i].p_type == PT_LOAD && ph[i].p_memsz) max_vaddr = MAX(max_vaddr, ph[i].p_vaddr + ph[i].p_memsz); max_vaddr = ROUNDUP(max_vaddr, RISCV_PGSIZE); // don't load dynamic linker at 0, else we can't catch NULL pointer derefs uintptr_t bias = 0; if (eh.e_type == ET_DYN) bias = RISCV_PGSIZE; info->entry = eh.e_entry + bias; int flags = MAP_FIXED | MAP_PRIVATE; for (int i = eh.e_phnum - 1; i >= 0; i--) { if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) { uintptr_t prepad = ph[i].p_vaddr % RISCV_PGSIZE; uintptr_t vaddr = ph[i].p_vaddr + bias; if (vaddr + ph[i].p_memsz > info->brk_min) info->brk_min = vaddr + ph[i].p_memsz; int flags2 = flags | (prepad ? MAP_POPULATE : 0); int prot = get_prot(ph[i].p_flags); if (__do_mmap(vaddr - prepad, ph[i].p_filesz + prepad, prot | PROT_WRITE, flags2, file, ph[i].p_offset - prepad) != vaddr - prepad) goto fail; memset((void*)vaddr - prepad, 0, prepad); if (!(prot & PROT_WRITE)) if (do_mprotect(vaddr - prepad, ph[i].p_filesz + prepad, prot)) goto fail; size_t mapped = ROUNDUP(ph[i].p_filesz + prepad, RISCV_PGSIZE) - prepad; if (ph[i].p_memsz > mapped) if (__do_mmap(vaddr + mapped, ph[i].p_memsz - mapped, prot, flags|MAP_ANONYMOUS, 0, 0) != vaddr + mapped) goto fail; } } file_decref(file); return; fail: panic("couldn't open ELF program: %s!", fn); }