Honor p_vaddr if set

(cherry picked from commit 88ff15c2c279d2bbe3569101b36cd2aa0931a0a9)

Change-Id: I4aabbe911d30aea8ace69e29bb6e980a4e89de90
This commit is contained in:
Brian Carlstrom 2013-01-10 16:39:58 -08:00
parent b7b4f5b838
commit e7dffe150b
2 changed files with 32 additions and 21 deletions

View File

@ -226,24 +226,32 @@ bool ElfReader::ReadProgramHeader() {
return true; return true;
} }
/* Compute the extent of all loadable segments in an ELF program header /* Returns the size of the extent of all the possibly non-contiguous
* table. This corresponds to the page-aligned size in bytes that needs to be * loadable segments in an ELF program header table. This corresponds
* reserved in the process' address space * to the page-aligned size in bytes that needs to be reserved in the
* process' address space. If there are no loadable segments, 0 is
* returned.
* *
* This returns 0 if there are no loadable segments. * If out_min_vaddr or out_max_vaddr are non-NULL, they will be
* set to the minimum and maximum addresses of pages to be reserved,
* or 0 if there is nothing to load.
*/ */
Elf32_Addr phdr_table_get_load_size(const Elf32_Phdr* phdr_table, size_t phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
size_t phdr_count) size_t phdr_count,
Elf32_Addr* out_min_vaddr,
Elf32_Addr* out_max_vaddr)
{ {
Elf32_Addr min_vaddr = 0xFFFFFFFFU; Elf32_Addr min_vaddr = 0xFFFFFFFFU;
Elf32_Addr max_vaddr = 0x00000000U; Elf32_Addr max_vaddr = 0x00000000U;
bool found_pt_load = false;
for (size_t i = 0; i < phdr_count; ++i) { for (size_t i = 0; i < phdr_count; ++i) {
const Elf32_Phdr* phdr = &phdr_table[i]; const Elf32_Phdr* phdr = &phdr_table[i];
if (phdr->p_type != PT_LOAD) { if (phdr->p_type != PT_LOAD) {
continue; continue;
} }
found_pt_load = true;
if (phdr->p_vaddr < min_vaddr) { if (phdr->p_vaddr < min_vaddr) {
min_vaddr = phdr->p_vaddr; min_vaddr = phdr->p_vaddr;
@ -253,14 +261,19 @@ Elf32_Addr phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
max_vaddr = phdr->p_vaddr + phdr->p_memsz; max_vaddr = phdr->p_vaddr + phdr->p_memsz;
} }
} }
if (!found_pt_load) {
if (min_vaddr > max_vaddr) { min_vaddr = 0x00000000U;
return 0;
} }
min_vaddr = PAGE_START(min_vaddr); min_vaddr = PAGE_START(min_vaddr);
max_vaddr = PAGE_END(max_vaddr); max_vaddr = PAGE_END(max_vaddr);
if (out_min_vaddr != NULL) {
*out_min_vaddr = min_vaddr;
}
if (out_max_vaddr != NULL) {
*out_max_vaddr = max_vaddr;
}
return max_vaddr - min_vaddr; return max_vaddr - min_vaddr;
} }
@ -268,29 +281,23 @@ Elf32_Addr phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
// segments of a program header table. This is done by creating a // segments of a program header table. This is done by creating a
// private anonymous mmap() with PROT_NONE. // private anonymous mmap() with PROT_NONE.
bool ElfReader::ReserveAddressSpace() { bool ElfReader::ReserveAddressSpace() {
load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_); Elf32_Addr min_vaddr;
load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
if (load_size_ == 0) { if (load_size_ == 0) {
DL_ERR("\"%s\" has no loadable segments", name_); DL_ERR("\"%s\" has no loadable segments", name_);
return false; return false;
} }
uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS; int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
void* start = mmap(NULL, load_size_, PROT_NONE, mmap_flags, -1, 0); void* start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0);
if (start == MAP_FAILED) { if (start == MAP_FAILED) {
DL_ERR("couldn't reserve %d bytes of address space for \"%s\"", load_size_, name_); DL_ERR("couldn't reserve %d bytes of address space for \"%s\"", load_size_, name_);
return false; return false;
} }
load_start_ = start; load_start_ = start;
load_bias_ = 0; load_bias_ = reinterpret_cast<uint8_t*>(start) - addr;
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; return true;
} }

View File

@ -80,7 +80,11 @@ class ElfReader {
const Elf32_Phdr* loaded_phdr_; const Elf32_Phdr* loaded_phdr_;
}; };
Elf32_Addr phdr_table_get_load_size(const Elf32_Phdr* phdr, size_t phnum); size_t
phdr_table_get_load_size(const Elf32_Phdr* phdr_table,
size_t phdr_count,
Elf32_Addr* min_vaddr = NULL,
Elf32_Addr* max_vaddr = NULL);
int int
phdr_table_protect_segments(const Elf32_Phdr* phdr_table, phdr_table_protect_segments(const Elf32_Phdr* phdr_table,