diff options
Diffstat (limited to 'llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp')
| -rw-r--r-- | llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp | 178 |
1 files changed, 142 insertions, 36 deletions
diff --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp index 03a8b98dff18..d588b63d9e88 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp @@ -23,7 +23,7 @@ MachOLinkGraphBuilder::~MachOLinkGraphBuilder() {} Expected<std::unique_ptr<LinkGraph>> MachOLinkGraphBuilder::buildGraph() { - // Sanity check: we only operate on relocatable objects. + // We only operate on relocatable objects. if (!Obj.isRelocatableObject()) return make_error<JITLinkError>("Object is not a relocatable MachO"); @@ -107,11 +107,9 @@ MachOLinkGraphBuilder::getEndianness(const object::MachOObjectFile &Obj) { } Section &MachOLinkGraphBuilder::getCommonSection() { - if (!CommonSection) { - auto Prot = static_cast<sys::Memory::ProtectionFlags>( - sys::Memory::MF_READ | sys::Memory::MF_WRITE); - CommonSection = &G->createSection(CommonSectionName, Prot); - } + if (!CommonSection) + CommonSection = + &G->createSection(CommonSectionName, MemProt::Read | MemProt::Write); return *CommonSection; } @@ -176,25 +174,16 @@ Error MachOLinkGraphBuilder::createNormalizedSections() { // Get prot flags. // FIXME: Make sure this test is correct (it's probably missing cases // as-is). - sys::Memory::ProtectionFlags Prot; + MemProt Prot; if (NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) - Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | - sys::Memory::MF_EXEC); + Prot = MemProt::Read | MemProt::Exec; else - Prot = static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ | - sys::Memory::MF_WRITE); + Prot = MemProt::Read | MemProt::Write; - if (!isDebugSection(NSec)) { - auto FullyQualifiedName = - G->allocateString(StringRef(NSec.SegName) + "," + NSec.SectName); - NSec.GraphSection = &G->createSection( - StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()), - Prot); - } else - LLVM_DEBUG({ - dbgs() << " " << NSec.SegName << "," << NSec.SectName - << " is a debug section: No graph section will be created.\n"; - }); + auto FullyQualifiedName = + G->allocateString(StringRef(NSec.SegName) + "," + NSec.SectName); + NSec.GraphSection = &G->createSection( + StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()), Prot); IndexToSection.insert(std::make_pair(SecIndex, std::move(NSec))); } @@ -292,15 +281,16 @@ Error MachOLinkGraphBuilder::createNormalizedSymbols() { dbgs() << "\n"; }); - // If this symbol has a section, sanity check that the addresses line up. + // If this symbol has a section, verify that the addresses line up. if (Sect != 0) { auto NSec = findSectionByIndex(Sect - 1); if (!NSec) return NSec.takeError(); if (Value < NSec->Address || Value > NSec->Address + NSec->Size) - return make_error<JITLinkError>("Symbol address does not fall within " - "section"); + return make_error<JITLinkError>("Address " + formatv("{0:x}", Value) + + " for symbol " + *Name + + " does not fall within section"); if (!NSec->GraphSection) { LLVM_DEBUG({ @@ -321,16 +311,19 @@ Error MachOLinkGraphBuilder::createNormalizedSymbols() { } void MachOLinkGraphBuilder::addSectionStartSymAndBlock( - Section &GraphSec, uint64_t Address, const char *Data, uint64_t Size, - uint32_t Alignment, bool IsLive) { + unsigned SecIndex, Section &GraphSec, uint64_t Address, const char *Data, + uint64_t Size, uint32_t Alignment, bool IsLive) { Block &B = Data ? G->createContentBlock(GraphSec, ArrayRef<char>(Data, Size), Address, Alignment, 0) : G->createZeroFillBlock(GraphSec, Size, Address, Alignment, 0); auto &Sym = G->addAnonymousSymbol(B, 0, Size, false, IsLive); - assert(!AddrToCanonicalSymbol.count(Sym.getAddress()) && + auto SecI = IndexToSection.find(SecIndex); + assert(SecI != IndexToSection.end() && "SecIndex invalid"); + auto &NSec = SecI->second; + assert(!NSec.CanonicalSymbols.count(Sym.getAddress()) && "Anonymous block start symbol clashes with existing symbol address"); - AddrToCanonicalSymbol[Sym.getAddress()] = &Sym; + NSec.CanonicalSymbols[Sym.getAddress()] = &Sym; } Error MachOLinkGraphBuilder::graphifyRegularSymbols() { @@ -444,8 +437,8 @@ Error MachOLinkGraphBuilder::graphifyRegularSymbols() { << formatv("{0:x16}", NSec.Address) << " -- " << formatv("{0:x16}", NSec.Address + NSec.Size) << "\n"; }); - addSectionStartSymAndBlock(*NSec.GraphSection, NSec.Address, NSec.Data, - NSec.Size, NSec.Alignment, + addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address, + NSec.Data, NSec.Size, NSec.Alignment, SectionIsNoDeadStrip); } else LLVM_DEBUG({ @@ -483,8 +476,8 @@ Error MachOLinkGraphBuilder::graphifyRegularSymbols() { << formatv("{0:x16}", NSec.Address) << " -- " << formatv("{0:x16}", NSec.Address + AnonBlockSize) << " ]\n"; }); - addSectionStartSymAndBlock(*NSec.GraphSection, NSec.Address, NSec.Data, - AnonBlockSize, NSec.Alignment, + addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address, + NSec.Data, AnonBlockSize, NSec.Alignment, SectionIsNoDeadStrip); } @@ -583,7 +576,7 @@ Symbol &MachOLinkGraphBuilder::createStandardGraphSymbol(NormalizedSymbol &NSym, NSym.GraphSymbol = &Sym; if (IsCanonical) - setCanonicalSymbol(Sym); + setCanonicalSymbol(getSectionByIndex(NSym.Sect - 1), Sym); return Sym; } @@ -610,7 +603,6 @@ Error MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() { Error MachOLinkGraphBuilder::graphifyCStringSection( NormalizedSection &NSec, std::vector<NormalizedSymbol *> NSyms) { - assert(NSec.GraphSection && "C string literal section missing graph section"); assert(NSec.Data && "C string literal section has no data"); @@ -664,7 +656,7 @@ Error MachOLinkGraphBuilder::graphifyCStringSection( // If there's no symbol at the start of this block then create one. if (NSyms.empty() || NSyms.back()->Value != B.getAddress()) { auto &S = G->addAnonymousSymbol(B, 0, BlockSize, false, false); - setCanonicalSymbol(S); + setCanonicalSymbol(NSec, S); LLVM_DEBUG({ dbgs() << " Adding anonymous symbol for c-string block " << formatv("{0:x16} -- {1:x16}", S.getAddress(), @@ -700,5 +692,119 @@ Error MachOLinkGraphBuilder::graphifyCStringSection( return Error::success(); } +Error CompactUnwindSplitter::operator()(LinkGraph &G) { + auto *CUSec = G.findSectionByName(CompactUnwindSectionName); + if (!CUSec) + return Error::success(); + + if (!G.getTargetTriple().isOSBinFormatMachO()) + return make_error<JITLinkError>( + "Error linking " + G.getName() + + ": compact unwind splitting not supported on non-macho target " + + G.getTargetTriple().str()); + + unsigned CURecordSize = 0; + unsigned PersonalityEdgeOffset = 0; + unsigned LSDAEdgeOffset = 0; + switch (G.getTargetTriple().getArch()) { + case Triple::aarch64: + case Triple::x86_64: + // 64-bit compact-unwind record format: + // Range start: 8 bytes. + // Range size: 4 bytes. + // CU encoding: 4 bytes. + // Personality: 8 bytes. + // LSDA: 8 bytes. + CURecordSize = 32; + PersonalityEdgeOffset = 16; + LSDAEdgeOffset = 24; + break; + default: + return make_error<JITLinkError>( + "Error linking " + G.getName() + + ": compact unwind splitting not supported on " + + G.getTargetTriple().getArchName()); + } + + std::vector<Block *> OriginalBlocks(CUSec->blocks().begin(), + CUSec->blocks().end()); + LLVM_DEBUG({ + dbgs() << "In " << G.getName() << " splitting compact unwind section " + << CompactUnwindSectionName << " containing " + << OriginalBlocks.size() << " initial blocks...\n"; + }); + + while (!OriginalBlocks.empty()) { + auto *B = OriginalBlocks.back(); + OriginalBlocks.pop_back(); + + if (B->getSize() == 0) { + LLVM_DEBUG({ + dbgs() << " Skipping empty block at " + << formatv("{0:x16}", B->getAddress()) << "\n"; + }); + continue; + } + + LLVM_DEBUG({ + dbgs() << " Splitting block at " << formatv("{0:x16}", B->getAddress()) + << " into " << (B->getSize() / CURecordSize) + << " compact unwind record(s)\n"; + }); + + if (B->getSize() % CURecordSize) + return make_error<JITLinkError>( + "Error splitting compact unwind record in " + G.getName() + + ": block at " + formatv("{0:x}", B->getAddress()) + " has size " + + formatv("{0:x}", B->getSize()) + + " (not a multiple of CU record size of " + + formatv("{0:x}", CURecordSize) + ")"); + + unsigned NumBlocks = B->getSize() / CURecordSize; + LinkGraph::SplitBlockCache C; + + for (unsigned I = 0; I != NumBlocks; ++I) { + auto &CURec = G.splitBlock(*B, CURecordSize, &C); + bool AddedKeepAlive = false; + + for (auto &E : CURec.edges()) { + if (E.getOffset() == 0) { + LLVM_DEBUG({ + dbgs() << " Updating compact unwind record at " + << formatv("{0:x16}", CURec.getAddress()) << " to point to " + << (E.getTarget().hasName() ? E.getTarget().getName() + : StringRef()) + << " (at " << formatv("{0:x16}", E.getTarget().getAddress()) + << ")\n"; + }); + + if (E.getTarget().isExternal()) + return make_error<JITLinkError>( + "Error adding keep-alive edge for compact unwind record at " + + formatv("{0:x}", CURec.getAddress()) + ": target " + + E.getTarget().getName() + " is an external symbol"); + auto &TgtBlock = E.getTarget().getBlock(); + auto &CURecSym = + G.addAnonymousSymbol(CURec, 0, CURecordSize, 0, false); + TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0); + AddedKeepAlive = true; + } else if (E.getOffset() != PersonalityEdgeOffset && + E.getOffset() != LSDAEdgeOffset) + return make_error<JITLinkError>("Unexpected edge at offset " + + formatv("{0:x}", E.getOffset()) + + " in compact unwind record at " + + formatv("{0:x}", CURec.getAddress())); + } + + if (!AddedKeepAlive) + return make_error<JITLinkError>( + "Error adding keep-alive edge for compact unwind record at " + + formatv("{0:x}", CURec.getAddress()) + + ": no outgoing target edge at offset 0"); + } + } + return Error::success(); +} + } // end namespace jitlink } // end namespace llvm |
