Bug 1378986 - Adjust the fake phdr section properly. r?froydnj
The PT_PHDR segment is optional, but the Android toolchain decides to
create one in some cases, and places it first. When that happens, the
work around for
bug 1233963 fails, because the fake phdr section has not
been adjusted yet (it only happens when we see a PT_LOAD).
So we adjust the fake phdr section when we see a PT_PHDR segment (and
avoid re-updating it when we see a subsequent PT_LOAD).
--- a/build/unix/elfhack/elf.cpp
+++ b/build/unix/elfhack/elf.cpp
@@ -223,16 +223,17 @@ Elf::Elf(std::ifstream &file)
delete[] shdr;
eh_shstrndx = (ElfStrtab_Section *)sections[ehdr->e_shstrndx];
// Skip reading program headers if there aren't any
if (ehdr->e_phnum == 0)
return;
+ bool adjusted_phdr_section = false;
// Read program headers
file.seekg(ehdr->e_phoff);
for (int i = 0; i < ehdr->e_phnum; i++) {
Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
if (phdr.p_type == PT_LOAD) {
// Default alignment for PT_LOAD on x86-64 prevents elfhack from
// doing anything useful. However, the system doesn't actually
// require such a big alignment, so in order for elfhack to work
@@ -242,22 +243,30 @@ Elf::Elf(std::ifstream &file)
phdr.p_align = 0x1000;
}
ElfSegment *segment = new ElfSegment(&phdr);
// Some segments aren't entirely filled (if at all) by sections
// For those, we use fake sections
if ((phdr.p_type == PT_LOAD) && (phdr.p_offset == 0)) {
// Use a fake section for ehdr and phdr
ehdr->getShdr().sh_addr = phdr.p_vaddr;
- phdr_section->getShdr().sh_addr += phdr.p_vaddr;
+ if (!adjusted_phdr_section) {
+ phdr_section->getShdr().sh_addr += phdr.p_vaddr;
+ adjusted_phdr_section = true;
+ }
segment->addSection(ehdr);
segment->addSection(phdr_section);
}
- if (phdr.p_type == PT_PHDR)
+ if (phdr.p_type == PT_PHDR) {
+ if (!adjusted_phdr_section) {
+ phdr_section->getShdr().sh_addr = phdr.p_vaddr;
+ adjusted_phdr_section = true;
+ }
segment->addSection(phdr_section);
+ }
for (int j = 1; j < ehdr->e_shnum; j++)
if (phdr.contains(sections[j]))
segment->addSection(sections[j]);
// Make sure that our view of segments corresponds to the original
// ELF file.
// GNU gold likes to start some segments before the first section
// they contain. https://sourceware.org/bugzilla/show_bug.cgi?id=19392
unsigned int gold_adjustment = segment->getAddr() - phdr.p_vaddr;