[llvm] r325700 - Handle IMAGE_REL_AMD64_ADDR32NB in RuntimeDyldCOFF

Frederich Munch via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 21 09:18:20 PST 2018


Author: marsupial
Date: Wed Feb 21 09:18:20 2018
New Revision: 325700

URL: http://llvm.org/viewvc/llvm-project?rev=325700&view=rev
Log:
Handle IMAGE_REL_AMD64_ADDR32NB in RuntimeDyldCOFF

Summary:
IMAGE_REL_AMD64_ADDR32NB relocations are currently set to zero in all cases.
This patch sets the relocation to the correct value when possible and shows an error when not.

Reviewers: enderby, lhames, compnerd

Reviewed By: compnerd

Subscribers: LepelTsmok, compnerd, martell, llvm-commits

Differential Revision: https://reviews.llvm.org/D30709

Added:
    llvm/trunk/test/ExecutionEngine/RuntimeDyld/X86/COFF_x86_64_IMGREL.s
Modified:
    llvm/trunk/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h

Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h?rev=325700&r1=325699&r2=325700&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h (original)
+++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h Wed Feb 21 09:18:20 2018
@@ -30,15 +30,33 @@ private:
   // unregisteredEH frame sections with the memory manager.
   SmallVector<SID, 2> UnregisteredEHFrameSections;
   SmallVector<SID, 2> RegisteredEHFrameSections;
+  uint64_t ImageBase;
+
+  // Fake an __ImageBase pointer by returning the section with the lowest adress
+  uint64_t getImageBase() {
+    if (!ImageBase) {
+      ImageBase = std::numeric_limits<uint64_t>::max();
+      for (const SectionEntry &Section : Sections)
+        ImageBase = std::min(ImageBase, Section.getLoadAddress());
+    }
+    return ImageBase;
+  }
+
+  void write32BitOffset(uint8_t *Target, int64_t Addend, uint64_t Delta) {
+    uint64_t Result = Addend + Delta;
+    assert(Result <= UINT32_MAX && "Relocation overflow");
+    writeBytesUnaligned(Result, Target, 4);
+  }
 
 public:
   RuntimeDyldCOFFX86_64(RuntimeDyld::MemoryManager &MM,
                         JITSymbolResolver &Resolver)
-    : RuntimeDyldCOFF(MM, Resolver) {}
+    : RuntimeDyldCOFF(MM, Resolver), ImageBase(0) {}
 
-  unsigned getMaxStubSize() override {
-    return 6; // 2-byte jmp instruction + 32-bit relative address
-  }
+  unsigned getStubAlignment() override { return 1; }
+
+  // 2-byte jmp instruction + 32-bit relative address + 64-bit absolute jump
+  unsigned getMaxStubSize() override { return 14; }
 
   // The target location for the relocation is described by RE.SectionID and
   // RE.Offset.  RE.SectionID can be used to find the SectionEntry.  Each
@@ -85,13 +103,17 @@ public:
     }
 
     case COFF::IMAGE_REL_AMD64_ADDR32NB: {
-      // Note ADDR32NB requires a well-established notion of
-      // image base. This address must be less than or equal
-      // to every section's load address, and all sections must be
-      // within a 32 bit offset from the base.
-      //
-      // For now we just set these to zero.
-      writeBytesUnaligned(0, Target, 4);
+      // ADDR32NB requires an offset less than 2GB from 'ImageBase'.
+      // The MemoryManager can make sure this is always true by forcing the
+      // memory layout to be: CodeSection < ReadOnlySection < ReadWriteSection.
+      const uint64_t ImageBase = getImageBase();
+      if (Value < ImageBase || ((Value - ImageBase) > UINT32_MAX)) {
+        llvm::errs() << "IMAGE_REL_AMD64_ADDR32NB relocation requires an"
+                     << "ordered section layout.\n";
+        write32BitOffset(Target, 0, 0);
+      } else {
+        write32BitOffset(Target, RE.Addend, Value - ImageBase);
+      }
       break;
     }
 
@@ -106,6 +128,51 @@ public:
     }
   }
 
