Bug 1423822 - Check segments overlapping later. r=froydnj
We treat segments overlapping as a fatal error, rather than a condition
to do nothing, because it happening is usually the result of some bad
assumptions on the input ELF, and we don't want to silently ignore
those.
However, there are cases where a setup /could/ lead to overlapping
segments, but would be skipped because elfhack wouldn't be a win
anyways. By checking segments overlap later, we allow those to not
hard fail.
--- a/build/unix/elfhack/elf.cpp
+++ b/build/unix/elfhack/elf.cpp
@@ -403,16 +403,33 @@ void Elf::normalize()
std::list<ElfSection *>::iterator it = (*seg)->begin();
for (ElfSection *last = *(it++); it != (*seg)->end(); last = *(it++)) {
if (((*it)->getType() != SHT_NOBITS) &&
((*it)->getAddr() - last->getAddr()) != ((*it)->getOffset() - last->getOffset())) {
throw std::runtime_error("Segments inconsistency");
}
}
}
+
+ ElfSegment* prevLoad = nullptr;
+ for (auto& it : segments) {
+ if (it->getType() == PT_LOAD) {
+ if (prevLoad) {
+ size_t alignedPrevEnd =
+ (prevLoad->getAddr() + prevLoad->getMemSize() + prevLoad->getAlign() - 1)
+ & ~(prevLoad->getAlign() - 1);
+ size_t alignedStart = it->getAddr() & ~(it->getAlign() - 1);
+ if (alignedPrevEnd > alignedStart) {
+ throw std::runtime_error("Segments overlap");
+ }
+ }
+ prevLoad = it;
+ }
+ }
+
// fixup ehdr before writing
if (ehdr->e_phnum != segments.size()) {
ehdr->e_phnum = segments.size();
phdr_section->getShdr().sh_size = segments.size() * Elf_Phdr::size(ehdr->e_ident[EI_CLASS]);
phdr_section->getNext()->markDirty();
}
// fixup shdr before writing
if (ehdr->e_shnum != shdr_section->getSize() / shdr_section->getEntSize())
@@ -548,24 +565,16 @@ unsigned int ElfSection::getOffset()
if ((getAddr() & mask) < (offset & mask))
offset = (offset | mask) + (getAddr() & mask) + 1;
else
offset = (offset & ~mask) + (getAddr() & mask);
}
if ((getType() != SHT_NOBITS) && (offset & (getAddrAlign() - 1)))
offset = (offset | (getAddrAlign() - 1)) + 1;
- // Two subsequent sections can't be mapped in the same page in memory
- // if they aren't in the same 4K block on disk.
- if ((getType() != SHT_NOBITS) && getAddr()) {
- if (((offset >> 12) != (previous->getOffset() >> 12)) &&
- ((getAddr() >> 12) == (previous->getAddr() >> 12)))
- throw std::runtime_error("Moving section would require overlapping segments");
- }
-
return (shdr.sh_offset = offset);
}
int ElfSection::getIndex()
{
if (index != -1)
return index;
if (getType() == SHT_NULL)