diff options
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler.h | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp | 14 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/File.h | 15 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp | 91 | ||||
| -rw-r--r-- | lld/test/mach-o/parse-eh-frame-x86-anon.yaml | 16 | ||||
| -rw-r--r-- | lld/test/mach-o/parse-eh-frame.yaml | 8 |
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 §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: 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 §ion, @@ -605,6 +621,74 @@ bool isDebugInfoSection(const Section §ion) { 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 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 ] |

