[lld] r237222 - [LLD] Properly relocate the LSDA field of MachO eh-frames.

Lang Hames lhames at gmail.com
Tue May 12 17:44:47 PDT 2015


Author: lhames
Date: Tue May 12 19:44:47 2015
New Revision: 237222

URL: http://llvm.org/viewvc/llvm-project?rev=237222&view=rev
Log:
[LLD] Properly relocate the LSDA field of MachO eh-frames.

Previously the LSDA field was not being relocated during linking, leading to
failures for some EH tests.

Added:
    lld/trunk/test/mach-o/parse-eh-frame-relocs-x86_64.yaml
Modified:
    lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp

Modified: lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp?rev=237222&r1=237221&r2=237222&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp (original)
+++ lld/trunk/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp Tue May 12 19:44:47 2015
@@ -29,6 +29,7 @@
 #include "lld/Core/LLVM.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/MachO.h"
+#include "llvm/Support/LEB128.h"
 
 using namespace llvm::MachO;
 using namespace lld::mach_o::normalized;
@@ -644,11 +645,147 @@ static int64_t readSPtr(bool is64, bool
   return res;
 }
 
+/// --- Augmentation String Processing ---
+
+struct AugmentationDataInfo {
+  bool _present = false;
+  bool _mayHaveLSDA = false;
+};
+
+static std::error_code processAugmentationString(const uint8_t *augStr,
+                                                 AugmentationDataInfo &adi,
+                                                 unsigned *len = nullptr) {
+
+  if (augStr[0] == '\0') {
+    if (len)
+      *len = 1;
+    return std::error_code();
+  }
+
+  if (augStr[0] != 'z')
+    return make_dynamic_error_code("expected 'z' at start of augmentation "
+                                   "string");
+
+  adi._present = true;
+  uint64_t idx = 1;
+
+  while (augStr[idx] != '\0') {
+    if (augStr[idx] == 'L') {
+      adi._mayHaveLSDA = true;
+      ++idx;
+    } else
+      ++idx;
+  }
+
+  if (len)
+    *len = idx + 1;
+  return std::error_code();
+}
+
+static std::error_code processCIE(const NormalizedFile &normalizedFile,
+                                  MachODefinedAtom *atom,
+                                  AugmentationDataInfo &adi) {
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+
+  const uint8_t *frameData = atom->rawContent().data();
+  uint32_t size = read32(frameData, isBig);
+  uint64_t cieIDField = size == 0xffffffffU
+                          ? sizeof(uint32_t) + sizeof(uint64_t)
+                          : sizeof(uint32_t);
+  uint64_t versionField = cieIDField + sizeof(uint32_t);
+  uint64_t augmentationStringField = versionField + sizeof(uint8_t);
+
+  if (auto err = processAugmentationString(frameData + augmentationStringField,
+                                           adi))
+    return err;
+
+  return std::error_code();
+}
+
+static std::error_code processFDE(const NormalizedFile &normalizedFile,
+                                  MachOFile &file,
+                                  mach_o::ArchHandler &handler,
+                                  const Section *ehFrameSection,
+                                  MachODefinedAtom *atom,
+                                  uint64_t offset,
+                                  const AugmentationDataInfo &adi) {
+
+  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+  const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
+
+  // Compiler wasn't lazy and actually told us what it meant.
+  if (atom->begin() != atom->end())
+    return std::error_code();
+
+  const uint8_t *frameData = atom->rawContent().data();
+  uint32_t size = read32(frameData, isBig);
+  uint64_t cieFieldInFDE = size == 0xffffffffU
+    ? sizeof(uint32_t) + sizeof(uint64_t)
+    : sizeof(uint32_t);
+
+  // Linker needs to fixup a reference from the FDE to its parent CIE (a
+  // 32-bit byte offset backwards in the __eh_frame section).
+  uint32_t cieDelta = read32(frameData + cieFieldInFDE, isBig);
+  uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE;
+  cieAddress -= cieDelta;
+
+  Reference::Addend addend;
+  const Atom *cie =
+    findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend);
+  atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie,
+                     addend, handler.kindArch());
+
+  // Linker needs to fixup reference from the FDE to the function it's
+  // describing. FIXME: there are actually different ways to do this, and the
+  // particular method used is specified in the CIE's augmentation fields
+  // (hopefully)
+  uint64_t rangeFieldInFDE = cieFieldInFDE + sizeof(uint32_t);
+
+  int64_t functionFromFDE = readSPtr(is64, isBig,
+                                     frameData + rangeFieldInFDE);
+  uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE;
+  rangeStart += functionFromFDE;
+
+  const Atom *func =
+    findAtomCoveringAddress(normalizedFile, file, rangeStart, &addend);
+  atom->addReference(rangeFieldInFDE, handler.unwindRefToFunctionKind(),
+                     func, addend, handler.kindArch());
+
+  // Handle the augmentation data if there is any.
+  if (adi._present) {
+    // First process the augmentation data length field.
+    uint64_t augmentationDataLengthFieldInFDE =
+      rangeFieldInFDE + 2 * (is64 ? sizeof(uint64_t) : sizeof(uint32_t));
+    unsigned lengthFieldSize = 0;
+    uint64_t augmentationDataLength =
+      llvm::decodeULEB128(frameData + augmentationDataLengthFieldInFDE,
+                          &lengthFieldSize);
+
+    if (adi._mayHaveLSDA && augmentationDataLength > 0) {
+
+      // Look at the augmentation data field.
+      uint64_t augmentationDataFieldInFDE =
+        augmentationDataLengthFieldInFDE + lengthFieldSize;
+
+      int64_t lsdaFromFDE = readSPtr(is64, isBig,
+                                     frameData + augmentationDataFieldInFDE);
+      uint64_t lsdaStart =
+        ehFrameSection->address + offset + augmentationDataFieldInFDE +
+        lsdaFromFDE;
+      const Atom *lsda =
+        findAtomCoveringAddress(normalizedFile, file, lsdaStart, &addend);
+      atom->addReference(augmentationDataFieldInFDE,
+                         handler.unwindRefToFunctionKind(),
+                         lsda, addend, handler.kindArch());
+    }
+  }
+
+  return std::error_code();
+}
+
 std::error_code addEHFrameReferences(const NormalizedFile &normalizedFile,
                                      MachOFile &file,
                                      mach_o::ArchHandler &handler) {
-  const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
-  const bool is64 = MachOLinkingContext::is64Bit(normalizedFile.arch);
 
   const Section *ehFrameSection = nullptr;
   for (auto &section : normalizedFile.sections)
@@ -662,51 +799,27 @@ std::error_code addEHFrameReferences(con
   if (!ehFrameSection)
     return std::error_code();
 
+  std::error_code ehFrameErr;
+  AugmentationDataInfo adi;
+
   file.eachAtomInSection(*ehFrameSection,
                          [&](MachODefinedAtom *atom, uint64_t offset) -> void {
     assert(atom->contentType() == DefinedAtom::typeCFI);
 
-    if (ArchHandler::isDwarfCIE(isBig, atom))
+    // Bail out if we've encountered an error.
+    if (ehFrameErr)
       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(frameData, isBig);
-    uint64_t cieFieldInFDE = size == 0xffffffffU
-                                   ? sizeof(uint32_t) + sizeof(uint64_t)
-                                   : sizeof(uint32_t);
-
-    // Linker needs to fixup a reference from the FDE to its parent CIE (a
-    // 32-bit byte offset backwards in the __eh_frame section).
-    uint32_t cieDelta = read32(frameData + cieFieldInFDE, isBig);
-    uint64_t cieAddress = ehFrameSection->address + offset + cieFieldInFDE;
-    cieAddress -= cieDelta;
-
-    Reference::Addend addend;
-    const Atom *cie =
-        findAtomCoveringAddress(normalizedFile, file, cieAddress, &addend);
-    atom->addReference(cieFieldInFDE, handler.unwindRefToCIEKind(), cie,
-                       addend, handler.kindArch());
-
-    // Linker needs to fixup reference from the FDE to the function it's
-    // describing. FIXME: there are actually different ways to do this, and the
-    // particular method used is specified in the CIE's augmentation fields
-    // (hopefully)
-    uint64_t rangeFieldInFDE = cieFieldInFDE + sizeof(uint32_t);
-
-    int64_t functionFromFDE = readSPtr(is64, isBig, frameData + rangeFieldInFDE);
-    uint64_t rangeStart = ehFrameSection->address + offset + rangeFieldInFDE;
-    rangeStart += functionFromFDE;
-
-    const Atom *func =
-        findAtomCoveringAddress(normalizedFile, file, rangeStart, &addend);
-    atom->addReference(rangeFieldInFDE, handler.unwindRefToFunctionKind(), func,
-                       addend, handler.kindArch());
+    const bool isBig = MachOLinkingContext::isBigEndian(normalizedFile.arch);
+    if (ArchHandler::isDwarfCIE(isBig, atom)) {
+      adi = AugmentationDataInfo();
+      ehFrameErr = processCIE(normalizedFile, atom, adi);
+    } else
+      ehFrameErr = processFDE(normalizedFile, file, handler, ehFrameSection,
+                              atom, offset, adi);
   });
-  return std::error_code();
+
+  return ehFrameErr;
 }
 
 

Added: lld/trunk/test/mach-o/parse-eh-frame-relocs-x86_64.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/mach-o/parse-eh-frame-relocs-x86_64.yaml?rev=237222&view=auto
==============================================================================
--- lld/trunk/test/mach-o/parse-eh-frame-relocs-x86_64.yaml (added)
+++ lld/trunk/test/mach-o/parse-eh-frame-relocs-x86_64.yaml Tue May 12 19:44:47 2015
@@ -0,0 +1,107 @@
+# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s
+#
+# Test parsing of x86_64 __eh_frame (dwarf unwind) relocations.
+#
+#_catchMyException:
+# pushq   %rbp
+# movq    %rsp, %rbp
+# callq   _foo
+# popq    %rbp
+# retq
+# movq    %rax, %rdi
+# callq   ___cxa_begin_catch
+# popq    %rbp
+# jmp     ___cxa_end_catch
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [  ]
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [0x55, 0x48, 0x89, 0xe5, 0xe8, 0x00, 0x00, 0x00,
+                      0x00, 0x5d, 0xc3, 0x48, 0x89, 0xc7, 0xe8, 0x00,
+                      0x00, 0x00, 0x00, 0x5d, 0xe9, 0x00, 0x00, 0x00,
+                      0x00, 0x00, 0x00, 0x00 ]
+    relocations:
+      - offset:          0x00000015
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          2
+      - offset:          0x0000000f
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          1
+      - offset:          0x00000005
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          0
+  - segment:         __TEXT
+    section:         __gcc_except_tab
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x000000000000001c
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    address:         0x0000000000000020
+    content:         [ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x01, 0x7a, 0x50, 0x4c, 0x52, 0x00, 0x01, 0x78,
+                       0x10, 0x07, 0x9b, 0x04, 0x00, 0x00, 0x00, 0x10,
+                       0x10, 0x0c, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00,
+                       0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
+                       0xB8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                       0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x08, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                       0xff, 0x41, 0x0e, 0x10, 0x86, 0x02, 0x43, 0x0d,
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+  - segment:         __DATA
+    section:         __data
+    type:            S_REGULAR
+    attributes:      [  ]
+    address:         0x0000000000000068
+    content:         [ 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:
+  - name:            _catchMyException
+    type:            N_SECT
+    sect:            1
+    value:           0x0000000000000000
+undefined-symbols:
+  - name:            _foo
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_begin_catch
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            ___cxa_end_catch
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+...
+
+# CHECK:       - type:            unwind-cfi
+# CHECK-NOT:   - type:
+# CHECK:         references:
+# CHECK-NEXT:      - kind:            negDelta32
+# CHECK-NEXT:        offset:          4
+# CHECK-NEXT:        target:          L000
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          8
+# CHECK-NEXT:        target:          _catchMyException
+# CHECK-NEXT:      - kind:            unwindFDEToFunction
+# CHECK-NEXT:        offset:          25
+# CHECK-NEXT:        target:          L001





More information about the llvm-commits mailing list