xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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