summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/lib/ReaderWriter/MachO/ArchHandler.h4
-rw-r--r--lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp4
-rw-r--r--lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp4
-rw-r--r--lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp4
-rw-r--r--lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp14
-rw-r--r--lld/lib/ReaderWriter/MachO/File.h15
-rw-r--r--lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp91
-rw-r--r--lld/test/mach-o/parse-eh-frame-x86-anon.yaml16
-rw-r--r--lld/test/mach-o/parse-eh-frame.yaml8
9 files changed, 151 insertions, 9 deletions
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.h b/lld/lib/ReaderWriter/MachO/ArchHandler.h
index 0c82d251b1c..51994b56200 100644
--- a/lld/lib/ReaderWriter/MachO/ArchHandler.h
+++ b/lld/lib/ReaderWriter/MachO/ArchHandler.h
@@ -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.
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
index 68350e2a689..163421aef75 100644
--- a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
+++ b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
@@ -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,
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
index 4320010ab11..eb6a460b9a2 100644
--- a/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
+++ b/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
@@ -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,
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
index d1f73b6dabb..bd086f2839b 100644
--- a/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
+++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
@@ -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,
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index fff07a5e4e9..315aba3d7b5 100644
--- a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -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_x86_64::_sKindStrings[] = {
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(const Reference &ref,
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::applyFixupRelocatable(const Reference &ref,
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::appendSectionRelocations(
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;
diff --git a/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h
index f3e77e788de..8bdce17613b 100644
--- a/lld/lib/ReaderWriter/MachO/File.h
+++ b/lld/lib/ReaderWriter/MachO/File.h
@@ -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:
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
index 8f83672cc35..a73a279abbc 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
@@ -466,6 +466,22 @@ const Section* findSectionCoveringAddress(const NormalizedFile &normalizedFile,
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 &section) {
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 = &section;
+ 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 NormalizedFile &normalizedFile, StringRef path,
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;
diff --git a/lld/test/mach-o/parse-eh-frame-x86-anon.yaml b/lld/test/mach-o/parse-eh-frame-x86-anon.yaml
index 088f14d5cec..67432e08894 100644
--- a/lld/test/mach-o/parse-eh-frame-x86-anon.yaml
+++ b/lld/test/mach-o/parse-eh-frame-x86-anon.yaml
@@ -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
diff --git a/lld/test/mach-o/parse-eh-frame.yaml b/lld/test/mach-o/parse-eh-frame.yaml
index da143fe04ed..799eb26e663 100644
--- a/lld/test/mach-o/parse-eh-frame.yaml
+++ b/lld/test/mach-o/parse-eh-frame.yaml
@@ -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 ]
OpenPOWER on IntegriCloud