brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.2 KiB · 8562ebe Raw
737 lines · cpp
1//=--------- MachOLinkGraphBuilder.cpp - MachO LinkGraph builder ----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Generic MachO LinkGraph building code.10//11//===----------------------------------------------------------------------===//12 13#include "MachOLinkGraphBuilder.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/ADT/Sequence.h"16#include <optional>17 18#define DEBUG_TYPE "jitlink"19 20static const char *CommonSectionName = "__common";21 22namespace llvm {23namespace jitlink {24 25MachOLinkGraphBuilder::~MachOLinkGraphBuilder() = default;26 27Expected<std::unique_ptr<LinkGraph>> MachOLinkGraphBuilder::buildGraph() {28 29  // We only operate on relocatable objects.30  if (!Obj.isRelocatableObject())31    return make_error<JITLinkError>("Object is not a relocatable MachO");32 33  if (auto Err = createNormalizedSections())34    return std::move(Err);35 36  if (auto Err = createNormalizedSymbols())37    return std::move(Err);38 39  if (auto Err = graphifyRegularSymbols())40    return std::move(Err);41 42  if (auto Err = graphifySectionsWithCustomParsers())43    return std::move(Err);44 45  if (auto Err = addRelocations())46    return std::move(Err);47 48  return std::move(G);49}50 51MachOLinkGraphBuilder::MachOLinkGraphBuilder(52    const object::MachOObjectFile &Obj,53    std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,54    SubtargetFeatures Features,55    LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)56    : Obj(Obj),57      G(std::make_unique<LinkGraph>(58          std::string(Obj.getFileName()), std::move(SSP), std::move(TT),59          std::move(Features), std::move(GetEdgeKindName))) {60  auto &MachHeader = Obj.getHeader64();61  SubsectionsViaSymbols = MachHeader.flags & MachO::MH_SUBSECTIONS_VIA_SYMBOLS;62}63 64void MachOLinkGraphBuilder::addCustomSectionParser(65    StringRef SectionName, SectionParserFunction Parser) {66  assert(!CustomSectionParserFunctions.count(SectionName) &&67         "Custom parser for this section already exists");68  CustomSectionParserFunctions[SectionName] = std::move(Parser);69}70 71Linkage MachOLinkGraphBuilder::getLinkage(uint16_t Desc) {72  if ((Desc & MachO::N_WEAK_DEF) || (Desc & MachO::N_WEAK_REF))73    return Linkage::Weak;74  return Linkage::Strong;75}76 77Scope MachOLinkGraphBuilder::getScope(StringRef Name, uint8_t Type) {78  if (Type & MachO::N_EXT) {79    if ((Type & MachO::N_PEXT) || Name.starts_with("l"))80      return Scope::Hidden;81    else82      return Scope::Default;83  }84  return Scope::Local;85}86 87bool MachOLinkGraphBuilder::isAltEntry(const NormalizedSymbol &NSym) {88  return NSym.Desc & MachO::N_ALT_ENTRY;89}90 91bool MachOLinkGraphBuilder::isDebugSection(const NormalizedSection &NSec) {92  return (NSec.Flags & MachO::S_ATTR_DEBUG &&93          strcmp(NSec.SegName, "__DWARF") == 0);94}95 96bool MachOLinkGraphBuilder::isZeroFillSection(const NormalizedSection &NSec) {97  switch (NSec.Flags & MachO::SECTION_TYPE) {98  case MachO::S_ZEROFILL:99  case MachO::S_GB_ZEROFILL:100  case MachO::S_THREAD_LOCAL_ZEROFILL:101    return true;102  default:103    return false;104  }105}106 107Section &MachOLinkGraphBuilder::getCommonSection() {108  if (!CommonSection)109    CommonSection = &G->createSection(CommonSectionName,110                                      orc::MemProt::Read | orc::MemProt::Write);111  return *CommonSection;112}113 114Error MachOLinkGraphBuilder::createNormalizedSections() {115  // Build normalized sections. Verifies that section data is in-range (for116  // sections with content) and that address ranges are non-overlapping.117 118  LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");119 120  for (auto &SecRef : Obj.sections()) {121    NormalizedSection NSec;122    uint32_t DataOffset = 0;123 124    auto SecIndex = Obj.getSectionIndex(SecRef.getRawDataRefImpl());125 126    if (Obj.is64Bit()) {127      const MachO::section_64 &Sec64 =128          Obj.getSection64(SecRef.getRawDataRefImpl());129 130      memcpy(&NSec.SectName, &Sec64.sectname, 16);131      NSec.SectName[16] = '\0';132      memcpy(&NSec.SegName, Sec64.segname, 16);133      NSec.SegName[16] = '\0';134 135      NSec.Address = orc::ExecutorAddr(Sec64.addr);136      NSec.Size = Sec64.size;137      NSec.Alignment = 1ULL << Sec64.align;138      NSec.Flags = Sec64.flags;139      DataOffset = Sec64.offset;140    } else {141      const MachO::section &Sec32 = Obj.getSection(SecRef.getRawDataRefImpl());142 143      memcpy(&NSec.SectName, &Sec32.sectname, 16);144      NSec.SectName[16] = '\0';145      memcpy(&NSec.SegName, Sec32.segname, 16);146      NSec.SegName[16] = '\0';147 148      NSec.Address = orc::ExecutorAddr(Sec32.addr);149      NSec.Size = Sec32.size;150      NSec.Alignment = 1ULL << Sec32.align;151      NSec.Flags = Sec32.flags;152      DataOffset = Sec32.offset;153    }154 155    LLVM_DEBUG({156      dbgs() << "  " << NSec.SegName << "," << NSec.SectName << ": "157             << formatv("{0:x16}", NSec.Address) << " -- "158             << formatv("{0:x16}", NSec.Address + NSec.Size)159             << ", align: " << NSec.Alignment << ", index: " << SecIndex160             << "\n";161    });162 163    // Get the section data if any.164    if (!isZeroFillSection(NSec)) {165      if (DataOffset + NSec.Size > Obj.getData().size())166        return make_error<JITLinkError>(167            "Section data extends past end of file");168 169      NSec.Data = Obj.getData().data() + DataOffset;170    }171 172    // Get prot flags.173    // FIXME: Make sure this test is correct (it's probably missing cases174    // as-is).175    orc::MemProt Prot;176    if (NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS)177      Prot = orc::MemProt::Read | orc::MemProt::Exec;178    else179      Prot = orc::MemProt::Read | orc::MemProt::Write;180 181    auto FullyQualifiedName =182        G->allocateContent(StringRef(NSec.SegName) + "," + NSec.SectName);183    NSec.GraphSection = &G->createSection(184        StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()), Prot);185 186    // TODO: Are there any other criteria for NoAlloc lifetime?187    if (NSec.Flags & MachO::S_ATTR_DEBUG)188      NSec.GraphSection->setMemLifetime(orc::MemLifetime::NoAlloc);189 190    IndexToSection.insert(std::make_pair(SecIndex, std::move(NSec)));191  }192 193  std::vector<NormalizedSection *> Sections;194  Sections.reserve(IndexToSection.size());195  for (auto &KV : IndexToSection)196    Sections.push_back(&KV.second);197 198  // If we didn't end up creating any sections then bail out. The code below199  // assumes that we have at least one section.200  if (Sections.empty())201    return Error::success();202 203  llvm::sort(Sections,204             [](const NormalizedSection *LHS, const NormalizedSection *RHS) {205               assert(LHS && RHS && "Null section?");206               return std::tie(LHS->Address, LHS->Size) <207                      std::tie(RHS->Address, RHS->Size);208             });209 210  for (unsigned I = 0, E = Sections.size() - 1; I != E; ++I) {211    auto &Cur = *Sections[I];212    auto &Next = *Sections[I + 1];213    if (Next.Address < Cur.Address + Cur.Size)214      return make_error<JITLinkError>(215          "Address range for section " +216          formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Cur.SegName,217                  Cur.SectName, Cur.Address, Cur.Address + Cur.Size) +218          "overlaps section \"" + Next.SegName + "/" + Next.SectName + "\"" +219          formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Next.SegName,220                  Next.SectName, Next.Address, Next.Address + Next.Size));221  }222 223  return Error::success();224}225 226Error MachOLinkGraphBuilder::createNormalizedSymbols() {227  LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");228 229  for (auto &SymRef : Obj.symbols()) {230 231    unsigned SymbolIndex = Obj.getSymbolIndex(SymRef.getRawDataRefImpl());232    uint64_t Value;233    uint32_t NStrX;234    uint8_t Type;235    uint8_t Sect;236    uint16_t Desc;237 238    if (Obj.is64Bit()) {239      const MachO::nlist_64 &NL64 =240          Obj.getSymbol64TableEntry(SymRef.getRawDataRefImpl());241      Value = NL64.n_value;242      NStrX = NL64.n_strx;243      Type = NL64.n_type;244      Sect = NL64.n_sect;245      Desc = NL64.n_desc;246    } else {247      const MachO::nlist &NL32 =248          Obj.getSymbolTableEntry(SymRef.getRawDataRefImpl());249      Value = NL32.n_value;250      NStrX = NL32.n_strx;251      Type = NL32.n_type;252      Sect = NL32.n_sect;253      Desc = NL32.n_desc;254    }255 256    // Skip stabs.257    // FIXME: Are there other symbols we should be skipping?258    if (Type & MachO::N_STAB)259      continue;260 261    std::optional<StringRef> Name;262    if (NStrX) {263      if (auto NameOrErr = SymRef.getName())264        Name = *NameOrErr;265      else266        return NameOrErr.takeError();267    } else if (Type & MachO::N_EXT)268      return make_error<JITLinkError>("Symbol at index " +269                                      formatv("{0}", SymbolIndex) +270                                      " has no name (string table index 0), "271                                      "but N_EXT bit is set");272 273    LLVM_DEBUG({274      dbgs() << "  ";275      if (!Name)276        dbgs() << "<anonymous symbol>";277      else278        dbgs() << *Name;279      dbgs() << ": value = " << formatv("{0:x16}", Value)280             << ", type = " << formatv("{0:x2}", Type)281             << ", desc = " << formatv("{0:x4}", Desc) << ", sect = ";282      if (Sect)283        dbgs() << static_cast<unsigned>(Sect - 1);284      else285        dbgs() << "none";286      dbgs() << "\n";287    });288 289    // If this symbol has a section, verify that the addresses line up.290    if (Sect != 0) {291      auto NSec = findSectionByIndex(Sect - 1);292      if (!NSec)293        return NSec.takeError();294 295      if (orc::ExecutorAddr(Value) < NSec->Address ||296          orc::ExecutorAddr(Value) > NSec->Address + NSec->Size)297        return make_error<JITLinkError>("Address " + formatv("{0:x}", Value) +298                                        " for symbol " + *Name +299                                        " does not fall within section");300 301      if (!NSec->GraphSection) {302        LLVM_DEBUG({303          dbgs() << "  Skipping: Symbol is in section " << NSec->SegName << "/"304                 << NSec->SectName305                 << " which has no associated graph section.\n";306        });307        continue;308      }309    }310 311    IndexToSymbol[SymbolIndex] = &createNormalizedSymbol(312        Name, Value, Type, Sect, Desc, getLinkage(Desc), getScope(*Name, Type));313  }314 315  return Error::success();316}317 318void MachOLinkGraphBuilder::addSectionStartSymAndBlock(319    unsigned SecIndex, Section &GraphSec, orc::ExecutorAddr Address,320    const char *Data, orc::ExecutorAddrDiff Size, uint32_t Alignment,321    bool IsLive) {322  Block &B =323      Data ? G->createContentBlock(GraphSec, ArrayRef<char>(Data, Size),324                                   Address, Alignment, 0)325           : G->createZeroFillBlock(GraphSec, Size, Address, Alignment, 0);326  auto &Sym = G->addAnonymousSymbol(B, 0, Size, false, IsLive);327  auto SecI = IndexToSection.find(SecIndex);328  assert(SecI != IndexToSection.end() && "SecIndex invalid");329  auto &NSec = SecI->second;330  assert(!NSec.CanonicalSymbols.count(Sym.getAddress()) &&331         "Anonymous block start symbol clashes with existing symbol address");332  NSec.CanonicalSymbols[Sym.getAddress()] = &Sym;333}334 335Error MachOLinkGraphBuilder::graphifyRegularSymbols() {336 337  LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");338 339  /// We only have 256 section indexes: Use a vector rather than a map.340  std::vector<std::vector<NormalizedSymbol *>> SecIndexToSymbols;341  SecIndexToSymbols.resize(256);342 343  // Create commons, externs, and absolutes, and partition all other symbols by344  // section.345  for (auto &KV : IndexToSymbol) {346    auto &NSym = *KV.second;347 348    switch (NSym.Type & MachO::N_TYPE) {349    case MachO::N_UNDF:350      if (NSym.Value) {351        if (!NSym.Name)352          return make_error<JITLinkError>("Anonymous common symbol at index " +353                                          Twine(KV.first));354        NSym.GraphSymbol = &G->addDefinedSymbol(355            G->createZeroFillBlock(getCommonSection(),356                                   orc::ExecutorAddrDiff(NSym.Value),357                                   orc::ExecutorAddr(),358                                   1ull << MachO::GET_COMM_ALIGN(NSym.Desc), 0),359            0, *NSym.Name, orc::ExecutorAddrDiff(NSym.Value), Linkage::Weak,360            NSym.S, false, NSym.Desc & MachO::N_NO_DEAD_STRIP);361      } else {362        if (!NSym.Name)363          return make_error<JITLinkError>("Anonymous external symbol at "364                                          "index " +365                                          Twine(KV.first));366        NSym.GraphSymbol = &G->addExternalSymbol(367            *NSym.Name, 0, (NSym.Desc & MachO::N_WEAK_REF) != 0);368      }369      break;370    case MachO::N_ABS:371      if (!NSym.Name)372        return make_error<JITLinkError>("Anonymous absolute symbol at index " +373                                        Twine(KV.first));374      NSym.GraphSymbol = &G->addAbsoluteSymbol(375          *NSym.Name, orc::ExecutorAddr(NSym.Value), 0, Linkage::Strong,376          getScope(*NSym.Name, NSym.Type), NSym.Desc & MachO::N_NO_DEAD_STRIP);377      break;378    case MachO::N_SECT:379      SecIndexToSymbols[NSym.Sect - 1].push_back(&NSym);380      break;381    case MachO::N_PBUD:382      return make_error<JITLinkError>(383          "Unupported N_PBUD symbol " +384          (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +385          " at index " + Twine(KV.first));386    case MachO::N_INDR:387      return make_error<JITLinkError>(388          "Unupported N_INDR symbol " +389          (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +390          " at index " + Twine(KV.first));391    default:392      return make_error<JITLinkError>(393          "Unrecognized symbol type " + Twine(NSym.Type & MachO::N_TYPE) +394          " for symbol " +395          (NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +396          " at index " + Twine(KV.first));397    }398  }399 400  // Loop over sections performing regular graphification for those that401  // don't have custom parsers.402  for (auto &KV : IndexToSection) {403    auto SecIndex = KV.first;404    auto &NSec = KV.second;405 406    if (!NSec.GraphSection) {407      LLVM_DEBUG({408        dbgs() << "  " << NSec.SegName << "/" << NSec.SectName409               << " has no graph section. Skipping.\n";410      });411      continue;412    }413 414    // Skip sections with custom parsers.415    if (CustomSectionParserFunctions.count(NSec.GraphSection->getName())) {416      LLVM_DEBUG({417        dbgs() << "  Skipping section " << NSec.GraphSection->getName()418               << " as it has a custom parser.\n";419      });420      continue;421    } else if ((NSec.Flags & MachO::SECTION_TYPE) ==422               MachO::S_CSTRING_LITERALS) {423      if (auto Err = graphifyCStringSection(424              NSec, std::move(SecIndexToSymbols[SecIndex])))425        return Err;426      continue;427    } else428      LLVM_DEBUG({429        dbgs() << "  Graphifying regular section "430               << NSec.GraphSection->getName() << "...\n";431      });432 433    bool SectionIsNoDeadStrip = NSec.Flags & MachO::S_ATTR_NO_DEAD_STRIP;434    bool SectionIsText = NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;435 436    auto &SecNSymStack = SecIndexToSymbols[SecIndex];437 438    // If this section is non-empty but there are no symbols covering it then439    // create one block and anonymous symbol to cover the entire section.440    if (SecNSymStack.empty()) {441      if (NSec.Size > 0) {442        LLVM_DEBUG({443          dbgs() << "    Section non-empty, but contains no symbols. "444                    "Creating anonymous block to cover "445                 << formatv("{0:x16}", NSec.Address) << " -- "446                 << formatv("{0:x16}", NSec.Address + NSec.Size) << "\n";447        });448        addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,449                                   NSec.Data, NSec.Size, NSec.Alignment,450                                   SectionIsNoDeadStrip);451      } else452        LLVM_DEBUG({453          dbgs() << "    Section empty and contains no symbols. Skipping.\n";454        });455      continue;456    }457 458    // Sort the symbol stack in by address, alt-entry status, scope, and name.459    // We sort in reverse order so that symbols will be visited in the right460    // order when we pop off the stack below.461    llvm::sort(SecNSymStack, [](const NormalizedSymbol *LHS,462                                const NormalizedSymbol *RHS) {463      if (LHS->Value != RHS->Value)464        return LHS->Value > RHS->Value;465      if (isAltEntry(*LHS) != isAltEntry(*RHS))466        return isAltEntry(*RHS);467      if (LHS->S != RHS->S)468        return static_cast<uint8_t>(LHS->S) < static_cast<uint8_t>(RHS->S);469      return LHS->Name < RHS->Name;470    });471 472    // The first symbol in a section can not be an alt-entry symbol.473    if (!SecNSymStack.empty() && isAltEntry(*SecNSymStack.back()))474      return make_error<JITLinkError>(475          "First symbol in " + NSec.GraphSection->getName() + " is alt-entry");476 477    // If the section is non-empty but there is no symbol covering the start478    // address then add an anonymous one.479    if (orc::ExecutorAddr(SecNSymStack.back()->Value) != NSec.Address) {480      auto AnonBlockSize =481          orc::ExecutorAddr(SecNSymStack.back()->Value) - NSec.Address;482      LLVM_DEBUG({483        dbgs() << "    Section start not covered by symbol. "484               << "Creating anonymous block to cover [ " << NSec.Address485               << " -- " << (NSec.Address + AnonBlockSize) << " ]\n";486      });487      addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,488                                 NSec.Data, AnonBlockSize, NSec.Alignment,489                                 SectionIsNoDeadStrip);490    }491 492    // Visit section symbols in order by popping off the reverse-sorted stack,493    // building graph symbols as we go.494    //495    // If MH_SUBSECTIONS_VIA_SYMBOLS is set we'll build a block for each496    // alt-entry chain.497    //498    // If MH_SUBSECTIONS_VIA_SYMBOLS is not set then we'll just build one block499    // for the whole section.500    while (!SecNSymStack.empty()) {501      SmallVector<NormalizedSymbol *, 8> BlockSyms;502 503      // Get the symbols in this alt-entry chain, or the whole section (if504      // !SubsectionsViaSymbols).505      BlockSyms.push_back(SecNSymStack.back());506      SecNSymStack.pop_back();507      while (!SecNSymStack.empty() &&508             (isAltEntry(*SecNSymStack.back()) ||509              SecNSymStack.back()->Value == BlockSyms.back()->Value ||510             !SubsectionsViaSymbols)) {511        BlockSyms.push_back(SecNSymStack.back());512        SecNSymStack.pop_back();513      }514 515      // BlockNSyms now contains the block symbols in reverse canonical order.516      auto BlockStart = orc::ExecutorAddr(BlockSyms.front()->Value);517      orc::ExecutorAddr BlockEnd =518          SecNSymStack.empty() ? NSec.Address + NSec.Size519                               : orc::ExecutorAddr(SecNSymStack.back()->Value);520      orc::ExecutorAddrDiff BlockOffset = BlockStart - NSec.Address;521      orc::ExecutorAddrDiff BlockSize = BlockEnd - BlockStart;522 523      LLVM_DEBUG({524        dbgs() << "    Creating block for " << formatv("{0:x16}", BlockStart)525               << " -- " << formatv("{0:x16}", BlockEnd) << ": "526               << NSec.GraphSection->getName() << " + "527               << formatv("{0:x16}", BlockOffset) << " with "528               << BlockSyms.size() << " symbol(s)...\n";529      });530 531      Block &B =532          NSec.Data533              ? G->createContentBlock(534                    *NSec.GraphSection,535                    ArrayRef<char>(NSec.Data + BlockOffset, BlockSize),536                    BlockStart, NSec.Alignment, BlockStart % NSec.Alignment)537              : G->createZeroFillBlock(*NSec.GraphSection, BlockSize,538                                       BlockStart, NSec.Alignment,539                                       BlockStart % NSec.Alignment);540 541      std::optional<orc::ExecutorAddr> LastCanonicalAddr;542      auto SymEnd = BlockEnd;543      while (!BlockSyms.empty()) {544        auto &NSym = *BlockSyms.back();545        BlockSyms.pop_back();546 547        bool SymLive =548            (NSym.Desc & MachO::N_NO_DEAD_STRIP) || SectionIsNoDeadStrip;549 550        auto &Sym = createStandardGraphSymbol(551            NSym, B, SymEnd - orc::ExecutorAddr(NSym.Value), SectionIsText,552            SymLive, LastCanonicalAddr != orc::ExecutorAddr(NSym.Value));553 554        if (LastCanonicalAddr != Sym.getAddress()) {555          if (LastCanonicalAddr)556            SymEnd = *LastCanonicalAddr;557          LastCanonicalAddr = Sym.getAddress();558        }559      }560    }561  }562 563  return Error::success();564}565 566Symbol &MachOLinkGraphBuilder::createStandardGraphSymbol(NormalizedSymbol &NSym,567                                                         Block &B, size_t Size,568                                                         bool IsText,569                                                         bool IsNoDeadStrip,570                                                         bool IsCanonical) {571 572  LLVM_DEBUG({573    dbgs() << "      " << formatv("{0:x16}", NSym.Value) << " -- "574           << formatv("{0:x16}", NSym.Value + Size) << ": ";575    if (!NSym.Name)576      dbgs() << "<anonymous symbol>";577    else578      dbgs() << *NSym.Name;579    if (IsText)580      dbgs() << " [text]";581    if (IsNoDeadStrip)582      dbgs() << " [no-dead-strip]";583    if (!IsCanonical)584      dbgs() << " [non-canonical]";585    dbgs() << "\n";586  });587 588  auto SymOffset = orc::ExecutorAddr(NSym.Value) - B.getAddress();589  auto &Sym =590      NSym.Name591          ? G->addDefinedSymbol(B, SymOffset, *NSym.Name, Size, NSym.L, NSym.S,592                                IsText, IsNoDeadStrip)593          : G->addAnonymousSymbol(B, SymOffset, Size, IsText, IsNoDeadStrip);594  NSym.GraphSymbol = &Sym;595 596  if (IsCanonical)597    setCanonicalSymbol(getSectionByIndex(NSym.Sect - 1), Sym);598 599  return Sym;600}601 602Error MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() {603  // Graphify special sections.604  for (auto &KV : IndexToSection) {605    auto &NSec = KV.second;606 607    // Skip non-graph sections.608    if (!NSec.GraphSection)609      continue;610 611    auto HI = CustomSectionParserFunctions.find(NSec.GraphSection->getName());612    if (HI != CustomSectionParserFunctions.end()) {613      auto &Parse = HI->second;614      if (auto Err = Parse(NSec))615        return Err;616    }617  }618 619  return Error::success();620}621 622Error MachOLinkGraphBuilder::graphifyCStringSection(623    NormalizedSection &NSec, std::vector<NormalizedSymbol *> NSyms) {624  assert(NSec.GraphSection && "C string literal section missing graph section");625  assert(NSec.Data && "C string literal section has no data");626 627  LLVM_DEBUG({628    dbgs() << "  Graphifying C-string literal section "629           << NSec.GraphSection->getName() << "\n";630  });631 632  if (NSec.Data[NSec.Size - 1] != '\0')633    return make_error<JITLinkError>("C string literal section " +634                                    NSec.GraphSection->getName() +635                                    " does not end with null terminator");636 637  /// Sort into reverse order to use as a stack.638  llvm::sort(NSyms,639             [](const NormalizedSymbol *LHS, const NormalizedSymbol *RHS) {640               if (LHS->Value != RHS->Value)641                 return LHS->Value > RHS->Value;642               if (LHS->L != RHS->L)643                 return LHS->L > RHS->L;644               if (LHS->S != RHS->S)645                 return LHS->S > RHS->S;646               if (RHS->Name) {647                 if (!LHS->Name)648                   return true;649                 return *LHS->Name > *RHS->Name;650               }651               return false;652             });653 654  bool SectionIsNoDeadStrip = NSec.Flags & MachO::S_ATTR_NO_DEAD_STRIP;655  bool SectionIsText = NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;656  orc::ExecutorAddrDiff BlockStart = 0;657 658  // Scan section for null characters.659  for (size_t I = 0; I != NSec.Size; ++I) {660    if (NSec.Data[I] == '\0') {661      size_t BlockSize = I + 1 - BlockStart;662      // Create a block for this null terminated string.663      auto &B = G->createContentBlock(*NSec.GraphSection,664                                      {NSec.Data + BlockStart, BlockSize},665                                      NSec.Address + BlockStart, NSec.Alignment,666                                      BlockStart % NSec.Alignment);667 668      LLVM_DEBUG({669        dbgs() << "    Created block " << B.getRange()670               << ", align = " << B.getAlignment()671               << ", align-ofs = " << B.getAlignmentOffset() << " for \"";672        for (size_t J = 0; J != std::min(B.getSize(), size_t(16)); ++J)673          switch (B.getContent()[J]) {674          case '\0': break;675          case '\n': dbgs() << "\\n"; break;676          case '\t': dbgs() << "\\t"; break;677          default:   dbgs() << B.getContent()[J]; break;678          }679        if (B.getSize() > 16)680          dbgs() << "...";681        dbgs() << "\"\n";682      });683 684      // If there's no symbol at the start of this block then create one.685      if (NSyms.empty() ||686          orc::ExecutorAddr(NSyms.back()->Value) != B.getAddress()) {687        auto &S = G->addAnonymousSymbol(B, 0, BlockSize, false, false);688        setCanonicalSymbol(NSec, S);689        LLVM_DEBUG({690          dbgs() << "      Adding symbol for c-string block " << B.getRange()691                 << ": <anonymous symbol> at offset 0\n";692        });693      }694 695      // Process any remaining symbols that point into this block.696      auto LastCanonicalAddr = B.getAddress() + BlockSize;697      while (!NSyms.empty() && orc::ExecutorAddr(NSyms.back()->Value) <698                                   B.getAddress() + BlockSize) {699        auto &NSym = *NSyms.back();700        size_t SymSize = (B.getAddress() + BlockSize) -701                         orc::ExecutorAddr(NSyms.back()->Value);702        bool SymLive =703            (NSym.Desc & MachO::N_NO_DEAD_STRIP) || SectionIsNoDeadStrip;704 705        bool IsCanonical = false;706        if (LastCanonicalAddr != orc::ExecutorAddr(NSym.Value)) {707          IsCanonical = true;708          LastCanonicalAddr = orc::ExecutorAddr(NSym.Value);709        }710 711        auto &Sym = createStandardGraphSymbol(NSym, B, SymSize, SectionIsText,712                                              SymLive, IsCanonical);713        (void)Sym;714        LLVM_DEBUG({715          dbgs() << "      Adding symbol for c-string block " << B.getRange()716                 << ": "717                 << (Sym.hasName() ? *Sym.getName() : "<anonymous symbol>")718                 << " at offset " << formatv("{0:x}", Sym.getOffset()) << "\n";719        });720 721        NSyms.pop_back();722      }723 724      BlockStart += BlockSize;725    }726  }727 728  assert(llvm::all_of(NSec.GraphSection->blocks(),729                      [](Block *B) { return isCStringBlock(*B); }) &&730         "All blocks in section should hold single c-strings");731 732  return Error::success();733}734 735} // end namespace jitlink736} // end namespace llvm737