[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 §ion, SectionAtomVisitor visitor) {
+ auto pos = _sectionAtoms.find(§ion);
+ 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 §ion,
@@ -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 §ion : 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