[lld] r219824 - [macho] Create references from __eh_frame FDEs to their function.

Tim Northover tnorthover at apple.com
Wed Oct 15 11:19:32 PDT 2014


Author: tnorthover
Date: Wed Oct 15 13:19:31 2014
New Revision: 219824

URL: http://llvm.org/viewvc/llvm-project?rev=219824&view=rev
Log:
[macho] Create references from __eh_frame FDEs to their function.

We'll also need references back to the CIE eventually, but for now making sure
we can work out what an FDE is referring to is enough.

The actual kind of reference needs to be different between architectures,
probably because of MachO's chronic shortage of relocation types but I don't
really want to know in case I find out something that distresses me even more.

rdar://problem/18208653

Modified:
    lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h
    lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
    lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
    lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
    lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
    lld/trunk/lib/ReaderWriter/MachO/File.h
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
    lld/trunk/test/mach-o/parse-eh-frame-x86-anon.yaml
    lld/trunk/test/mach-o/parse-eh-frame.yaml

Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h?rev=219824&r1=219823&r2=219824&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler.h Wed Oct 15 13:19:31 2014
@@ -70,6 +70,10 @@ public:
   /// section.
   virtual Reference::KindValue imageOffsetKindIndirect() = 0;
 
+  /// Reference from an __eh_frame FDE atom to the function it's
+  /// describing. Usually pointer-sized and PC-relative, but differs in whether
+  /// it needs to be in relocatable objects.
+  virtual Reference::KindValue unwindRefToFunctionKind() = 0;
 
   /// Used by normalizedFromAtoms() to know where to generated rebasing and 
   /// binding info in final executables.

Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp?rev=219824&r1=219823&r2=219824&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm.cpp Wed Oct 15 13:19:31 2014
@@ -48,6 +48,10 @@ public:
     return invalid;
   }
 
+  Reference::KindValue unwindRefToFunctionKind() override {
+    return invalid;
+  }
+
   std::error_code getReferenceInfo(const normalized::Relocation &reloc,
                                    const DefinedAtom *inAtom,
                                    uint32_t offsetInAtom,

Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp?rev=219824&r1=219823&r2=219824&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp Wed Oct 15 13:19:31 2014
@@ -91,6 +91,10 @@ public:
     return invalid;
   }
 
+  Reference::KindValue unwindRefToFunctionKind() override {
+    return invalid;
+  }
+
   std::error_code getReferenceInfo(const normalized::Relocation &reloc,
                                    const DefinedAtom *inAtom,
                                    uint32_t offsetInAtom,

Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86.cpp?rev=219824&r1=219823&r2=219824&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86.cpp Wed Oct 15 13:19:31 2014
@@ -51,6 +51,10 @@ public:
     return invalid;
   }
 
+  Reference::KindValue unwindRefToFunctionKind() override{
+    return delta32;
+  }
+
   std::error_code getReferenceInfo(const normalized::Relocation &reloc,
                                    const DefinedAtom *inAtom,
                                    uint32_t offsetInAtom,

Modified: lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp?rev=219824&r1=219823&r2=219824&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp Wed Oct 15 13:19:31 2014
@@ -84,6 +84,11 @@ public:
     return imageOffsetGot;
   }
 
+  Reference::KindValue unwindRefToFunctionKind() override{
+    return unwindFDEToFunction;
+  }
+
+
   const StubInfo &stubInfo() override { return _sStubInfo; }
 
   bool isNonCallBranch(const Reference &) override {
@@ -165,6 +170,8 @@ private:
     imageOffset,           /// Location contains offset of atom in final image
     imageOffsetGot,        /// Location contains offset of GOT entry for atom in
                            /// final image (typically personality function).
+    unwindFDEToFunction,   /// Nearly delta64, but cannot be rematerialized in
+                           /// relocatable object (yay for implicit contracts!).
 
   };
 
@@ -202,6 +209,7 @@ const Registry::KindStrings ArchHandler_
   LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64),
   LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon),
   LLD_KIND_STRING_ENTRY(imageOffset), LLD_KIND_STRING_ENTRY(imageOffsetGot),
+  LLD_KIND_STRING_ENTRY(unwindFDEToFunction),
   LLD_KIND_STRING_END
 };
 
@@ -482,6 +490,7 @@ void ArchHandler_x86_64::applyFixupFinal
     return;
   case delta64:
   case delta64Anon:
+  case unwindFDEToFunction:
     write64(*loc64, _swap, (targetAddress - fixupAddress) + ref.addend());
     return;
   case ripRel32GotLoadNowLea:
@@ -561,6 +570,9 @@ void ArchHandler_x86_64::applyFixupReloc
   case imageOffsetGot:
     llvm_unreachable("image offset implies __unwind_info");
     return;
