static int mprotect_segments (char *base, const Elf_Phdr *from, const Elf_Phdr *to) { return mprotect (base + from->p_vaddr, to->p_vaddr + to->p_memsz - from->p_vaddr, segment_flags_to_prot (from->p_flags)); }
static int map_segments (int fd, char **base, const Elf_Phdr *from, const Elf_Phdr *to) { int prot = segment_flags_to_prot (from->p_flags); char *ret; ret = mmap (*base + from->p_vaddr, to->p_offset + to->p_filesz - from->p_offset, prot, MAP_PRIVATE, fd, from->p_offset); if (ret == (char *) -1) return 1; if (!*base) *base = ret; return 0; }
static SCM load_thunk_from_memory (char *data, size_t len, int is_read_only) #define FUNC_NAME "load-thunk-from-memory" { Elf_Ehdr *header; Elf_Phdr *ph; const char *err_msg = 0; size_t n, alignment = 8; int i; int dynamic_segment = -1; SCM init = SCM_BOOL_F, entry = SCM_BOOL_F; char *frame_maps = 0; if (len < sizeof *header) ABORT ("object file too small"); header = (Elf_Ehdr*) data; if ((err_msg = check_elf_header (header))) goto cleanup; if (header->e_phnum == 0) ABORT ("no loadable segments"); n = header->e_phnum; if (len < header->e_phoff + n * sizeof (Elf_Phdr)) ABORT ("object file too small"); ph = (Elf_Phdr*) (data + header->e_phoff); /* Check that the segment table is sane. */ for (i = 0; i < n; i++) { if (ph[i].p_filesz != ph[i].p_memsz) ABORT ("expected p_filesz == p_memsz"); if (!ph[i].p_flags) ABORT ("expected nonzero segment flags"); if (ph[i].p_align < alignment) { if (ph[i].p_align % alignment) ABORT ("expected new alignment to be multiple of old"); alignment = ph[i].p_align; } if (ph[i].p_type == PT_DYNAMIC) { if (dynamic_segment >= 0) ABORT ("expected only one PT_DYNAMIC segment"); dynamic_segment = i; continue; } if (ph[i].p_type != PT_LOAD) ABORT ("unknown segment type"); if (i == 0) { if (ph[i].p_vaddr != 0) ABORT ("first loadable vaddr is not 0"); } else { if (ph[i].p_vaddr < ph[i-1].p_vaddr + ph[i-1].p_memsz) ABORT ("overlapping segments"); if (ph[i].p_offset + ph[i].p_filesz > len) ABORT ("segment beyond end of byte array"); } } if (dynamic_segment < 0) ABORT ("no PT_DYNAMIC segment"); if (!IS_ALIGNED ((scm_t_uintptr) data, alignment)) ABORT ("incorrectly aligned base"); /* Allow writes to writable pages. */ if (is_read_only) { #ifdef HAVE_SYS_MMAN_H for (i = 0; i < n; i++) { if (ph[i].p_type != PT_LOAD) continue; if (ph[i].p_flags == PF_R) continue; if (ph[i].p_align != 4096) continue; if (mprotect (data + ph[i].p_vaddr, ph[i].p_memsz, segment_flags_to_prot (ph[i].p_flags))) goto cleanup; } #else ABORT ("expected writable pages"); #endif } if ((err_msg = process_dynamic_segment (data, &ph[dynamic_segment], &init, &entry, &frame_maps))) goto cleanup; if (scm_is_true (init)) scm_call_0 (init); register_elf (data, len, frame_maps); /* Finally! Return the thunk. */ return entry; cleanup: { if (errno) SCM_SYSERROR; scm_misc_error (FUNC_NAME, err_msg ? err_msg : "error loading ELF file", SCM_EOL); } }