/* Reserve a virtual address range big enough to hold all loadable * segments of a program header table. This is done by creating a * private anonymous mmap() with PROT_NONE. * * Input: * phdr_table -> program header table * phdr_count -> number of entries in the tables * Output: * load_start -> first page of reserved address space range * load_size -> size in bytes of reserved address space range * load_bias -> load bias, as described in technical note above. * * Return: * 0 on success, -1 otherwise. Error code in errno. */ int phdr_table_reserve_memory(const Elf32_Phdr* phdr_table, size_t phdr_count, void** load_start, Elf32_Addr* load_size, Elf32_Addr* load_bias) { Elf32_Addr size = phdr_table_get_load_size(phdr_table, phdr_count); if (size == 0) { errno = EINVAL; return -1; } int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; void* start = mmap(NULL, size, PROT_NONE, mmap_flags, -1, 0); if (start == MAP_FAILED) { return -1; } *load_start = start; *load_size = size; *load_bias = 0; for (size_t i = 0; i < phdr_count; ++i) { const Elf32_Phdr* phdr = &phdr_table[i]; if (phdr->p_type == PT_LOAD) { *load_bias = (Elf32_Addr)start - PAGE_START(phdr->p_vaddr); break; } } return 0; }
// Reserve a virtual address range big enough to hold all loadable // segments of a program header table. This is done by creating a // private anonymous mmap() with PROT_NONE. bool ElfReader::ReserveAddressSpace() { load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_); if (load_size_ == 0) { DL_ERR("\"%s\" has no loadable segments", name_); return false; } int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; void* start = mmap(NULL, load_size_, PROT_NONE, mmap_flags, -1, 0); if (start == MAP_FAILED) { DL_ERR("couldn't reserve %d bytes of address space for \"%s\"", load_size_, name_); return false; } load_start_ = start; load_bias_ = 0; for (size_t i = 0; i < phdr_num_; ++i) { const Elf32_Phdr* phdr = &phdr_table_[i]; if (phdr->p_type == PT_LOAD) { load_bias_ = reinterpret_cast<Elf32_Addr>(start) - PAGE_START(phdr->p_vaddr); break; } } return true; }
// Reserve a virtual address range big enough to hold all loadable // segments of a program header table. This is done by creating a // private anonymous mmap() with PROT_NONE. // // This will use the wanted_load_address_ value, bool ElfLoader::ReserveAddressSpace(Error* error) { ELF::Addr min_vaddr; load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr, NULL); if (load_size_ == 0) { error->Set("No loadable segments"); return false; } uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr); int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; // Support loading at a fixed address. if (wanted_load_address_) { addr = static_cast<uint8_t*>(wanted_load_address_); mmap_flags |= MAP_FIXED; } LOG("%s: address=%p size=%p\n", __FUNCTION__, addr, load_size_); void* start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0); if (start == MAP_FAILED) { error->Format("Could not reserve %d bytes of address space", load_size_); return false; } load_start_ = start; load_bias_ = reinterpret_cast<ELF::Addr>(start) - min_vaddr; return true; }
// Reserve a virtual address range big enough to hold all loadable // segments of a program header table. This is done by creating a // private anonymous mmap() with PROT_NONE. bool ElfReader_ReserveAddressSpace(ElfReader* er) { Elf32_Addr min_vaddr; er->load_size_ = phdr_table_get_load_size(er->phdr_table_, er->phdr_num_, &min_vaddr, NULL); if (er->load_size_ == 0) { DL_ERR("\"%s\" has no loadable segments", er->name_); return false; } uint8_t* addr = (uint8_t*)(min_vaddr); int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; void* start = mmap(NULL, er->load_size_, PROT_NONE, mmap_flags, -1, 0); if (start == MAP_FAILED) { DL_ERR("couldn't reserve %d bytes of address space for \"%s\"", er->load_size_, er->name_); return false; } er->load_start_ = start; er->load_bias_ = (uint8_t*)(start) - addr; return true; }
bool ElfView::InitUnmapped(ELF::Addr load_address, const ELF::Phdr* phdr, size_t phdr_count, Error* error) { // Compute load size and bias. ELF::Addr min_vaddr = 0; load_size_ = phdr_table_get_load_size(phdr, phdr_count, &min_vaddr, NULL); if (load_size_ == 0) { *error = "Invalid program header table"; return false; } load_address_ = (load_address ? load_address : min_vaddr); load_bias_ = load_address - min_vaddr; // Extract the dynamic table information. phdr_table_get_dynamic_section(phdr, phdr_count, load_address, &dynamic_, &dynamic_count_, &dynamic_flags_); if (!dynamic_) { *error = "No PT_DYNAMIC section!"; return false; } // Compute the program header table address relative to load_address. // This is different from |phdr|..|phdr + phdr_count| which can actually // be at a different location. const ELF::Phdr* phdr0 = NULL; // First, if there is a PT_PHDR, use it directly. for (size_t n = 0; n < phdr_count; ++n) { const ELF::Phdr* entry = &phdr[n]; if (entry->p_type == PT_PHDR) { phdr0 = entry; break; } } // Otherwise, check the first loadable segment. If its file offset // is 0, it starts with the ELF header, and we can trivially find the // loaded program header from it. if (!phdr0) { for (size_t n = 0; n < phdr_count; ++n) { const ELF::Phdr* entry = &phdr[n]; if (entry->p_type == PT_LOAD) { if (entry->p_offset == 0) { ELF::Addr elf_addr = load_bias_ + entry->p_vaddr; const ELF::Ehdr* ehdr = reinterpret_cast<const ELF::Ehdr*>(elf_addr); ELF::Addr offset = ehdr->e_phoff; phdr0 = reinterpret_cast<const ELF::Phdr*>(elf_addr + offset); } break; } } } // Check that the program header table is indeed in a loadable segment, // this helps catching malformed ELF binaries. if (phdr0) { ELF::Addr phdr0_addr = reinterpret_cast<ELF::Addr>(phdr0); ELF::Addr phdr0_limit = phdr0_addr + sizeof(ELF::Phdr) * phdr_count; bool found = false; for (size_t n = 0; n < phdr_count; ++n) { size_t seg_start = load_bias_ + phdr[n].p_vaddr; size_t seg_end = seg_start + phdr[n].p_filesz; if (seg_start <= phdr0_addr && phdr0_limit <= seg_end) { found = true; break; } } if (!found) phdr0 = NULL; } if (!phdr0) { *error = "Malformed ELF binary"; return false; } phdr_ = phdr0; phdr_count_ = phdr_count; LOG("%s: New ELF view [load_address:%p, load_size:%p, load_bias:%p, phdr:%p, " "phdr_count:%d, dynamic:%p, dynamic_count:%d, dynamic_flags:%d\n", __FUNCTION__, load_address_, load_size_, load_bias_, phdr_, phdr_count_, dynamic_, dynamic_count_, dynamic_flags_); return true; }