Bug 1423822 - Check segments overlapping later. r=froydnj draft
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 01 Aug 2018 11:17:07 +0900
changeset 825729 9ca3ce5300f0923a6e14bb1661cd834079ba4c85
parent 825728 c7493f77f0a55ad63434c9fb7c41e4f0bf660b6a
child 825730 9f6bdfb258445e0301ff5f50aa1ed0a86abfb4c4
push id118154
push userbmo:mh+mozilla@glandium.org
push dateThu, 02 Aug 2018 05:40:11 +0000
reviewersfroydnj
bugs1423822
milestone63.0a1
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.
build/unix/elfhack/elf.cpp
--- 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)