]> granicus.if.org Git - llvm/commitdiff
[JITLink] Track section alignment and make sure it is respected during layout.
authorLang Hames <lhames@gmail.com>
Mon, 13 May 2019 04:51:31 +0000 (04:51 +0000)
committerLang Hames <lhames@gmail.com>
Mon, 13 May 2019 04:51:31 +0000 (04:51 +0000)
Previously we had only honored alignments on individual atoms, but
tools/runtimes may assume that the section alignment is respected too.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@360555 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ExecutionEngine/JITLink/JITLink.h
lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp
lib/ExecutionEngine/JITLink/JITLinkGeneric.h
lib/ExecutionEngine/JITLink/MachOAtomGraphBuilder.cpp
lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
test/ExecutionEngine/JITLink/X86/MachO_x86-64_relocations.s

index dd4fe369c76ac8c2e96f5ca34529cbdece2523ae..01e26a902177ede8ced6540c5820c1bc5c13dd7d 100644 (file)
@@ -22,6 +22,7 @@
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/Memory.h"
 #include "llvm/Support/MemoryBuffer.h"
 
@@ -329,9 +330,12 @@ class Section {
   friend class AtomGraph;
 
 private:
-  Section(StringRef Name, sys::Memory::ProtectionFlags Prot, unsigned Ordinal,
-          bool IsZeroFill)
-      : Name(Name), Prot(Prot), Ordinal(Ordinal), IsZeroFill(IsZeroFill) {}
+  Section(StringRef Name, uint32_t Alignment, sys::Memory::ProtectionFlags Prot,
+          unsigned Ordinal, bool IsZeroFill)
+      : Name(Name), Alignment(Alignment), Prot(Prot), Ordinal(Ordinal),
+        IsZeroFill(IsZeroFill) {
+    assert(isPowerOf2_32(Alignment) && "Alignments must be a power of 2");
+  }
 
   using DefinedAtomSet = DenseSet<DefinedAtom *>;
 
@@ -341,6 +345,7 @@ public:
 
   ~Section();
   StringRef getName() const { return Name; }
+  uint32_t getAlignment() const { return Alignment; }
   sys::Memory::ProtectionFlags getProtectionFlags() const { return Prot; }
   unsigned getSectionOrdinal() const { return Ordinal; }
   size_t getNextAtomOrdinal() { return ++NextAtomOrdinal; }
@@ -388,6 +393,7 @@ private:
   }
 
   StringRef Name;
+  uint32_t Alignment = 0;
   sys::Memory::ProtectionFlags Prot;
   unsigned Ordinal = 0;
   unsigned NextAtomOrdinal = 0;
