[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 §ion : 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