summaryrefslogtreecommitdiff
path: root/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp')
-rw-r--r--llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp178
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