+  case unwindFDEToFunction:
+    // Do nothing for now
+    return;
   case invalid:
     // Fall into llvm_unreachable().
     break;
@@ -645,6 +657,8 @@ void ArchHandler_x86_64::appendSectionRe
     appendReloc(relocs, sectionOffset, sectionIndexForAtom(*ref.target()), 0,
                 X86_64_RELOC_UNSIGNED             | rLength8 );
     return;
+  case unwindFDEToFunction:
+    return;
   case ripRel32GotLoadNowLea:
     llvm_unreachable("ripRel32GotLoadNowLea implies GOT pass was run");
     return;

Modified: lld/trunk/lib/ReaderWriter/MachO/File.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/File.h?rev=219824&r1=219823&r2=219824&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/File.h (original)
+++ lld/trunk/lib/ReaderWriter/MachO/File.h Wed Oct 15 13:19:31 2014
@@ -132,7 +132,7 @@ public:
       *foundOffsetAtom = offsetInSect - atomPos->offset;
     return atomPos->atom;
   }
-  
+
   /// Searches this file for an UndefinedAtom named 'name'. Returns
   /// nullptr is no such atom found.
   const lld::Atom *findUndefAtom(StringRef name) {
@@ -152,6 +152,19 @@ public:
     }
   }
 
+  typedef std::function<void(MachODefinedAtom *atom, uint64_t offset)>
+      SectionAtomVisitor;
+
+  void eachAtomInSection(const Section &section, SectionAtomVisitor visitor) {
+    auto pos = _sectionAtoms.find(&section);
+    if (pos == _sectionAtoms.end())
+      return;
+    auto vec = pos->second;
+
+    for (auto &offAndAtom : vec)
+      visitor(offAndAtom.atom, offAndAtom.offset);
+  }
+
   llvm::BumpPtrAllocator &allocator() { return _allocator; }
   
 private:

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp?rev=219824&r1=219823&r2=219824&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp Wed Oct 15 13:19:31 2014
@@ -466,6 +466,22 @@ const Section* findSectionCoveringAddres
   return nullptr;
 }
 
+const MachODefinedAtom *
+findAtomCoveringAddress(const NormalizedFile &normalizedFile, MachOFile &file,
+                        uint64_t addr, Reference::Addend *addend) {
+  const Section *sect = nullptr;
+  sect = findSectionCoveringAddress(normalizedFile, addr);
+  if (!sect)
+    return nullptr;
+
+  uint32_t offsetInTarget;
+  uint64_t offsetInSect = addr - sect->address;
+  auto atom =
+      file.findAtomCoveringAddress(*sect, offsetInSect, &offsetInTarget);
+  *addend = offsetInTarget;
+  return atom;
+}
+
 // Walks all relocations for a section in a normalized .o file and
 // creates corresponding lld::Reference objects.
 std::error_code convertRelocs(const Section &section,
@@ -605,6 +621,74 @@ bool isDebugInfoSection(const Section &s
   return section.segmentName.equals("__DWARF");
 }
 
+static bool isCIE(bool swap, const DefinedAtom *atom) {
+  assert(atom->contentType() == DefinedAtom::typeCFI);
+  uint32_t size = read32(swap, *(uint32_t *)atom->rawContent().data());
+
+  uint32_t idOffset = sizeof(uint32_t);
+  if (size == 0xffffffffU)
+    idOffset += sizeof(uint64_t);
+
+  return read32(swap, *(uint32_t *)(atom->rawContent().data() + idOffset)) == 0;
+}
+
+static int64_t readSPtr(bool is64, bool swap, const uint8_t *addr) {
+  if (is64)
+    return read64(swap, *reinterpret_cast<const uint64_t *>(addr));
+
+  int32_t res = read32(swap, *reinterpret_cast<const uint32_t *>(addr));
+  return res;
+}
+
+std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
+                                     MachOFile &file,
+                                     mach_o::ArchHandler &handler) {
+  const bool swap = !MachOLinkingContext::isHostEndian(normalizedFile.arch);
+  const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+
+  const Section *ehFrameSection = nullptr;
+  for (auto &section : normalizedFile.sections)
+    if (section.segmentName == "__TEXT" &&
+        section.sectionName == "__eh_frame") {
+      ehFrameSection = §ion;
+      break;
+    }
+
+  // No __eh_frame so nothing to do.
+  if (!ehFrameSection)
+    return std::error_code();
+
+  file.eachAtomInSection(*ehFrameSection,
+                         [&](MachODefinedAtom *atom, uint64_t offset) -> void {
+    assert(atom->contentType() == DefinedAtom::typeCFI);
+
+    if (isCIE(swap, atom))
+      return;
+
+    // Compiler wasn't lazy and actually told us what it meant.
+    if (atom->begin() != atom->end())
+      return;
+
+    const uint8_t *frameData = atom->rawContent().data();
+    uint32_t size = read32(swap, *(uint32_t *)frameData);
+    uint64_t rangeFieldInFDE = size == 0xffffffffU
+                                   ? 2 * sizeof(uint32_t) + sizeof(uint64_t)
+                                   : 2 * sizeof(uint32_t);
+
+    int64_t functionFromFDE = readSPtr(is64, swap, frameData + rangeFieldInFDE);
+    uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE;
+    rangeStart += functionFromFDE;
+
+    Reference::Addend addend;
+    const Atom *func =
+        findAtomCoveringAddress(normalizedFile, file, rangeStart, &addend);
+    atom->addReference(rangeFieldInFDE, handler.unwindRefToFunctionKind(), func,
+                       addend, handler.kindArch());
+  });
+  return std::error_code();
+}
+
+
 /// Converts normalized mach-o file into an lld::File and lld::Atoms.
 ErrorOr<std::unique_ptr<lld::File>>
 normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
