summaryrefslogtreecommitdiffstats
path: root/lld/lib
diff options
context:
space:
mode:
authorTim Northover <tnorthover@apple.com>2014-10-15 18:19:31 +0000
committerTim Northover <tnorthover@apple.com>2014-10-15 18:19:31 +0000
commita6a6ab994956b898ce64e7f65bfd03273627019e (patch)
treeb67b93419f910f6467377b3ceb787f1b27ed32e4 /lld/lib
parent1a74aff84653ec6c428df97fc09fc8cbcb82d334 (diff)
downloadbcm5719-llvm-a6a6ab994956b898ce64e7f65bfd03273627019e.tar.gz
bcm5719-llvm-a6a6ab994956b898ce64e7f65bfd03273627019e.zip
[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 llvm-svn: 219824
Diffstat (limited to 'lld/lib')
-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
7 files changed, 135 insertions, 1 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;
OpenPOWER on IntegriCloud