18bcb0991SDimitry Andric //=--------- MachOLinkGraphBuilder.cpp - MachO LinkGraph builder ----------===// 28bcb0991SDimitry Andric // 38bcb0991SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 48bcb0991SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 58bcb0991SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68bcb0991SDimitry Andric // 78bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 88bcb0991SDimitry Andric // 9*5f757f3fSDimitry Andric // Generic MachO LinkGraph building code. 108bcb0991SDimitry Andric // 118bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 128bcb0991SDimitry Andric 138bcb0991SDimitry Andric #include "MachOLinkGraphBuilder.h" 14bdd1243dSDimitry Andric #include <optional> 158bcb0991SDimitry Andric 168bcb0991SDimitry Andric #define DEBUG_TYPE "jitlink" 178bcb0991SDimitry Andric 188bcb0991SDimitry Andric static const char *CommonSectionName = "__common"; 198bcb0991SDimitry Andric 208bcb0991SDimitry Andric namespace llvm { 218bcb0991SDimitry Andric namespace jitlink { 228bcb0991SDimitry Andric 2381ad6265SDimitry Andric MachOLinkGraphBuilder::~MachOLinkGraphBuilder() = default; 248bcb0991SDimitry Andric 258bcb0991SDimitry Andric Expected<std::unique_ptr<LinkGraph>> MachOLinkGraphBuilder::buildGraph() { 268bcb0991SDimitry Andric 27349cc55cSDimitry Andric // We only operate on relocatable objects. 288bcb0991SDimitry Andric if (!Obj.isRelocatableObject()) 298bcb0991SDimitry Andric return make_error<JITLinkError>("Object is not a relocatable MachO"); 308bcb0991SDimitry Andric 318bcb0991SDimitry Andric if (auto Err = createNormalizedSections()) 328bcb0991SDimitry Andric return std::move(Err); 338bcb0991SDimitry Andric 348bcb0991SDimitry Andric if (auto Err = createNormalizedSymbols()) 358bcb0991SDimitry Andric return std::move(Err); 368bcb0991SDimitry Andric 378bcb0991SDimitry Andric if (auto Err = graphifyRegularSymbols()) 388bcb0991SDimitry Andric return std::move(Err); 398bcb0991SDimitry Andric 408bcb0991SDimitry Andric if (auto Err = graphifySectionsWithCustomParsers()) 418bcb0991SDimitry Andric return std::move(Err); 428bcb0991SDimitry Andric 438bcb0991SDimitry Andric if (auto Err = addRelocations()) 448bcb0991SDimitry Andric return std::move(Err); 458bcb0991SDimitry Andric 468bcb0991SDimitry Andric return std::move(G); 478bcb0991SDimitry Andric } 488bcb0991SDimitry Andric 49fe6060f1SDimitry Andric MachOLinkGraphBuilder::MachOLinkGraphBuilder( 5006c3fb27SDimitry Andric const object::MachOObjectFile &Obj, Triple TT, SubtargetFeatures Features, 51fe6060f1SDimitry Andric LinkGraph::GetEdgeKindNameFunction GetEdgeKindName) 528bcb0991SDimitry Andric : Obj(Obj), 5306c3fb27SDimitry Andric G(std::make_unique<LinkGraph>(std::string(Obj.getFileName()), 5406c3fb27SDimitry Andric std::move(TT), std::move(Features), 5506c3fb27SDimitry Andric getPointerSize(Obj), getEndianness(Obj), 5606c3fb27SDimitry Andric std::move(GetEdgeKindName))) { 57bdd1243dSDimitry Andric auto &MachHeader = Obj.getHeader64(); 58bdd1243dSDimitry Andric SubsectionsViaSymbols = MachHeader.flags & MachO::MH_SUBSECTIONS_VIA_SYMBOLS; 59bdd1243dSDimitry Andric } 608bcb0991SDimitry Andric 618bcb0991SDimitry Andric void MachOLinkGraphBuilder::addCustomSectionParser( 628bcb0991SDimitry Andric StringRef SectionName, SectionParserFunction Parser) { 638bcb0991SDimitry Andric assert(!CustomSectionParserFunctions.count(SectionName) && 648bcb0991SDimitry Andric "Custom parser for this section already exists"); 658bcb0991SDimitry Andric CustomSectionParserFunctions[SectionName] = std::move(Parser); 668bcb0991SDimitry Andric } 678bcb0991SDimitry Andric 688bcb0991SDimitry Andric Linkage MachOLinkGraphBuilder::getLinkage(uint16_t Desc) { 698bcb0991SDimitry Andric if ((Desc & MachO::N_WEAK_DEF) || (Desc & MachO::N_WEAK_REF)) 708bcb0991SDimitry Andric return Linkage::Weak; 718bcb0991SDimitry Andric return Linkage::Strong; 728bcb0991SDimitry Andric } 738bcb0991SDimitry Andric 748bcb0991SDimitry Andric Scope MachOLinkGraphBuilder::getScope(StringRef Name, uint8_t Type) { 755ffd83dbSDimitry Andric if (Type & MachO::N_EXT) { 76*5f757f3fSDimitry Andric if ((Type & MachO::N_PEXT) || Name.starts_with("l")) 775ffd83dbSDimitry Andric return Scope::Hidden; 785ffd83dbSDimitry Andric else 798bcb0991SDimitry Andric return Scope::Default; 805ffd83dbSDimitry Andric } 818bcb0991SDimitry Andric return Scope::Local; 828bcb0991SDimitry Andric } 838bcb0991SDimitry Andric 848bcb0991SDimitry Andric bool MachOLinkGraphBuilder::isAltEntry(const NormalizedSymbol &NSym) { 858bcb0991SDimitry Andric return NSym.Desc & MachO::N_ALT_ENTRY; 868bcb0991SDimitry Andric } 878bcb0991SDimitry Andric 885ffd83dbSDimitry Andric bool MachOLinkGraphBuilder::isDebugSection(const NormalizedSection &NSec) { 895ffd83dbSDimitry Andric return (NSec.Flags & MachO::S_ATTR_DEBUG && 905ffd83dbSDimitry Andric strcmp(NSec.SegName, "__DWARF") == 0); 915ffd83dbSDimitry Andric } 925ffd83dbSDimitry Andric 93fe6060f1SDimitry Andric bool MachOLinkGraphBuilder::isZeroFillSection(const NormalizedSection &NSec) { 94fe6060f1SDimitry Andric switch (NSec.Flags & MachO::SECTION_TYPE) { 95fe6060f1SDimitry Andric case MachO::S_ZEROFILL: 96fe6060f1SDimitry Andric case MachO::S_GB_ZEROFILL: 97fe6060f1SDimitry Andric case MachO::S_THREAD_LOCAL_ZEROFILL: 98fe6060f1SDimitry Andric return true; 99fe6060f1SDimitry Andric default: 100fe6060f1SDimitry Andric return false; 101fe6060f1SDimitry Andric } 102fe6060f1SDimitry Andric } 103fe6060f1SDimitry Andric 1048bcb0991SDimitry Andric unsigned 1058bcb0991SDimitry Andric MachOLinkGraphBuilder::getPointerSize(const object::MachOObjectFile &Obj) { 1068bcb0991SDimitry Andric return Obj.is64Bit() ? 8 : 4; 1078bcb0991SDimitry Andric } 1088bcb0991SDimitry Andric 109*5f757f3fSDimitry Andric llvm::endianness 1108bcb0991SDimitry Andric MachOLinkGraphBuilder::getEndianness(const object::MachOObjectFile &Obj) { 111*5f757f3fSDimitry Andric return Obj.isLittleEndian() ? llvm::endianness::little 112*5f757f3fSDimitry Andric : llvm::endianness::big; 1138bcb0991SDimitry Andric } 1148bcb0991SDimitry Andric 1158bcb0991SDimitry Andric Section &MachOLinkGraphBuilder::getCommonSection() { 116349cc55cSDimitry Andric if (!CommonSection) 117bdd1243dSDimitry Andric CommonSection = &G->createSection(CommonSectionName, 118bdd1243dSDimitry Andric orc::MemProt::Read | orc::MemProt::Write); 1198bcb0991SDimitry Andric return *CommonSection; 1208bcb0991SDimitry Andric } 1218bcb0991SDimitry Andric 1228bcb0991SDimitry Andric Error MachOLinkGraphBuilder::createNormalizedSections() { 1238bcb0991SDimitry Andric // Build normalized sections. Verifies that section data is in-range (for 1248bcb0991SDimitry Andric // sections with content) and that address ranges are non-overlapping. 1258bcb0991SDimitry Andric 1268bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << "Creating normalized sections...\n"); 1278bcb0991SDimitry Andric 1288bcb0991SDimitry Andric for (auto &SecRef : Obj.sections()) { 1298bcb0991SDimitry Andric NormalizedSection NSec; 1308bcb0991SDimitry Andric uint32_t DataOffset = 0; 1318bcb0991SDimitry Andric 1328bcb0991SDimitry Andric auto SecIndex = Obj.getSectionIndex(SecRef.getRawDataRefImpl()); 1338bcb0991SDimitry Andric 1348bcb0991SDimitry Andric if (Obj.is64Bit()) { 1358bcb0991SDimitry Andric const MachO::section_64 &Sec64 = 1368bcb0991SDimitry Andric Obj.getSection64(SecRef.getRawDataRefImpl()); 1378bcb0991SDimitry Andric 1385ffd83dbSDimitry Andric memcpy(&NSec.SectName, &Sec64.sectname, 16); 1395ffd83dbSDimitry Andric NSec.SectName[16] = '\0'; 1405ffd83dbSDimitry Andric memcpy(&NSec.SegName, Sec64.segname, 16); 1415ffd83dbSDimitry Andric NSec.SegName[16] = '\0'; 1425ffd83dbSDimitry Andric 14304eeddc0SDimitry Andric NSec.Address = orc::ExecutorAddr(Sec64.addr); 1448bcb0991SDimitry Andric NSec.Size = Sec64.size; 1458bcb0991SDimitry Andric NSec.Alignment = 1ULL << Sec64.align; 1468bcb0991SDimitry Andric NSec.Flags = Sec64.flags; 1478bcb0991SDimitry Andric DataOffset = Sec64.offset; 1488bcb0991SDimitry Andric } else { 1498bcb0991SDimitry Andric const MachO::section &Sec32 = Obj.getSection(SecRef.getRawDataRefImpl()); 1505ffd83dbSDimitry Andric 1515ffd83dbSDimitry Andric memcpy(&NSec.SectName, &Sec32.sectname, 16); 1525ffd83dbSDimitry Andric NSec.SectName[16] = '\0'; 1535ffd83dbSDimitry Andric memcpy(&NSec.SegName, Sec32.segname, 16); 1545ffd83dbSDimitry Andric NSec.SegName[16] = '\0'; 1555ffd83dbSDimitry Andric 15604eeddc0SDimitry Andric NSec.Address = orc::ExecutorAddr(Sec32.addr); 1578bcb0991SDimitry Andric NSec.Size = Sec32.size; 1588bcb0991SDimitry Andric NSec.Alignment = 1ULL << Sec32.align; 1598bcb0991SDimitry Andric NSec.Flags = Sec32.flags; 1608bcb0991SDimitry Andric DataOffset = Sec32.offset; 1618bcb0991SDimitry Andric } 1628bcb0991SDimitry Andric 1638bcb0991SDimitry Andric LLVM_DEBUG({ 164fe6060f1SDimitry Andric dbgs() << " " << NSec.SegName << "," << NSec.SectName << ": " 165fe6060f1SDimitry Andric << formatv("{0:x16}", NSec.Address) << " -- " 166fe6060f1SDimitry Andric << formatv("{0:x16}", NSec.Address + NSec.Size) 1678bcb0991SDimitry Andric << ", align: " << NSec.Alignment << ", index: " << SecIndex 1688bcb0991SDimitry Andric << "\n"; 1698bcb0991SDimitry Andric }); 1708bcb0991SDimitry Andric 1718bcb0991SDimitry Andric // Get the section data if any. 172fe6060f1SDimitry Andric if (!isZeroFillSection(NSec)) { 1738bcb0991SDimitry Andric if (DataOffset + NSec.Size > Obj.getData().size()) 1748bcb0991SDimitry Andric return make_error<JITLinkError>( 1758bcb0991SDimitry Andric "Section data extends past end of file"); 1768bcb0991SDimitry Andric 1778bcb0991SDimitry Andric NSec.Data = Obj.getData().data() + DataOffset; 1788bcb0991SDimitry Andric } 1798bcb0991SDimitry Andric 1808bcb0991SDimitry Andric // Get prot flags. 1818bcb0991SDimitry Andric // FIXME: Make sure this test is correct (it's probably missing cases 1828bcb0991SDimitry Andric // as-is). 183bdd1243dSDimitry Andric orc::MemProt Prot; 1848bcb0991SDimitry Andric if (NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) 185bdd1243dSDimitry Andric Prot = orc::MemProt::Read | orc::MemProt::Exec; 1868bcb0991SDimitry Andric else 187bdd1243dSDimitry Andric Prot = orc::MemProt::Read | orc::MemProt::Write; 1888bcb0991SDimitry Andric 189fe6060f1SDimitry Andric auto FullyQualifiedName = 19006c3fb27SDimitry Andric G->allocateContent(StringRef(NSec.SegName) + "," + NSec.SectName); 191fe6060f1SDimitry Andric NSec.GraphSection = &G->createSection( 192349cc55cSDimitry Andric StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()), Prot); 1935ffd83dbSDimitry Andric 19406c3fb27SDimitry Andric // TODO: Are there any other criteria for NoAlloc lifetime? 19506c3fb27SDimitry Andric if (NSec.Flags & MachO::S_ATTR_DEBUG) 196*5f757f3fSDimitry Andric NSec.GraphSection->setMemLifetime(orc::MemLifetime::NoAlloc); 19706c3fb27SDimitry Andric 1988bcb0991SDimitry Andric IndexToSection.insert(std::make_pair(SecIndex, std::move(NSec))); 1998bcb0991SDimitry Andric } 2008bcb0991SDimitry Andric 2018bcb0991SDimitry Andric std::vector<NormalizedSection *> Sections; 2028bcb0991SDimitry Andric Sections.reserve(IndexToSection.size()); 2038bcb0991SDimitry Andric for (auto &KV : IndexToSection) 2048bcb0991SDimitry Andric Sections.push_back(&KV.second); 2058bcb0991SDimitry Andric 2068bcb0991SDimitry Andric // If we didn't end up creating any sections then bail out. The code below 2078bcb0991SDimitry Andric // assumes that we have at least one section. 2088bcb0991SDimitry Andric if (Sections.empty()) 2098bcb0991SDimitry Andric return Error::success(); 2108bcb0991SDimitry Andric 2118bcb0991SDimitry Andric llvm::sort(Sections, 2128bcb0991SDimitry Andric [](const NormalizedSection *LHS, const NormalizedSection *RHS) { 2138bcb0991SDimitry Andric assert(LHS && RHS && "Null section?"); 214480093f4SDimitry Andric if (LHS->Address != RHS->Address) 2158bcb0991SDimitry Andric return LHS->Address < RHS->Address; 216480093f4SDimitry Andric return LHS->Size < RHS->Size; 2178bcb0991SDimitry Andric }); 2188bcb0991SDimitry Andric 2198bcb0991SDimitry Andric for (unsigned I = 0, E = Sections.size() - 1; I != E; ++I) { 2208bcb0991SDimitry Andric auto &Cur = *Sections[I]; 2218bcb0991SDimitry Andric auto &Next = *Sections[I + 1]; 2228bcb0991SDimitry Andric if (Next.Address < Cur.Address + Cur.Size) 2238bcb0991SDimitry Andric return make_error<JITLinkError>( 2245ffd83dbSDimitry Andric "Address range for section " + 2255ffd83dbSDimitry Andric formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Cur.SegName, 2265ffd83dbSDimitry Andric Cur.SectName, Cur.Address, Cur.Address + Cur.Size) + 2275ffd83dbSDimitry Andric "overlaps section \"" + Next.SegName + "/" + Next.SectName + "\"" + 2285ffd83dbSDimitry Andric formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Next.SegName, 2295ffd83dbSDimitry Andric Next.SectName, Next.Address, Next.Address + Next.Size)); 2308bcb0991SDimitry Andric } 2318bcb0991SDimitry Andric 2328bcb0991SDimitry Andric return Error::success(); 2338bcb0991SDimitry Andric } 2348bcb0991SDimitry Andric 2358bcb0991SDimitry Andric Error MachOLinkGraphBuilder::createNormalizedSymbols() { 2368bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n"); 2378bcb0991SDimitry Andric 2388bcb0991SDimitry Andric for (auto &SymRef : Obj.symbols()) { 2398bcb0991SDimitry Andric 2408bcb0991SDimitry Andric unsigned SymbolIndex = Obj.getSymbolIndex(SymRef.getRawDataRefImpl()); 2418bcb0991SDimitry Andric uint64_t Value; 2428bcb0991SDimitry Andric uint32_t NStrX; 2438bcb0991SDimitry Andric uint8_t Type; 2448bcb0991SDimitry Andric uint8_t Sect; 2458bcb0991SDimitry Andric uint16_t Desc; 2468bcb0991SDimitry Andric 2478bcb0991SDimitry Andric if (Obj.is64Bit()) { 2488bcb0991SDimitry Andric const MachO::nlist_64 &NL64 = 2498bcb0991SDimitry Andric Obj.getSymbol64TableEntry(SymRef.getRawDataRefImpl()); 2508bcb0991SDimitry Andric Value = NL64.n_value; 2518bcb0991SDimitry Andric NStrX = NL64.n_strx; 2528bcb0991SDimitry Andric Type = NL64.n_type; 2538bcb0991SDimitry Andric Sect = NL64.n_sect; 2548bcb0991SDimitry Andric Desc = NL64.n_desc; 2558bcb0991SDimitry Andric } else { 2568bcb0991SDimitry Andric const MachO::nlist &NL32 = 2578bcb0991SDimitry Andric Obj.getSymbolTableEntry(SymRef.getRawDataRefImpl()); 2588bcb0991SDimitry Andric Value = NL32.n_value; 2598bcb0991SDimitry Andric NStrX = NL32.n_strx; 2608bcb0991SDimitry Andric Type = NL32.n_type; 2618bcb0991SDimitry Andric Sect = NL32.n_sect; 2628bcb0991SDimitry Andric Desc = NL32.n_desc; 2638bcb0991SDimitry Andric } 2648bcb0991SDimitry Andric 2658bcb0991SDimitry Andric // Skip stabs. 2668bcb0991SDimitry Andric // FIXME: Are there other symbols we should be skipping? 2678bcb0991SDimitry Andric if (Type & MachO::N_STAB) 2688bcb0991SDimitry Andric continue; 2698bcb0991SDimitry Andric 270bdd1243dSDimitry Andric std::optional<StringRef> Name; 2718bcb0991SDimitry Andric if (NStrX) { 2728bcb0991SDimitry Andric if (auto NameOrErr = SymRef.getName()) 2738bcb0991SDimitry Andric Name = *NameOrErr; 2748bcb0991SDimitry Andric else 2758bcb0991SDimitry Andric return NameOrErr.takeError(); 27606c3fb27SDimitry Andric } else if (Type & MachO::N_EXT) 27706c3fb27SDimitry Andric return make_error<JITLinkError>("Symbol at index " + 27806c3fb27SDimitry Andric formatv("{0}", SymbolIndex) + 27906c3fb27SDimitry Andric " has no name (string table index 0), " 28006c3fb27SDimitry Andric "but N_EXT bit is set"); 2818bcb0991SDimitry Andric 2828bcb0991SDimitry Andric LLVM_DEBUG({ 2838bcb0991SDimitry Andric dbgs() << " "; 2848bcb0991SDimitry Andric if (!Name) 2858bcb0991SDimitry Andric dbgs() << "<anonymous symbol>"; 2868bcb0991SDimitry Andric else 2878bcb0991SDimitry Andric dbgs() << *Name; 2888bcb0991SDimitry Andric dbgs() << ": value = " << formatv("{0:x16}", Value) 2898bcb0991SDimitry Andric << ", type = " << formatv("{0:x2}", Type) 2908bcb0991SDimitry Andric << ", desc = " << formatv("{0:x4}", Desc) << ", sect = "; 2918bcb0991SDimitry Andric if (Sect) 2928bcb0991SDimitry Andric dbgs() << static_cast<unsigned>(Sect - 1); 2938bcb0991SDimitry Andric else 2948bcb0991SDimitry Andric dbgs() << "none"; 2958bcb0991SDimitry Andric dbgs() << "\n"; 2968bcb0991SDimitry Andric }); 2978bcb0991SDimitry Andric 298349cc55cSDimitry Andric // If this symbol has a section, verify that the addresses line up. 2998bcb0991SDimitry Andric if (Sect != 0) { 3005ffd83dbSDimitry Andric auto NSec = findSectionByIndex(Sect - 1); 3015ffd83dbSDimitry Andric if (!NSec) 3025ffd83dbSDimitry Andric return NSec.takeError(); 3038bcb0991SDimitry Andric 30404eeddc0SDimitry Andric if (orc::ExecutorAddr(Value) < NSec->Address || 30504eeddc0SDimitry Andric orc::ExecutorAddr(Value) > NSec->Address + NSec->Size) 306349cc55cSDimitry Andric return make_error<JITLinkError>("Address " + formatv("{0:x}", Value) + 307349cc55cSDimitry Andric " for symbol " + *Name + 308349cc55cSDimitry Andric " does not fall within section"); 3095ffd83dbSDimitry Andric 3105ffd83dbSDimitry Andric if (!NSec->GraphSection) { 3115ffd83dbSDimitry Andric LLVM_DEBUG({ 3125ffd83dbSDimitry Andric dbgs() << " Skipping: Symbol is in section " << NSec->SegName << "/" 3135ffd83dbSDimitry Andric << NSec->SectName 3145ffd83dbSDimitry Andric << " which has no associated graph section.\n"; 3155ffd83dbSDimitry Andric }); 3165ffd83dbSDimitry Andric continue; 3175ffd83dbSDimitry Andric } 3188bcb0991SDimitry Andric } 3198bcb0991SDimitry Andric 3208bcb0991SDimitry Andric IndexToSymbol[SymbolIndex] = 3218bcb0991SDimitry Andric &createNormalizedSymbol(*Name, Value, Type, Sect, Desc, 3225ffd83dbSDimitry Andric getLinkage(Desc), getScope(*Name, Type)); 3238bcb0991SDimitry Andric } 3248bcb0991SDimitry Andric 3258bcb0991SDimitry Andric return Error::success(); 3268bcb0991SDimitry Andric } 3278bcb0991SDimitry Andric 3288bcb0991SDimitry Andric void MachOLinkGraphBuilder::addSectionStartSymAndBlock( 32904eeddc0SDimitry Andric unsigned SecIndex, Section &GraphSec, orc::ExecutorAddr Address, 33004eeddc0SDimitry Andric const char *Data, orc::ExecutorAddrDiff Size, uint32_t Alignment, 33104eeddc0SDimitry Andric bool IsLive) { 3328bcb0991SDimitry Andric Block &B = 333fe6060f1SDimitry Andric Data ? G->createContentBlock(GraphSec, ArrayRef<char>(Data, Size), 334fe6060f1SDimitry Andric Address, Alignment, 0) 3358bcb0991SDimitry Andric : G->createZeroFillBlock(GraphSec, Size, Address, Alignment, 0); 3368bcb0991SDimitry Andric auto &Sym = G->addAnonymousSymbol(B, 0, Size, false, IsLive); 337349cc55cSDimitry Andric auto SecI = IndexToSection.find(SecIndex); 338349cc55cSDimitry Andric assert(SecI != IndexToSection.end() && "SecIndex invalid"); 339349cc55cSDimitry Andric auto &NSec = SecI->second; 340349cc55cSDimitry Andric assert(!NSec.CanonicalSymbols.count(Sym.getAddress()) && 3418bcb0991SDimitry Andric "Anonymous block start symbol clashes with existing symbol address"); 342349cc55cSDimitry Andric NSec.CanonicalSymbols[Sym.getAddress()] = &Sym; 3438bcb0991SDimitry Andric } 3448bcb0991SDimitry Andric 3458bcb0991SDimitry Andric Error MachOLinkGraphBuilder::graphifyRegularSymbols() { 3468bcb0991SDimitry Andric 3478bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << "Creating graph symbols...\n"); 3488bcb0991SDimitry Andric 3498bcb0991SDimitry Andric /// We only have 256 section indexes: Use a vector rather than a map. 3508bcb0991SDimitry Andric std::vector<std::vector<NormalizedSymbol *>> SecIndexToSymbols; 3518bcb0991SDimitry Andric SecIndexToSymbols.resize(256); 3528bcb0991SDimitry Andric 3538bcb0991SDimitry Andric // Create commons, externs, and absolutes, and partition all other symbols by 3548bcb0991SDimitry Andric // section. 3558bcb0991SDimitry Andric for (auto &KV : IndexToSymbol) { 3568bcb0991SDimitry Andric auto &NSym = *KV.second; 3578bcb0991SDimitry Andric 3588bcb0991SDimitry Andric switch (NSym.Type & MachO::N_TYPE) { 3598bcb0991SDimitry Andric case MachO::N_UNDF: 3608bcb0991SDimitry Andric if (NSym.Value) { 3618bcb0991SDimitry Andric if (!NSym.Name) 3628bcb0991SDimitry Andric return make_error<JITLinkError>("Anonymous common symbol at index " + 3638bcb0991SDimitry Andric Twine(KV.first)); 364bdd1243dSDimitry Andric NSym.GraphSymbol = &G->addDefinedSymbol( 365bdd1243dSDimitry Andric G->createZeroFillBlock(getCommonSection(), 36604eeddc0SDimitry Andric orc::ExecutorAddrDiff(NSym.Value), 367bdd1243dSDimitry Andric orc::ExecutorAddr(), 368bdd1243dSDimitry Andric 1ull << MachO::GET_COMM_ALIGN(NSym.Desc), 0), 369bdd1243dSDimitry Andric 0, *NSym.Name, orc::ExecutorAddrDiff(NSym.Value), Linkage::Strong, 370bdd1243dSDimitry Andric NSym.S, false, NSym.Desc & MachO::N_NO_DEAD_STRIP); 3718bcb0991SDimitry Andric } else { 3728bcb0991SDimitry Andric if (!NSym.Name) 3738bcb0991SDimitry Andric return make_error<JITLinkError>("Anonymous external symbol at " 3748bcb0991SDimitry Andric "index " + 3758bcb0991SDimitry Andric Twine(KV.first)); 376480093f4SDimitry Andric NSym.GraphSymbol = &G->addExternalSymbol( 377bdd1243dSDimitry Andric *NSym.Name, 0, (NSym.Desc & MachO::N_WEAK_REF) != 0); 3788bcb0991SDimitry Andric } 3798bcb0991SDimitry Andric break; 3808bcb0991SDimitry Andric case MachO::N_ABS: 3818bcb0991SDimitry Andric if (!NSym.Name) 3828bcb0991SDimitry Andric return make_error<JITLinkError>("Anonymous absolute symbol at index " + 3838bcb0991SDimitry Andric Twine(KV.first)); 3848bcb0991SDimitry Andric NSym.GraphSymbol = &G->addAbsoluteSymbol( 38504eeddc0SDimitry Andric *NSym.Name, orc::ExecutorAddr(NSym.Value), 0, Linkage::Strong, 38681ad6265SDimitry Andric getScope(*NSym.Name, NSym.Type), NSym.Desc & MachO::N_NO_DEAD_STRIP); 3878bcb0991SDimitry Andric break; 3888bcb0991SDimitry Andric case MachO::N_SECT: 3898bcb0991SDimitry Andric SecIndexToSymbols[NSym.Sect - 1].push_back(&NSym); 3908bcb0991SDimitry Andric break; 3918bcb0991SDimitry Andric case MachO::N_PBUD: 3928bcb0991SDimitry Andric return make_error<JITLinkError>( 3938bcb0991SDimitry Andric "Unupported N_PBUD symbol " + 3948bcb0991SDimitry Andric (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) + 3958bcb0991SDimitry Andric " at index " + Twine(KV.first)); 3968bcb0991SDimitry Andric case MachO::N_INDR: 3978bcb0991SDimitry Andric return make_error<JITLinkError>( 3988bcb0991SDimitry Andric "Unupported N_INDR symbol " + 3998bcb0991SDimitry Andric (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) + 4008bcb0991SDimitry Andric " at index " + Twine(KV.first)); 4018bcb0991SDimitry Andric default: 4028bcb0991SDimitry Andric return make_error<JITLinkError>( 4038bcb0991SDimitry Andric "Unrecognized symbol type " + Twine(NSym.Type & MachO::N_TYPE) + 4048bcb0991SDimitry Andric " for symbol " + 4058bcb0991SDimitry Andric (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) + 4068bcb0991SDimitry Andric " at index " + Twine(KV.first)); 4078bcb0991SDimitry Andric } 4088bcb0991SDimitry Andric } 4098bcb0991SDimitry Andric 4108bcb0991SDimitry Andric // Loop over sections performing regular graphification for those that 4118bcb0991SDimitry Andric // don't have custom parsers. 4128bcb0991SDimitry Andric for (auto &KV : IndexToSection) { 4138bcb0991SDimitry Andric auto SecIndex = KV.first; 4148bcb0991SDimitry Andric auto &NSec = KV.second; 4158bcb0991SDimitry Andric 4165ffd83dbSDimitry Andric if (!NSec.GraphSection) { 4175ffd83dbSDimitry Andric LLVM_DEBUG({ 4185ffd83dbSDimitry Andric dbgs() << " " << NSec.SegName << "/" << NSec.SectName 4195ffd83dbSDimitry Andric << " has no graph section. Skipping.\n"; 4205ffd83dbSDimitry Andric }); 4215ffd83dbSDimitry Andric continue; 4225ffd83dbSDimitry Andric } 4235ffd83dbSDimitry Andric 4248bcb0991SDimitry Andric // Skip sections with custom parsers. 4258bcb0991SDimitry Andric if (CustomSectionParserFunctions.count(NSec.GraphSection->getName())) { 4268bcb0991SDimitry Andric LLVM_DEBUG({ 4278bcb0991SDimitry Andric dbgs() << " Skipping section " << NSec.GraphSection->getName() 4288bcb0991SDimitry Andric << " as it has a custom parser.\n"; 4298bcb0991SDimitry Andric }); 4308bcb0991SDimitry Andric continue; 431fe6060f1SDimitry Andric } else if ((NSec.Flags & MachO::SECTION_TYPE) == 432fe6060f1SDimitry Andric MachO::S_CSTRING_LITERALS) { 433fe6060f1SDimitry Andric if (auto Err = graphifyCStringSection( 434fe6060f1SDimitry Andric NSec, std::move(SecIndexToSymbols[SecIndex]))) 435fe6060f1SDimitry Andric return Err; 436fe6060f1SDimitry Andric continue; 4378bcb0991SDimitry Andric } else 4388bcb0991SDimitry Andric LLVM_DEBUG({ 439fe6060f1SDimitry Andric dbgs() << " Graphifying regular section " 440fe6060f1SDimitry Andric << NSec.GraphSection->getName() << "...\n"; 4418bcb0991SDimitry Andric }); 4428bcb0991SDimitry Andric 4438bcb0991SDimitry Andric bool SectionIsNoDeadStrip = NSec.Flags & MachO::S_ATTR_NO_DEAD_STRIP; 4448bcb0991SDimitry Andric bool SectionIsText = NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS; 4458bcb0991SDimitry Andric 4468bcb0991SDimitry Andric auto &SecNSymStack = SecIndexToSymbols[SecIndex]; 4478bcb0991SDimitry Andric 4488bcb0991SDimitry Andric // If this section is non-empty but there are no symbols covering it then 4498bcb0991SDimitry Andric // create one block and anonymous symbol to cover the entire section. 4508bcb0991SDimitry Andric if (SecNSymStack.empty()) { 4518bcb0991SDimitry Andric if (NSec.Size > 0) { 4528bcb0991SDimitry Andric LLVM_DEBUG({ 4538bcb0991SDimitry Andric dbgs() << " Section non-empty, but contains no symbols. " 4548bcb0991SDimitry Andric "Creating anonymous block to cover " 4558bcb0991SDimitry Andric << formatv("{0:x16}", NSec.Address) << " -- " 4568bcb0991SDimitry Andric << formatv("{0:x16}", NSec.Address + NSec.Size) << "\n"; 4578bcb0991SDimitry Andric }); 458349cc55cSDimitry Andric addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address, 459349cc55cSDimitry Andric NSec.Data, NSec.Size, NSec.Alignment, 4608bcb0991SDimitry Andric SectionIsNoDeadStrip); 4618bcb0991SDimitry Andric } else 4628bcb0991SDimitry Andric LLVM_DEBUG({ 4638bcb0991SDimitry Andric dbgs() << " Section empty and contains no symbols. Skipping.\n"; 4648bcb0991SDimitry Andric }); 4658bcb0991SDimitry Andric continue; 4668bcb0991SDimitry Andric } 4678bcb0991SDimitry Andric 4688bcb0991SDimitry Andric // Sort the symbol stack in by address, alt-entry status, scope, and name. 4698bcb0991SDimitry Andric // We sort in reverse order so that symbols will be visited in the right 4708bcb0991SDimitry Andric // order when we pop off the stack below. 4718bcb0991SDimitry Andric llvm::sort(SecNSymStack, [](const NormalizedSymbol *LHS, 4728bcb0991SDimitry Andric const NormalizedSymbol *RHS) { 4738bcb0991SDimitry Andric if (LHS->Value != RHS->Value) 4748bcb0991SDimitry Andric return LHS->Value > RHS->Value; 4758bcb0991SDimitry Andric if (isAltEntry(*LHS) != isAltEntry(*RHS)) 4768bcb0991SDimitry Andric return isAltEntry(*RHS); 4778bcb0991SDimitry Andric if (LHS->S != RHS->S) 4788bcb0991SDimitry Andric return static_cast<uint8_t>(LHS->S) < static_cast<uint8_t>(RHS->S); 4798bcb0991SDimitry Andric return LHS->Name < RHS->Name; 4808bcb0991SDimitry Andric }); 4818bcb0991SDimitry Andric 4828bcb0991SDimitry Andric // The first symbol in a section can not be an alt-entry symbol. 4838bcb0991SDimitry Andric if (!SecNSymStack.empty() && isAltEntry(*SecNSymStack.back())) 4848bcb0991SDimitry Andric return make_error<JITLinkError>( 4858bcb0991SDimitry Andric "First symbol in " + NSec.GraphSection->getName() + " is alt-entry"); 4868bcb0991SDimitry Andric 4878bcb0991SDimitry Andric // If the section is non-empty but there is no symbol covering the start 4888bcb0991SDimitry Andric // address then add an anonymous one. 48904eeddc0SDimitry Andric if (orc::ExecutorAddr(SecNSymStack.back()->Value) != NSec.Address) { 49004eeddc0SDimitry Andric auto AnonBlockSize = 49104eeddc0SDimitry Andric orc::ExecutorAddr(SecNSymStack.back()->Value) - NSec.Address; 4928bcb0991SDimitry Andric LLVM_DEBUG({ 4938bcb0991SDimitry Andric dbgs() << " Section start not covered by symbol. " 49404eeddc0SDimitry Andric << "Creating anonymous block to cover [ " << NSec.Address 49504eeddc0SDimitry Andric << " -- " << (NSec.Address + AnonBlockSize) << " ]\n"; 4968bcb0991SDimitry Andric }); 497349cc55cSDimitry Andric addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address, 498349cc55cSDimitry Andric NSec.Data, AnonBlockSize, NSec.Alignment, 4998bcb0991SDimitry Andric SectionIsNoDeadStrip); 5008bcb0991SDimitry Andric } 5018bcb0991SDimitry Andric 5028bcb0991SDimitry Andric // Visit section symbols in order by popping off the reverse-sorted stack, 503bdd1243dSDimitry Andric // building graph symbols as we go. 504bdd1243dSDimitry Andric // 505bdd1243dSDimitry Andric // If MH_SUBSECTIONS_VIA_SYMBOLS is set we'll build a block for each 506bdd1243dSDimitry Andric // alt-entry chain. 507bdd1243dSDimitry Andric // 508bdd1243dSDimitry Andric // If MH_SUBSECTIONS_VIA_SYMBOLS is not set then we'll just build one block 509bdd1243dSDimitry Andric // for the whole section. 5108bcb0991SDimitry Andric while (!SecNSymStack.empty()) { 5118bcb0991SDimitry Andric SmallVector<NormalizedSymbol *, 8> BlockSyms; 5128bcb0991SDimitry Andric 513bdd1243dSDimitry Andric // Get the symbols in this alt-entry chain, or the whole section (if 514bdd1243dSDimitry Andric // !SubsectionsViaSymbols). 5158bcb0991SDimitry Andric BlockSyms.push_back(SecNSymStack.back()); 5168bcb0991SDimitry Andric SecNSymStack.pop_back(); 5178bcb0991SDimitry Andric while (!SecNSymStack.empty() && 5188bcb0991SDimitry Andric (isAltEntry(*SecNSymStack.back()) || 519bdd1243dSDimitry Andric SecNSymStack.back()->Value == BlockSyms.back()->Value || 520bdd1243dSDimitry Andric !SubsectionsViaSymbols)) { 5218bcb0991SDimitry Andric BlockSyms.push_back(SecNSymStack.back()); 5228bcb0991SDimitry Andric SecNSymStack.pop_back(); 5238bcb0991SDimitry Andric } 5248bcb0991SDimitry Andric 5258bcb0991SDimitry Andric // BlockNSyms now contains the block symbols in reverse canonical order. 52604eeddc0SDimitry Andric auto BlockStart = orc::ExecutorAddr(BlockSyms.front()->Value); 52704eeddc0SDimitry Andric orc::ExecutorAddr BlockEnd = 52804eeddc0SDimitry Andric SecNSymStack.empty() ? NSec.Address + NSec.Size 52904eeddc0SDimitry Andric : orc::ExecutorAddr(SecNSymStack.back()->Value); 53004eeddc0SDimitry Andric orc::ExecutorAddrDiff BlockOffset = BlockStart - NSec.Address; 53104eeddc0SDimitry Andric orc::ExecutorAddrDiff BlockSize = BlockEnd - BlockStart; 5328bcb0991SDimitry Andric 5338bcb0991SDimitry Andric LLVM_DEBUG({ 5348bcb0991SDimitry Andric dbgs() << " Creating block for " << formatv("{0:x16}", BlockStart) 5358bcb0991SDimitry Andric << " -- " << formatv("{0:x16}", BlockEnd) << ": " 5368bcb0991SDimitry Andric << NSec.GraphSection->getName() << " + " 5378bcb0991SDimitry Andric << formatv("{0:x16}", BlockOffset) << " with " 5388bcb0991SDimitry Andric << BlockSyms.size() << " symbol(s)...\n"; 5398bcb0991SDimitry Andric }); 5408bcb0991SDimitry Andric 5418bcb0991SDimitry Andric Block &B = 5428bcb0991SDimitry Andric NSec.Data 5438bcb0991SDimitry Andric ? G->createContentBlock( 5448bcb0991SDimitry Andric *NSec.GraphSection, 545fe6060f1SDimitry Andric ArrayRef<char>(NSec.Data + BlockOffset, BlockSize), 546fe6060f1SDimitry Andric BlockStart, NSec.Alignment, BlockStart % NSec.Alignment) 5478bcb0991SDimitry Andric : G->createZeroFillBlock(*NSec.GraphSection, BlockSize, 5488bcb0991SDimitry Andric BlockStart, NSec.Alignment, 5498bcb0991SDimitry Andric BlockStart % NSec.Alignment); 5508bcb0991SDimitry Andric 551bdd1243dSDimitry Andric std::optional<orc::ExecutorAddr> LastCanonicalAddr; 55204eeddc0SDimitry Andric auto SymEnd = BlockEnd; 5538bcb0991SDimitry Andric while (!BlockSyms.empty()) { 5548bcb0991SDimitry Andric auto &NSym = *BlockSyms.back(); 5558bcb0991SDimitry Andric BlockSyms.pop_back(); 5568bcb0991SDimitry Andric 5578bcb0991SDimitry Andric bool SymLive = 5588bcb0991SDimitry Andric (NSym.Desc & MachO::N_NO_DEAD_STRIP) || SectionIsNoDeadStrip; 5598bcb0991SDimitry Andric 56004eeddc0SDimitry Andric auto &Sym = createStandardGraphSymbol( 56104eeddc0SDimitry Andric NSym, B, SymEnd - orc::ExecutorAddr(NSym.Value), SectionIsText, 56204eeddc0SDimitry Andric SymLive, LastCanonicalAddr != orc::ExecutorAddr(NSym.Value)); 5638bcb0991SDimitry Andric 5648bcb0991SDimitry Andric if (LastCanonicalAddr != Sym.getAddress()) { 5658bcb0991SDimitry Andric if (LastCanonicalAddr) 5668bcb0991SDimitry Andric SymEnd = *LastCanonicalAddr; 5678bcb0991SDimitry Andric LastCanonicalAddr = Sym.getAddress(); 5688bcb0991SDimitry Andric } 5698bcb0991SDimitry Andric } 5708bcb0991SDimitry Andric } 5718bcb0991SDimitry Andric } 5728bcb0991SDimitry Andric 5738bcb0991SDimitry Andric return Error::success(); 5748bcb0991SDimitry Andric } 5758bcb0991SDimitry Andric 576fe6060f1SDimitry Andric Symbol &MachOLinkGraphBuilder::createStandardGraphSymbol(NormalizedSymbol &NSym, 577fe6060f1SDimitry Andric Block &B, size_t Size, 578fe6060f1SDimitry Andric bool IsText, 579fe6060f1SDimitry Andric bool IsNoDeadStrip, 580fe6060f1SDimitry Andric bool IsCanonical) { 581fe6060f1SDimitry Andric 582fe6060f1SDimitry Andric LLVM_DEBUG({ 583fe6060f1SDimitry Andric dbgs() << " " << formatv("{0:x16}", NSym.Value) << " -- " 584fe6060f1SDimitry Andric << formatv("{0:x16}", NSym.Value + Size) << ": "; 585fe6060f1SDimitry Andric if (!NSym.Name) 586fe6060f1SDimitry Andric dbgs() << "<anonymous symbol>"; 587fe6060f1SDimitry Andric else 588fe6060f1SDimitry Andric dbgs() << NSym.Name; 589fe6060f1SDimitry Andric if (IsText) 590fe6060f1SDimitry Andric dbgs() << " [text]"; 591fe6060f1SDimitry Andric if (IsNoDeadStrip) 592fe6060f1SDimitry Andric dbgs() << " [no-dead-strip]"; 593fe6060f1SDimitry Andric if (!IsCanonical) 594fe6060f1SDimitry Andric dbgs() << " [non-canonical]"; 595fe6060f1SDimitry Andric dbgs() << "\n"; 596fe6060f1SDimitry Andric }); 597fe6060f1SDimitry Andric 59804eeddc0SDimitry Andric auto SymOffset = orc::ExecutorAddr(NSym.Value) - B.getAddress(); 59904eeddc0SDimitry Andric auto &Sym = 60004eeddc0SDimitry Andric NSym.Name 60104eeddc0SDimitry Andric ? G->addDefinedSymbol(B, SymOffset, *NSym.Name, Size, NSym.L, NSym.S, 602fe6060f1SDimitry Andric IsText, IsNoDeadStrip) 60304eeddc0SDimitry Andric : G->addAnonymousSymbol(B, SymOffset, Size, IsText, IsNoDeadStrip); 604fe6060f1SDimitry Andric NSym.GraphSymbol = &Sym; 605fe6060f1SDimitry Andric 606fe6060f1SDimitry Andric if (IsCanonical) 607349cc55cSDimitry Andric setCanonicalSymbol(getSectionByIndex(NSym.Sect - 1), Sym); 608fe6060f1SDimitry Andric 609fe6060f1SDimitry Andric return Sym; 610fe6060f1SDimitry Andric } 611fe6060f1SDimitry Andric 6128bcb0991SDimitry Andric Error MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() { 6138bcb0991SDimitry Andric // Graphify special sections. 6148bcb0991SDimitry Andric for (auto &KV : IndexToSection) { 6158bcb0991SDimitry Andric auto &NSec = KV.second; 6168bcb0991SDimitry Andric 6175ffd83dbSDimitry Andric // Skip non-graph sections. 6185ffd83dbSDimitry Andric if (!NSec.GraphSection) 6195ffd83dbSDimitry Andric continue; 6205ffd83dbSDimitry Andric 6218bcb0991SDimitry Andric auto HI = CustomSectionParserFunctions.find(NSec.GraphSection->getName()); 6228bcb0991SDimitry Andric if (HI != CustomSectionParserFunctions.end()) { 6238bcb0991SDimitry Andric auto &Parse = HI->second; 6248bcb0991SDimitry Andric if (auto Err = Parse(NSec)) 6258bcb0991SDimitry Andric return Err; 6268bcb0991SDimitry Andric } 6278bcb0991SDimitry Andric } 6288bcb0991SDimitry Andric 6298bcb0991SDimitry Andric return Error::success(); 6308bcb0991SDimitry Andric } 6318bcb0991SDimitry Andric 632fe6060f1SDimitry Andric Error MachOLinkGraphBuilder::graphifyCStringSection( 633fe6060f1SDimitry Andric NormalizedSection &NSec, std::vector<NormalizedSymbol *> NSyms) { 634fe6060f1SDimitry Andric assert(NSec.GraphSection && "C string literal section missing graph section"); 635fe6060f1SDimitry Andric assert(NSec.Data && "C string literal section has no data"); 636fe6060f1SDimitry Andric 637fe6060f1SDimitry Andric LLVM_DEBUG({ 638fe6060f1SDimitry Andric dbgs() << " Graphifying C-string literal section " 639fe6060f1SDimitry Andric << NSec.GraphSection->getName() << "\n"; 640fe6060f1SDimitry Andric }); 641fe6060f1SDimitry Andric 642fe6060f1SDimitry Andric if (NSec.Data[NSec.Size - 1] != '\0') 643fe6060f1SDimitry Andric return make_error<JITLinkError>("C string literal section " + 644fe6060f1SDimitry Andric NSec.GraphSection->getName() + 645fe6060f1SDimitry Andric " does not end with null terminator"); 646fe6060f1SDimitry Andric 647fe6060f1SDimitry Andric /// Sort into reverse order to use as a stack. 648fe6060f1SDimitry Andric llvm::sort(NSyms, 649fe6060f1SDimitry Andric [](const NormalizedSymbol *LHS, const NormalizedSymbol *RHS) { 650fe6060f1SDimitry Andric if (LHS->Value != RHS->Value) 651fe6060f1SDimitry Andric return LHS->Value > RHS->Value; 652fe6060f1SDimitry Andric if (LHS->L != RHS->L) 653fe6060f1SDimitry Andric return LHS->L > RHS->L; 654fe6060f1SDimitry Andric if (LHS->S != RHS->S) 655fe6060f1SDimitry Andric return LHS->S > RHS->S; 656fe6060f1SDimitry Andric if (RHS->Name) { 657fe6060f1SDimitry Andric if (!LHS->Name) 658fe6060f1SDimitry Andric return true; 659fe6060f1SDimitry Andric return *LHS->Name > *RHS->Name; 660fe6060f1SDimitry Andric } 661fe6060f1SDimitry Andric return false; 662fe6060f1SDimitry Andric }); 663fe6060f1SDimitry Andric 664fe6060f1SDimitry Andric bool SectionIsNoDeadStrip = NSec.Flags & MachO::S_ATTR_NO_DEAD_STRIP; 665fe6060f1SDimitry Andric bool SectionIsText = NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS; 66604eeddc0SDimitry Andric orc::ExecutorAddrDiff BlockStart = 0; 667fe6060f1SDimitry Andric 668fe6060f1SDimitry Andric // Scan section for null characters. 66906c3fb27SDimitry Andric for (size_t I = 0; I != NSec.Size; ++I) { 670fe6060f1SDimitry Andric if (NSec.Data[I] == '\0') { 67181ad6265SDimitry Andric size_t BlockSize = I + 1 - BlockStart; 672fe6060f1SDimitry Andric // Create a block for this null terminated string. 673fe6060f1SDimitry Andric auto &B = G->createContentBlock(*NSec.GraphSection, 674fe6060f1SDimitry Andric {NSec.Data + BlockStart, BlockSize}, 67581ad6265SDimitry Andric NSec.Address + BlockStart, NSec.Alignment, 67681ad6265SDimitry Andric BlockStart % NSec.Alignment); 677fe6060f1SDimitry Andric 678fe6060f1SDimitry Andric LLVM_DEBUG({ 67981ad6265SDimitry Andric dbgs() << " Created block " << B.getRange() 68081ad6265SDimitry Andric << ", align = " << B.getAlignment() 68181ad6265SDimitry Andric << ", align-ofs = " << B.getAlignmentOffset() << " for \""; 68281ad6265SDimitry Andric for (size_t J = 0; J != std::min(B.getSize(), size_t(16)); ++J) 68381ad6265SDimitry Andric switch (B.getContent()[J]) { 68481ad6265SDimitry Andric case '\0': break; 68581ad6265SDimitry Andric case '\n': dbgs() << "\\n"; break; 68681ad6265SDimitry Andric case '\t': dbgs() << "\\t"; break; 68781ad6265SDimitry Andric default: dbgs() << B.getContent()[J]; break; 68881ad6265SDimitry Andric } 68981ad6265SDimitry Andric if (B.getSize() > 16) 69081ad6265SDimitry Andric dbgs() << "..."; 69181ad6265SDimitry Andric dbgs() << "\"\n"; 692fe6060f1SDimitry Andric }); 693fe6060f1SDimitry Andric 694fe6060f1SDimitry Andric // If there's no symbol at the start of this block then create one. 69504eeddc0SDimitry Andric if (NSyms.empty() || 69604eeddc0SDimitry Andric orc::ExecutorAddr(NSyms.back()->Value) != B.getAddress()) { 697fe6060f1SDimitry Andric auto &S = G->addAnonymousSymbol(B, 0, BlockSize, false, false); 698349cc55cSDimitry Andric setCanonicalSymbol(NSec, S); 699fe6060f1SDimitry Andric LLVM_DEBUG({ 70081ad6265SDimitry Andric dbgs() << " Adding symbol for c-string block " << B.getRange() 70181ad6265SDimitry Andric << ": <anonymous symbol> at offset 0\n"; 702fe6060f1SDimitry Andric }); 703fe6060f1SDimitry Andric } 704fe6060f1SDimitry Andric 705fe6060f1SDimitry Andric // Process any remaining symbols that point into this block. 70681ad6265SDimitry Andric auto LastCanonicalAddr = B.getAddress() + BlockSize; 70704eeddc0SDimitry Andric while (!NSyms.empty() && orc::ExecutorAddr(NSyms.back()->Value) < 70804eeddc0SDimitry Andric B.getAddress() + BlockSize) { 709fe6060f1SDimitry Andric auto &NSym = *NSyms.back(); 71004eeddc0SDimitry Andric size_t SymSize = (B.getAddress() + BlockSize) - 71104eeddc0SDimitry Andric orc::ExecutorAddr(NSyms.back()->Value); 712fe6060f1SDimitry Andric bool SymLive = 713fe6060f1SDimitry Andric (NSym.Desc & MachO::N_NO_DEAD_STRIP) || SectionIsNoDeadStrip; 714fe6060f1SDimitry Andric 715fe6060f1SDimitry Andric bool IsCanonical = false; 71604eeddc0SDimitry Andric if (LastCanonicalAddr != orc::ExecutorAddr(NSym.Value)) { 717fe6060f1SDimitry Andric IsCanonical = true; 71804eeddc0SDimitry Andric LastCanonicalAddr = orc::ExecutorAddr(NSym.Value); 719fe6060f1SDimitry Andric } 720fe6060f1SDimitry Andric 72181ad6265SDimitry Andric auto &Sym = createStandardGraphSymbol(NSym, B, SymSize, SectionIsText, 72281ad6265SDimitry Andric SymLive, IsCanonical); 72381ad6265SDimitry Andric (void)Sym; 72481ad6265SDimitry Andric LLVM_DEBUG({ 72581ad6265SDimitry Andric dbgs() << " Adding symbol for c-string block " << B.getRange() 72681ad6265SDimitry Andric << ": " 72781ad6265SDimitry Andric << (Sym.hasName() ? Sym.getName() : "<anonymous symbol>") 72881ad6265SDimitry Andric << " at offset " << formatv("{0:x}", Sym.getOffset()) << "\n"; 72981ad6265SDimitry Andric }); 730fe6060f1SDimitry Andric 731fe6060f1SDimitry Andric NSyms.pop_back(); 732fe6060f1SDimitry Andric } 733fe6060f1SDimitry Andric 734fe6060f1SDimitry Andric BlockStart += BlockSize; 735fe6060f1SDimitry Andric } 73606c3fb27SDimitry Andric } 73706c3fb27SDimitry Andric 73806c3fb27SDimitry Andric assert(llvm::all_of(NSec.GraphSection->blocks(), 73906c3fb27SDimitry Andric [](Block *B) { return isCStringBlock(*B); }) && 74006c3fb27SDimitry Andric "All blocks in section should hold single c-strings"); 741fe6060f1SDimitry Andric 742fe6060f1SDimitry Andric return Error::success(); 743fe6060f1SDimitry Andric } 744fe6060f1SDimitry Andric 745349cc55cSDimitry Andric Error CompactUnwindSplitter::operator()(LinkGraph &G) { 746349cc55cSDimitry Andric auto *CUSec = G.findSectionByName(CompactUnwindSectionName); 747349cc55cSDimitry Andric if (!CUSec) 748349cc55cSDimitry Andric return Error::success(); 749349cc55cSDimitry Andric 750349cc55cSDimitry Andric if (!G.getTargetTriple().isOSBinFormatMachO()) 751349cc55cSDimitry Andric return make_error<JITLinkError>( 752349cc55cSDimitry Andric "Error linking " + G.getName() + 753349cc55cSDimitry Andric ": compact unwind splitting not supported on non-macho target " + 754349cc55cSDimitry Andric G.getTargetTriple().str()); 755349cc55cSDimitry Andric 756349cc55cSDimitry Andric unsigned CURecordSize = 0; 757349cc55cSDimitry Andric unsigned PersonalityEdgeOffset = 0; 758349cc55cSDimitry Andric unsigned LSDAEdgeOffset = 0; 759349cc55cSDimitry Andric switch (G.getTargetTriple().getArch()) { 760349cc55cSDimitry Andric case Triple::aarch64: 761349cc55cSDimitry Andric case Triple::x86_64: 762349cc55cSDimitry Andric // 64-bit compact-unwind record format: 763349cc55cSDimitry Andric // Range start: 8 bytes. 764349cc55cSDimitry Andric // Range size: 4 bytes. 765349cc55cSDimitry Andric // CU encoding: 4 bytes. 766349cc55cSDimitry Andric // Personality: 8 bytes. 767349cc55cSDimitry Andric // LSDA: 8 bytes. 768349cc55cSDimitry Andric CURecordSize = 32; 769349cc55cSDimitry Andric PersonalityEdgeOffset = 16; 770349cc55cSDimitry Andric LSDAEdgeOffset = 24; 771349cc55cSDimitry Andric break; 772349cc55cSDimitry Andric default: 773349cc55cSDimitry Andric return make_error<JITLinkError>( 774349cc55cSDimitry Andric "Error linking " + G.getName() + 775349cc55cSDimitry Andric ": compact unwind splitting not supported on " + 776349cc55cSDimitry Andric G.getTargetTriple().getArchName()); 777349cc55cSDimitry Andric } 778349cc55cSDimitry Andric 779349cc55cSDimitry Andric std::vector<Block *> OriginalBlocks(CUSec->blocks().begin(), 780349cc55cSDimitry Andric CUSec->blocks().end()); 781349cc55cSDimitry Andric LLVM_DEBUG({ 782349cc55cSDimitry Andric dbgs() << "In " << G.getName() << " splitting compact unwind section " 783349cc55cSDimitry Andric << CompactUnwindSectionName << " containing " 784349cc55cSDimitry Andric << OriginalBlocks.size() << " initial blocks...\n"; 785349cc55cSDimitry Andric }); 786349cc55cSDimitry Andric 787349cc55cSDimitry Andric while (!OriginalBlocks.empty()) { 788349cc55cSDimitry Andric auto *B = OriginalBlocks.back(); 789349cc55cSDimitry Andric OriginalBlocks.pop_back(); 790349cc55cSDimitry Andric 791349cc55cSDimitry Andric if (B->getSize() == 0) { 792349cc55cSDimitry Andric LLVM_DEBUG({ 793349cc55cSDimitry Andric dbgs() << " Skipping empty block at " 794349cc55cSDimitry Andric << formatv("{0:x16}", B->getAddress()) << "\n"; 795349cc55cSDimitry Andric }); 796349cc55cSDimitry Andric continue; 797349cc55cSDimitry Andric } 798349cc55cSDimitry Andric 799349cc55cSDimitry Andric LLVM_DEBUG({ 800349cc55cSDimitry Andric dbgs() << " Splitting block at " << formatv("{0:x16}", B->getAddress()) 801349cc55cSDimitry Andric << " into " << (B->getSize() / CURecordSize) 802349cc55cSDimitry Andric << " compact unwind record(s)\n"; 803349cc55cSDimitry Andric }); 804349cc55cSDimitry Andric 805349cc55cSDimitry Andric if (B->getSize() % CURecordSize) 806349cc55cSDimitry Andric return make_error<JITLinkError>( 807349cc55cSDimitry Andric "Error splitting compact unwind record in " + G.getName() + 808349cc55cSDimitry Andric ": block at " + formatv("{0:x}", B->getAddress()) + " has size " + 809349cc55cSDimitry Andric formatv("{0:x}", B->getSize()) + 810349cc55cSDimitry Andric " (not a multiple of CU record size of " + 811349cc55cSDimitry Andric formatv("{0:x}", CURecordSize) + ")"); 812349cc55cSDimitry Andric 813349cc55cSDimitry Andric unsigned NumBlocks = B->getSize() / CURecordSize; 814349cc55cSDimitry Andric LinkGraph::SplitBlockCache C; 815349cc55cSDimitry Andric 816349cc55cSDimitry Andric for (unsigned I = 0; I != NumBlocks; ++I) { 817349cc55cSDimitry Andric auto &CURec = G.splitBlock(*B, CURecordSize, &C); 818349cc55cSDimitry Andric bool AddedKeepAlive = false; 819349cc55cSDimitry Andric 820349cc55cSDimitry Andric for (auto &E : CURec.edges()) { 821349cc55cSDimitry Andric if (E.getOffset() == 0) { 822349cc55cSDimitry Andric LLVM_DEBUG({ 823349cc55cSDimitry Andric dbgs() << " Updating compact unwind record at " 824349cc55cSDimitry Andric << formatv("{0:x16}", CURec.getAddress()) << " to point to " 825349cc55cSDimitry Andric << (E.getTarget().hasName() ? E.getTarget().getName() 826349cc55cSDimitry Andric : StringRef()) 827349cc55cSDimitry Andric << " (at " << formatv("{0:x16}", E.getTarget().getAddress()) 828349cc55cSDimitry Andric << ")\n"; 829349cc55cSDimitry Andric }); 830349cc55cSDimitry Andric 831349cc55cSDimitry Andric if (E.getTarget().isExternal()) 832349cc55cSDimitry Andric return make_error<JITLinkError>( 833349cc55cSDimitry Andric "Error adding keep-alive edge for compact unwind record at " + 834349cc55cSDimitry Andric formatv("{0:x}", CURec.getAddress()) + ": target " + 835349cc55cSDimitry Andric E.getTarget().getName() + " is an external symbol"); 836349cc55cSDimitry Andric auto &TgtBlock = E.getTarget().getBlock(); 837349cc55cSDimitry Andric auto &CURecSym = 83804eeddc0SDimitry Andric G.addAnonymousSymbol(CURec, 0, CURecordSize, false, false); 839349cc55cSDimitry Andric TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0); 840349cc55cSDimitry Andric AddedKeepAlive = true; 841349cc55cSDimitry Andric } else if (E.getOffset() != PersonalityEdgeOffset && 842349cc55cSDimitry Andric E.getOffset() != LSDAEdgeOffset) 843349cc55cSDimitry Andric return make_error<JITLinkError>("Unexpected edge at offset " + 844349cc55cSDimitry Andric formatv("{0:x}", E.getOffset()) + 845349cc55cSDimitry Andric " in compact unwind record at " + 846349cc55cSDimitry Andric formatv("{0:x}", CURec.getAddress())); 847349cc55cSDimitry Andric } 848349cc55cSDimitry Andric 849349cc55cSDimitry Andric if (!AddedKeepAlive) 850349cc55cSDimitry Andric return make_error<JITLinkError>( 851349cc55cSDimitry Andric "Error adding keep-alive edge for compact unwind record at " + 852349cc55cSDimitry Andric formatv("{0:x}", CURec.getAddress()) + 853349cc55cSDimitry Andric ": no outgoing target edge at offset 0"); 854349cc55cSDimitry Andric } 855349cc55cSDimitry Andric } 856349cc55cSDimitry Andric return Error::success(); 857349cc55cSDimitry Andric } 858349cc55cSDimitry Andric 8598bcb0991SDimitry Andric } // end namespace jitlink 8608bcb0991SDimitry Andric } // end namespace llvm 861