@@ -648,6 +732,13 @@ normalizedObjectToAtoms(const Normalized
     handler->addAdditionalReferences(*atom);
   });
 
+  // Each __eh_frame section needs references to both __text (the function we're
+  // providing unwind info for) and itself (FDE -> CIE). These aren't
+  // represented in the relocations on some architectures, so we have to add
+  // them back in manually there.
+  if (std::error_code ec = addEHFrameReferences(normalizedFile, *file, *handler))
+    return ec;
+
   // Process mach-o data-in-code regions array. That information is encoded in
   // atoms as References at each transition point.
   unsigned nextIndex = 0;

Modified: lld/trunk/test/mach-o/parse-eh-frame-x86-anon.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/parse-eh-frame-x86-anon.yaml?rev=219824&r1=219823&r2=219824&view=diff
==============================================================================
--- lld/trunk/test/mach-o/parse-eh-frame-x86-anon.yaml (original)
+++ lld/trunk/test/mach-o/parse-eh-frame-x86-anon.yaml Wed Oct 15 13:19:31 2014
@@ -110,20 +110,20 @@ undefined-symbols:
 # CHECK:     content:          
 # CHECK:   - type:            unwind-cfi
 # CHECK:     content:         
-# FIXME:     references:      
+# CHECK:     references:
 # FIXME:       - kind:            negDelta32
 # FIXME:         offset:          4
 # FIXME:         target:          [[CIE]]
-# FIXME:       - kind:            delta32
-# FIXME:         offset:          8
-# FIXME:         target:          __Z3foov
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3foov
 # CHECK:   - type:            unwind-cfi
 # CHECK:     content:          
-# FIXME:     references:      
+# CHECK:     references:
 # FIXME:       - kind:            negDelta32
 # FIXME:         offset:          4
 # FIXME:         target:          [[CIE]]
-# FIXME:       - kind:            delta32
-# FIXME:         offset:          8
-# FIXME:         target:          __Z3barv
+# CHECK:       - kind:            delta32
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3barv
 

Modified: lld/trunk/test/mach-o/parse-eh-frame.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/parse-eh-frame.yaml?rev=219824&r1=219823&r2=219824&view=diff
==============================================================================
--- lld/trunk/test/mach-o/parse-eh-frame.yaml (original)
+++ lld/trunk/test/mach-o/parse-eh-frame.yaml Wed Oct 15 13:19:31 2014
@@ -59,11 +59,19 @@ global-symbols:
 # CHECK:                        FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
 # CHECK:                        00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
 # CHECK:                        00, 00, 00, 00 ]
+# CHECK:     references:
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3barv
 # CHECK:   - type:            unwind-cfi
 # CHECK:     content:         [ 24, 00, 00, 00, 44, 00, 00, 00, 6B, FF, FF, FF,
 # CHECK:                        FF, FF, FF, FF, 0B, 00, 00, 00, 00, 00, 00, 00,
 # CHECK:                        00, 41, 0E, 10, 86, 02, 43, 0D, 06, 00, 00, 00,
 # CHECK:                        00, 00, 00, 00 ]
+# CHECK:     references:
+# CHECK:       - kind:            unwindFDEToFunction
+# CHECK:         offset:          8
+# CHECK:         target:          __Z3foov
 # CHECK:   - name:            __Z3barv
 # CHECK:     scope:           global
 # CHECK:     content:         [ 55, 48, 89, E5, B8, 09, 00, 00, 00, 5D, C3 ]





More information about the llvm-commits mailing list