Honor p_vaddr if set
(cherry picked from commit 88ff15c2c279d2bbe3569101b36cd2aa0931a0a9) Change-Id: I4aabbe911d30aea8ace69e29bb6e980a4e89de90
This commit is contained in:
parent
b7b4f5b838
commit
e7dffe150b
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user