+  std::tuple<uint64_t, uint64_t, uint64_t>
+  generateRelocationStub(unsigned SectionID, StringRef TargetName,
+                         uint64_t Offset, uint64_t RelType, uint64_t Addend,
+                         StubMap &Stubs) {
+    uintptr_t StubOffset;
+    SectionEntry &Section = Sections[SectionID];
+
+    RelocationValueRef OriginalRelValueRef;
+    OriginalRelValueRef.SectionID = SectionID;
+    OriginalRelValueRef.Offset = Offset;
+    OriginalRelValueRef.Addend = Addend;
+    OriginalRelValueRef.SymbolName = TargetName.data();
+
+    auto Stub = Stubs.find(OriginalRelValueRef);
+    if (Stub == Stubs.end()) {
+      DEBUG(dbgs() << " Create a new stub function for " << TargetName.data()
+                   << "\n");
+
+      StubOffset = Section.getStubOffset();
+      Stubs[OriginalRelValueRef] = StubOffset;
+      createStubFunction(Section.getAddressWithOffset(StubOffset));
+      Section.advanceStubOffset(getMaxStubSize());
+    } else {
+      DEBUG(dbgs() << " Stub function found for " << TargetName.data() << "\n");
+      StubOffset = Stub->second;
+    }
+
+    // FIXME: If RelType == COFF::IMAGE_REL_AMD64_ADDR32NB we should be able
+    // to ignore the __ImageBase requirement and just forward to the stub
+    // directly as an offset of this section:
+    // write32BitOffset(Section.getAddressWithOffset(Offset), 0, StubOffset);
+    // .xdata exception handler's aren't having this though.
+
+    // Resolve original relocation to stub function.
+    const RelocationEntry RE(SectionID, Offset, RelType, Addend);
+    resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset));
+
+    // adjust relocation info so resolution writes to the stub function
+    Addend = 0;
+    Offset = StubOffset + 6;
+    RelType = COFF::IMAGE_REL_AMD64_ADDR64;
+
+    return std::make_tuple(Offset, RelType, Addend);
+  }
+
   Expected<relocation_iterator>
   processRelocationRef(unsigned SectionID,
                        relocation_iterator RelI,
@@ -131,6 +198,11 @@ public:
     SectionEntry &Section = Sections[SectionID];
     uintptr_t ObjTarget = Section.getObjAddress() + Offset;
 
+    Expected<StringRef> TargetNameOrErr = Symbol->getName();
+    if (!TargetNameOrErr)
+      return TargetNameOrErr.takeError();
+    StringRef TargetName = *TargetNameOrErr;
+
     switch (RelType) {
 
     case COFF::IMAGE_REL_AMD64_REL32:
@@ -142,6 +214,11 @@ public:
     case COFF::IMAGE_REL_AMD64_ADDR32NB: {
       uint8_t *Displacement = (uint8_t *)ObjTarget;
       Addend = readBytesUnaligned(Displacement, 4);
+
+      if (IsExtern)
+        std::tie(Offset, RelType, Addend) = generateRelocationStub(
+          SectionID, TargetName, Offset, RelType, Addend, Stubs);
+
       break;
     }
 
@@ -155,11 +232,6 @@ public:
       break;
     }
 
-    Expected<StringRef> TargetNameOrErr = Symbol->getName();
-    if (!TargetNameOrErr)
-      return TargetNameOrErr.takeError();
-    StringRef TargetName = *TargetNameOrErr;
-
     DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
                  << " RelType: " << RelType << " TargetName: " << TargetName
                  << " Addend " << Addend << "\n");
@@ -183,7 +255,6 @@ public:
     return ++RelI;
   }
 
-  unsigned getStubAlignment() override { return 1; }
   void registerEHFrames() override {
     for (auto const &EHFrameSID : UnregisteredEHFrameSections) {
       uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress();
@@ -194,6 +265,7 @@ public:
     }
     UnregisteredEHFrameSections.clear();
   }
+
   Error finalizeLoad(const ObjectFile &Obj,
                      ObjSectionToIDMap &SectionMap) override {
     // Look for and record the EH frame section IDs.
@@ -202,11 +274,12 @@ public:
       StringRef Name;
       if (auto EC = Section.getName(Name))
         return errorCodeToError(EC);
-      // Note unwind info is split across .pdata and .xdata, so this
-      // may not be sufficiently general for all users.
-      if (Name == ".xdata") {
+
+      // Note unwind info is stored in .pdata but often points to .xdata
+      // with an IMAGE_REL_AMD64_ADDR32NB relocation. Using a memory manager
+      // that keeps sections ordered in relation to __ImageBase is necessary.
+      if (Name == ".pdata")
         UnregisteredEHFrameSections.push_back(SectionPair.second);
-      }
     }
     return Error::success();
   }

Added: llvm/trunk/test/ExecutionEngine/RuntimeDyld/X86/COFF_x86_64_IMGREL.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/RuntimeDyld/X86/COFF_x86_64_IMGREL.s?rev=325700&view=auto
==============================================================================
--- llvm/trunk/test/ExecutionEngine/RuntimeDyld/X86/COFF_x86_64_IMGREL.s (added)
+++ llvm/trunk/test/ExecutionEngine/RuntimeDyld/X86/COFF_x86_64_IMGREL.s Wed Feb 21 09:18:20 2018
@@ -0,0 +1,26 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=x86_64-pc-win32 -filetype=obj -o %t/COFF_x86_64_IMGREL.o %s
+# RUN: llvm-rtdyld -triple=x86_64-pc-win32 -verify -check=%s %t/COFF_x86_64_IMGREL.o
+.text
+	.def	 F;
+	.scl	2;
+	.type	32;
+	.endef
+	.globl	__constdata
+
+.section    .rdata, "dr", discard, __constdata
+    .align	8
+    __constdata:
+	    .quad	0
+
+.text
+	.globl	F
+	.align	16, 0x90
+
+F:                                      # @F
+# rtdyld-check: decode_operand(inst1, 3) = section_addr(COFF_x86_64_IMGREL.o, .text)+0
+inst1:
+    mov %ebx, F at IMGREL
+# rtdyld-check: decode_operand(inst2, 3) = section_addr(COFF_x86_64_IMGREL.o, .rdata)+5
+inst2:
+    mov %ebx, (__constdata at imgrel+5)




More information about the llvm-commits mailing list