From b18a506abeee718df575d9720bc4aeda0325985a Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Sun, 12 May 2019 22:26:33 +0000 Subject: [PATCH] [JITLink] Add a test for zero-filled content. Also updates RuntimeDyldChecker and llvm-rtdyld to support zero-fill tests by returning a content address of zero (but no error) for zero-fill atoms, and treating loads from zero as returning zero. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@360547 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../llvm/ExecutionEngine/RuntimeDyldChecker.h | 60 ++++++++++++++++++- .../JITLink/MachOAtomGraphBuilder.h | 2 +- .../RuntimeDyld/RuntimeDyldChecker.cpp | 36 +++++++---- .../JITLink/X86/MachO_x86-64_relocations.s | 5 ++ tools/llvm-jitlink/llvm-jitlink-macho.cpp | 39 ++++++++---- tools/llvm-jitlink/llvm-jitlink.cpp | 9 +-- tools/llvm-rtdyld/llvm-rtdyld.cpp | 20 +++---- 7 files changed, 132 insertions(+), 39 deletions(-) diff --git a/include/llvm/ExecutionEngine/RuntimeDyldChecker.h b/include/llvm/ExecutionEngine/RuntimeDyldChecker.h index 2897c8ebca8..93ea09107bd 100644 --- a/include/llvm/ExecutionEngine/RuntimeDyldChecker.h +++ b/include/llvm/ExecutionEngine/RuntimeDyldChecker.h @@ -73,9 +73,63 @@ class raw_ostream; /// class RuntimeDyldChecker { public: - struct MemoryRegionInfo { - StringRef Content; - JITTargetAddress TargetAddress; + class MemoryRegionInfo { + public: + MemoryRegionInfo() = default; + + /// Constructor for symbols/sections with content. + MemoryRegionInfo(StringRef Content, JITTargetAddress TargetAddress) + : ContentPtr(Content.data()), Size(Content.size()), + TargetAddress(TargetAddress) {} + + /// Constructor for zero-fill symbols/sections. + MemoryRegionInfo(uint64_t Size, JITTargetAddress TargetAddress) + : Size(Size), TargetAddress(TargetAddress) {} + + /// Returns true if this is a zero-fill symbol/section. + bool isZeroFill() const { + assert(Size && "setContent/setZeroFill must be called first"); + return !ContentPtr; + } + + /// Set the content for this memory region. + void setContent(StringRef Content) { + assert(!ContentPtr && !Size && "Content/zero-fill already set"); + ContentPtr = Content.data(); + Size = Content.size(); + } + + /// Set a zero-fill length for this memory region. + void setZeroFill(uint64_t Size) { + assert(!ContentPtr && !this->Size && "Content/zero-fill already set"); + this->Size = Size; + } + + /// Returns the content for this section if there is any. + StringRef getContent() const { + assert(!isZeroFill() && "Can't get content for a zero-fill section"); + return StringRef(ContentPtr, static_cast(Size)); + } + + /// Returns the zero-fill length for this section. + uint64_t getZeroFillLength() const { + assert(isZeroFill() && "Can't get zero-fill length for content section"); + return Size; + } + + /// Set the target address for this region. + void setTargetAddress(JITTargetAddress TargetAddress) { + assert(!this->TargetAddress && "TargetAddress already set"); + this->TargetAddress = TargetAddress; + } + + /// Return the target address for this region. + JITTargetAddress getTargetAddress() const { return TargetAddress; } + + private: + const char *ContentPtr = 0; + uint64_t Size = 0; + JITTargetAddress TargetAddress = 0; }; using IsSymbolValidFunction = std::function; diff --git a/lib/ExecutionEngine/JITLink/MachOAtomGraphBuilder.h b/lib/ExecutionEngine/JITLink/MachOAtomGraphBuilder.h index ce6a65b11ea..72d441b24d0 100644 --- a/lib/ExecutionEngine/JITLink/MachOAtomGraphBuilder.h +++ b/lib/ExecutionEngine/JITLink/MachOAtomGraphBuilder.h @@ -62,7 +62,7 @@ protected: } MachOSection &setZeroFill(uint64_t Size) { - assert(!ContentPtr && !Size && "Content/zeroFill already set"); + assert(!ContentPtr && !this->Size && "Content/zeroFill already set"); this->Size = Size; return *this; } diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp index e801ebd1cde..ec31ea4e573 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp @@ -526,6 +526,11 @@ private: uint64_t LoadAddr = LoadAddrExprResult.getValue(); + // If there is no error but the content pointer is null then this is a + // zero-fill symbol/section. + if (LoadAddr == 0) + return std::make_pair(0, RemainingExpr); + return std::make_pair( EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)), RemainingExpr); @@ -735,8 +740,12 @@ uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const { logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); return 0; } + + if (SymInfo->isZeroFill()) + return 0; + return static_cast( - reinterpret_cast(SymInfo->Content.data())); + reinterpret_cast(SymInfo->getContent().data())); } uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const { @@ -746,7 +755,7 @@ uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const { return 0; } - return SymInfo->TargetAddress; + return SymInfo->getTargetAddress(); } uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr, @@ -774,7 +783,7 @@ StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const { logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); return StringRef(); } - return SymInfo->Content; + return SymInfo->getContent(); } std::pair RuntimeDyldCheckerImpl::getSectionAddr( @@ -796,10 +805,13 @@ std::pair RuntimeDyldCheckerImpl::getSectionAddr( uint64_t Addr = 0; - if (IsInsideLoad) - Addr = pointerToJITTargetAddress(SecInfo->Content.data()); - else - Addr = SecInfo->TargetAddress; + if (IsInsideLoad) { + if (SecInfo->isZeroFill()) + Addr = 0; + else + Addr = pointerToJITTargetAddress(SecInfo->getContent().data()); + } else + Addr = SecInfo->getTargetAddress(); return std::make_pair(Addr, ""); } @@ -823,10 +835,12 @@ std::pair RuntimeDyldCheckerImpl::getStubOrGOTAddrFor( uint64_t Addr = 0; - if (IsInsideLoad) - Addr = pointerToJITTargetAddress(StubInfo->Content.data()); - else - Addr = StubInfo->TargetAddress; + if (IsInsideLoad) { + if (StubInfo->isZeroFill()) + return std::make_pair((uint64_t)0, "Detected zero-filled stub/GOT entry"); + Addr = pointerToJITTargetAddress(StubInfo->getContent().data()); + } else + Addr = StubInfo->getTargetAddress(); return std::make_pair(Addr, ""); } diff --git a/test/ExecutionEngine/JITLink/X86/MachO_x86-64_relocations.s b/test/ExecutionEngine/JITLink/X86/MachO_x86-64_relocations.s index 6c3d9036363..b306a490ebe 100644 --- a/test/ExecutionEngine/JITLink/X86/MachO_x86-64_relocations.s +++ b/test/ExecutionEngine/JITLink/X86/MachO_x86-64_relocations.s @@ -272,4 +272,9 @@ subtractor_with_alt_entry_subtrahend_quad_B: .section __DATA,__nds_test_sect,regular,no_dead_strip .quad 0 +# Check that explicit zero-fill symbols are supported +# jitlink-check: *{8}zero_fill_test = 0 + .globl zero_fill_test +.zerofill __DATA,__zero_fill_test,zero_fill_test,8,3 + .subsections_via_symbols diff --git a/tools/llvm-jitlink/llvm-jitlink-macho.cpp b/tools/llvm-jitlink/llvm-jitlink-macho.cpp index c3a12421dac..067c38a56cd 100644 --- a/tools/llvm-jitlink/llvm-jitlink-macho.cpp +++ b/tools/llvm-jitlink/llvm-jitlink-macho.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// . +// MachO parsing support for llvm-jitlink. // //===----------------------------------------------------------------------===// @@ -105,8 +105,6 @@ Error registerMachOStubsAndGOT(Session &S, AtomGraph &G) { bool isGOTSection = isMachOGOTSection(Sec); bool isStubsSection = isMachOStubsSection(Sec); - auto &SectionInfo = FileInfo.SectionInfos[Sec.getName()]; - auto *FirstAtom = *Sec.atoms().begin(); auto *LastAtom = FirstAtom; for (auto *DA : Sec.atoms()) { @@ -115,25 +113,46 @@ Error registerMachOStubsAndGOT(Session &S, AtomGraph &G) { if (DA->getAddress() > LastAtom->getAddress()) LastAtom = DA; if (isGOTSection) { + if (Sec.isZeroFill()) + return make_error("Content atom in zero-fill section", + inconvertibleErrorCode()); + if (auto TA = getMachOGOTTarget(G, *DA)) { FileInfo.GOTEntryInfos[TA->getName()] = {DA->getContent(), DA->getAddress()}; } else return TA.takeError(); } else if (isStubsSection) { + if (Sec.isZeroFill()) + return make_error("Content atom in zero-fill section", + inconvertibleErrorCode()); + if (auto TA = getMachOStubTarget(G, *DA)) FileInfo.StubInfos[TA->getName()] = {DA->getContent(), DA->getAddress()}; else return TA.takeError(); - } else if (DA->hasName() && DA->isGlobal()) - S.SymbolInfos[DA->getName()] = {DA->getContent(), DA->getAddress()}; + } else if (DA->hasName() && DA->isGlobal()) { + if (DA->isZeroFill()) + S.SymbolInfos[DA->getName()] = {DA->getSize(), DA->getAddress()}; + else { + if (Sec.isZeroFill()) + return make_error("Content atom in zero-fill section", + inconvertibleErrorCode()); + S.SymbolInfos[DA->getName()] = {DA->getContent(), DA->getAddress()}; + } + } } - const char *StartAddr = FirstAtom->getContent().data(); - const char *EndAddr = - LastAtom->getContent().data() + LastAtom->getContent().size(); - SectionInfo.TargetAddress = FirstAtom->getAddress(); - SectionInfo.Content = StringRef(StartAddr, EndAddr - StartAddr); + + JITTargetAddress SecAddr = FirstAtom->getAddress(); + uint64_t SecSize = (LastAtom->getAddress() + LastAtom->getSize()) - + FirstAtom->getAddress(); + + if (Sec.isZeroFill()) + FileInfo.SectionInfos[Sec.getName()] = {SecSize, SecAddr}; + else + FileInfo.SectionInfos[Sec.getName()] = { + StringRef(FirstAtom->getContent().data(), SecSize), SecAddr}; } return Error::success(); diff --git a/tools/llvm-jitlink/llvm-jitlink.cpp b/tools/llvm-jitlink/llvm-jitlink.cpp index 5ecf66ae9e4..97956f6513d 100644 --- a/tools/llvm-jitlink/llvm-jitlink.cpp +++ b/tools/llvm-jitlink/llvm-jitlink.cpp @@ -104,10 +104,11 @@ namespace llvm { static raw_ostream & operator<<(raw_ostream &OS, const Session::MemoryRegionInfo &MRI) { - return OS << "target addr = " << format("0x%016" PRIx64, MRI.TargetAddress) - << ", content: " << (const void *)MRI.Content.data() << " -- " - << (const void *)(MRI.Content.data() + MRI.Content.size()) << " (" - << MRI.Content.size() << " bytes)"; + return OS << "target addr = " + << format("0x%016" PRIx64, MRI.getTargetAddress()) + << ", content: " << (const void *)MRI.getContent().data() << " -- " + << (const void *)(MRI.getContent().data() + MRI.getContent().size()) + << " (" << MRI.getContent().size() << " bytes)"; } static raw_ostream & diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index d8382a1d29f..a52650b941d 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -774,7 +774,7 @@ static int linkAndVerify() { // First get the target address. if (auto InternalSymbol = Dyld.getSymbol(Symbol)) - SymInfo.TargetAddress = InternalSymbol.getAddress(); + SymInfo.setTargetAddress(InternalSymbol.getAddress()); else { // Symbol not found in RuntimeDyld. Fall back to external lookup. #ifdef _MSC_VER @@ -799,7 +799,7 @@ static int linkAndVerify() { auto I = Result->find(Symbol); assert(I != Result->end() && "Expected symbol address if no error occurred"); - SymInfo.TargetAddress = I->second.getAddress(); + SymInfo.setTargetAddress(I->second.getAddress()); } // Now find the symbol content if possible (otherwise leave content as a @@ -810,7 +810,7 @@ static int linkAndVerify() { char *CSymAddr = static_cast(SymAddr); StringRef SecContent = Dyld.getSectionContent(SectionID); uint64_t SymSize = SecContent.size() - (CSymAddr - SecContent.data()); - SymInfo.Content = StringRef(CSymAddr, SymSize); + SymInfo.setContent(StringRef(CSymAddr, SymSize)); } } return SymInfo; @@ -824,7 +824,7 @@ static int linkAndVerify() { logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); return false; } - return SymInfo->TargetAddress != 0; + return SymInfo->getTargetAddress() != 0; }; FileToSectionIDMap FileToSecIDMap; @@ -836,8 +836,8 @@ static int linkAndVerify() { if (!SectionID) return SectionID.takeError(); RuntimeDyldChecker::MemoryRegionInfo SecInfo; - SecInfo.TargetAddress = Dyld.getSectionLoadAddress(*SectionID); - SecInfo.Content = Dyld.getSectionContent(*SectionID); + SecInfo.setTargetAddress(Dyld.getSectionLoadAddress(*SectionID)); + SecInfo.setContent(Dyld.getSectionContent(*SectionID)); return SecInfo; }; @@ -854,10 +854,10 @@ static int linkAndVerify() { inconvertibleErrorCode()); auto &SI = StubMap[StubContainer][SymbolName]; RuntimeDyldChecker::MemoryRegionInfo StubMemInfo; - StubMemInfo.TargetAddress = - Dyld.getSectionLoadAddress(SI.SectionID) + SI.Offset; - StubMemInfo.Content = - Dyld.getSectionContent(SI.SectionID).substr(SI.Offset); + StubMemInfo.setTargetAddress(Dyld.getSectionLoadAddress(SI.SectionID) + + SI.Offset); + StubMemInfo.setContent( + Dyld.getSectionContent(SI.SectionID).substr(SI.Offset)); return StubMemInfo; }; -- 2.50.1