@@ -403,12 +409,16 @@ class DefinedAtom : public Atom {
 private:
   DefinedAtom(Section &Parent, JITTargetAddress Address, uint32_t Alignment)
       : Atom("", Address), Parent(Parent), Ordinal(Parent.getNextAtomOrdinal()),
-        Alignment(Alignment) {}
+        Alignment(Alignment) {
+    assert(isPowerOf2_32(Alignment) && "Alignments must be a power of two");
+  }
 
   DefinedAtom(Section &Parent, StringRef Name, JITTargetAddress Address,
               uint32_t Alignment)
       : Atom(Name, Address), Parent(Parent),
-        Ordinal(Parent.getNextAtomOrdinal()), Alignment(Alignment) {}
+        Ordinal(Parent.getNextAtomOrdinal()), Alignment(Alignment) {
+    assert(isPowerOf2_32(Alignment) && "Alignments must be a power of two");
+  }
 
 public:
   using edge_iterator = EdgeVector::iterator;
@@ -510,7 +520,7 @@ inline uint64_t SectionRange::getSize() const { return getEnd() - getStart(); }
 inline SectionRange Section::getRange() const {
   if (atoms_empty())
     return SectionRange();
-  DefinedAtom *First = *DefinedAtoms.begin(), *Last = *DefinedAtoms.end();
+  DefinedAtom *First = *DefinedAtoms.begin(), *Last = *DefinedAtoms.begin();
   for (auto *DA : atoms()) {
     if (DA->getAddress() < First->getAddress())
       First = DA;
@@ -602,10 +612,10 @@ public:
   support::endianness getEndianness() const { return Endianness; }
 
   /// Create a section with the given name, protection flags, and alignment.
-  Section &createSection(StringRef Name, sys::Memory::ProtectionFlags Prot,
-                         bool IsZeroFill) {
+  Section &createSection(StringRef Name, uint32_t Alignment,
+                         sys::Memory::ProtectionFlags Prot, bool IsZeroFill) {
     std::unique_ptr<Section> Sec(
-        new Section(Name, Prot, Sections.size(), IsZeroFill));
+        new Section(Name, Alignment, Prot, Sections.size(), IsZeroFill));
     Sections.push_back(std::move(Sec));
     return *Sections.back();
   }
index b3477f1ee4ce43ffc5ec3c45e48900aab96646d9..96e074da122ba476eccfa5bbfd992e3e1368dc54 100644 (file)
@@ -241,6 +241,10 @@ Error JITLinkerBase::allocateSegments(const SegmentLayoutMap &Layout) {
     for (auto &SI : SegLayout.ContentSections) {
       assert(!SI.S->atoms_empty() && "Sections in layout must not be empty");
       assert(!SI.Atoms.empty() && "Section layouts must not be empty");
+
+      // Bump to section alignment before processing atoms.
+      SegContentSize = alignTo(SegContentSize, SI.S->getAlignment());
+
       for (auto *DA : SI.Atoms) {
         SegContentSize = alignTo(SegContentSize, DA->getAlignment());
         SegContentSize += DA->getSize();
@@ -249,15 +253,22 @@ Error JITLinkerBase::allocateSegments(const SegmentLayoutMap &Layout) {
 
     // Get segment content alignment.
     unsigned SegContentAlign = 1;
-    if (!SegLayout.ContentSections.empty())
+    if (!SegLayout.ContentSections.empty()) {
+      auto &FirstContentSection = SegLayout.ContentSections.front();
       SegContentAlign =
-          SegLayout.ContentSections.front().Atoms.front()->getAlignment();
+          std::max(FirstContentSection.S->getAlignment(),
+                   FirstContentSection.Atoms.front()->getAlignment());
+    }
 
     // Calculate segment zero-fill size.
     uint64_t SegZeroFillSize = 0;
     for (auto &SI : SegLayout.ZeroFillSections) {
       assert(!SI.S->atoms_empty() && "Sections in layout must not be empty");
       assert(!SI.Atoms.empty() && "Section layouts must not be empty");
+
+      // Bump to section alignment before processing atoms.
+      SegZeroFillSize = alignTo(SegZeroFillSize, SI.S->getAlignment());
+
       for (auto *DA : SI.Atoms) {
         SegZeroFillSize = alignTo(SegZeroFillSize, DA->getAlignment());
         SegZeroFillSize += DA->getSize();
@@ -266,9 +277,13 @@ Error JITLinkerBase::allocateSegments(const SegmentLayoutMap &Layout) {
 
     // Calculate segment zero-fill alignment.
     uint32_t SegZeroFillAlign = 1;
-    if (!SegLayout.ZeroFillSections.empty())
+
+    if (!SegLayout.ZeroFillSections.empty()) {
+      auto &FirstZeroFillSection = SegLayout.ZeroFillSections.front();
       SegZeroFillAlign =
-          SegLayout.ZeroFillSections.front().Atoms.front()->getAlignment();
+          std::max(FirstZeroFillSection.S->getAlignment(),
+                   FirstZeroFillSection.Atoms.front()->getAlignment());
+    }
 
     if (SegContentSize == 0)
       SegContentAlign = SegZeroFillAlign;
@@ -314,12 +329,14 @@ Error JITLinkerBase::allocateSegments(const SegmentLayoutMap &Layout) {
         Alloc->getTargetMemory(static_cast<sys::Memory::ProtectionFlags>(Prot));
 
     for (auto *SIList : {&SL.ContentSections, &SL.ZeroFillSections})
-      for (auto &SI : *SIList)
+      for (auto &SI : *SIList) {
+        AtomTargetAddr = alignTo(AtomTargetAddr, SI.S->getAlignment());
         for (auto *DA : SI.Atoms) {
           AtomTargetAddr = alignTo(AtomTargetAddr, DA->getAlignment());
           DA->setAddress(AtomTargetAddr);
           AtomTargetAddr += DA->getSize();
         }
+      }
   }
 
   return Error::success();
index 9d8238cf2e516bd178a34ef9701df11408dac165..e6fd6e38f7a61e5f0aa1d0a50c727636af1e5720 100644 (file)
@@ -150,7 +150,7 @@ private:
       auto SegMem = Alloc.getWorkingMemory(
           static_cast<sys::Memory::ProtectionFlags>(Prot));
       char *LastAtomEnd = SegMem.data();
-      char *AtomDataPtr = nullptr;
+      char *AtomDataPtr = LastAtomEnd;
 
       LLVM_DEBUG({
         dbgs() << "  Processing segment "
@@ -162,8 +162,16 @@ private:
 
       for (auto &SI : SegLayout.ContentSections) {
         LLVM_DEBUG(dbgs() << "    " << SI.S->getName() << ":\n");
+
+        AtomDataPtr += alignmentAdjustment(AtomDataPtr, SI.S->getAlignment());
+
+        LLVM_DEBUG({
+          dbgs() << "      Bumped atom pointer to " << (const void *)AtomDataPtr
+                 << " to meet section alignment "
+                 << " of " << SI.S->getAlignment() << "\n";
+        });
+
         for (auto *DA : SI.Atoms) {
-          AtomDataPtr = LastAtomEnd;
 
           // Align.
           AtomDataPtr += alignmentAdjustment(AtomDataPtr, DA->getAlignment());
@@ -209,6 +217,7 @@ private:
 
           // Update atom end pointer.
           LastAtomEnd = AtomDataPtr + DA->getContent().size();
+          AtomDataPtr = LastAtomEnd;
         }
       }
 
index 0c19f8fee0da183970073babf019e0a6e272eafa..b24b22568269723db1143ae45d4782ad43aeb432 100644 (file)
@@ -85,7 +85,7 @@ MachOAtomGraphBuilder::MachOSection &MachOAtomGraphBuilder::getCommonSection() {
   if (!CommonSymbolsSection) {
     auto Prot = static_cast<sys::Memory::ProtectionFlags>(
         sys::Memory::MF_READ | sys::Memory::MF_WRITE);
-    auto &GenericSection = G->createSection("<common>", Prot, true);
+    auto &GenericSection = G->createSection("<common>", 1, Prot, true);
     CommonSymbolsSection = MachOSection(GenericSection);
   }
   return *CommonSymbolsSection;
@@ -102,6 +102,12 @@ Error MachOAtomGraphBuilder::parseSections() {
 
     unsigned SectionIndex = SecRef.getIndex() + 1;
 
+    uint32_t Align = SecRef.getAlignment();
+    if (!isPowerOf2_32(Align))
+      return make_error<JITLinkError>("Section " + Name +
+                                      " has non-power-of-2 "
+                                      "alignment");
+
     // FIXME: Get real section permissions
     // How, exactly, on MachO?
     sys::Memory::ProtectionFlags Prot;
@@ -112,7 +118,7 @@ Error MachOAtomGraphBuilder::parseSections() {
       Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
                                                        sys::Memory::MF_WRITE);
 
-    auto &GenericSection = G->createSection(Name, Prot, SecRef.isBSS());
+    auto &GenericSection = G->createSection(Name, Align, Prot, SecRef.isBSS());
 
     LLVM_DEBUG({
       dbgs() << "Adding section " << Name << ": "
index 7b4ddc3019a1d9ed7c50a6afdf7c7d9bcc3a0e8e..4010678c6d33c319db7cb9f07d9ee3ad4348ff1e 100644 (file)
@@ -399,7 +399,7 @@ public:
 private:
   Section &getGOTSection() {
     if (!GOTSection)
-      GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ, false);
+      GOTSection = &G.createSection("$__GOT", 8, sys::Memory::MF_READ, false);
     return *GOTSection;
   }
 
@@ -407,7 +407,7 @@ private:
     if (!StubsSection) {
       auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
           sys::Memory::MF_READ | sys::Memory::MF_EXEC);
-      StubsSection = &G.createSection("$__STUBS", StubsProt, false);
+      StubsSection = &G.createSection("$__STUBS", 8, StubsProt, false);
     }
     return *StubsSection;
   }
index b306a490ebe283d9dfd64e69bfa80a3338d052ab..568faebd9651d9d25c7679795840a75219c0618a 100644 (file)
@@ -277,4 +277,24 @@ subtractor_with_alt_entry_subtrahend_quad_B:
         .globl zero_fill_test
 .zerofill __DATA,__zero_fill_test,zero_fill_test,8,3
 
+# Check that section alignments are respected.
+# We test this by introducing two segments with alignment 8, each containing one
+# byte of data. We require both symbols to have an aligned address.
+#
+# jitlink-check: section_alignment_check1[2:0] = 0
+# jitlink-check: section_alignment_check2[2:0] = 0
+        .section        __DATA,__sec_align_chk1
+        .p2align 3
+
+        .globl section_alignment_check1
+section_alignment_check1:
+        .byte 0
+
+        .section        __DATA,__sec_align_chk2
+        .p2align 3
+
+        .globl section_alignment_check2
+section_alignment_check2:
+        .byte 0
+
 .subsections_via_symbols