Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
35271 views
//=--------- MachOLinkGraphBuilder.cpp - MachO LinkGraph builder ----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Generic MachO LinkGraph building code.9//10//===----------------------------------------------------------------------===//1112#include "MachOLinkGraphBuilder.h"13#include <optional>1415#define DEBUG_TYPE "jitlink"1617static const char *CommonSectionName = "__common";1819namespace llvm {20namespace jitlink {2122MachOLinkGraphBuilder::~MachOLinkGraphBuilder() = default;2324Expected<std::unique_ptr<LinkGraph>> MachOLinkGraphBuilder::buildGraph() {2526// We only operate on relocatable objects.27if (!Obj.isRelocatableObject())28return make_error<JITLinkError>("Object is not a relocatable MachO");2930if (auto Err = createNormalizedSections())31return std::move(Err);3233if (auto Err = createNormalizedSymbols())34return std::move(Err);3536if (auto Err = graphifyRegularSymbols())37return std::move(Err);3839if (auto Err = graphifySectionsWithCustomParsers())40return std::move(Err);4142if (auto Err = addRelocations())43return std::move(Err);4445return std::move(G);46}4748MachOLinkGraphBuilder::MachOLinkGraphBuilder(49const object::MachOObjectFile &Obj, Triple TT, SubtargetFeatures Features,50LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)51: Obj(Obj),52G(std::make_unique<LinkGraph>(std::string(Obj.getFileName()),53std::move(TT), std::move(Features),54getPointerSize(Obj), getEndianness(Obj),55std::move(GetEdgeKindName))) {56auto &MachHeader = Obj.getHeader64();57SubsectionsViaSymbols = MachHeader.flags & MachO::MH_SUBSECTIONS_VIA_SYMBOLS;58}5960void MachOLinkGraphBuilder::addCustomSectionParser(61StringRef SectionName, SectionParserFunction Parser) {62assert(!CustomSectionParserFunctions.count(SectionName) &&63"Custom parser for this section already exists");64CustomSectionParserFunctions[SectionName] = std::move(Parser);65}6667Linkage MachOLinkGraphBuilder::getLinkage(uint16_t Desc) {68if ((Desc & MachO::N_WEAK_DEF) || (Desc & MachO::N_WEAK_REF))69return Linkage::Weak;70return Linkage::Strong;71}7273Scope MachOLinkGraphBuilder::getScope(StringRef Name, uint8_t Type) {74if (Type & MachO::N_EXT) {75if ((Type & MachO::N_PEXT) || Name.starts_with("l"))76return Scope::Hidden;77else78return Scope::Default;79}80return Scope::Local;81}8283bool MachOLinkGraphBuilder::isAltEntry(const NormalizedSymbol &NSym) {84return NSym.Desc & MachO::N_ALT_ENTRY;85}8687bool MachOLinkGraphBuilder::isDebugSection(const NormalizedSection &NSec) {88return (NSec.Flags & MachO::S_ATTR_DEBUG &&89strcmp(NSec.SegName, "__DWARF") == 0);90}9192bool MachOLinkGraphBuilder::isZeroFillSection(const NormalizedSection &NSec) {93switch (NSec.Flags & MachO::SECTION_TYPE) {94case MachO::S_ZEROFILL:95case MachO::S_GB_ZEROFILL:96case MachO::S_THREAD_LOCAL_ZEROFILL:97return true;98default:99return false;100}101}102103unsigned104MachOLinkGraphBuilder::getPointerSize(const object::MachOObjectFile &Obj) {105return Obj.is64Bit() ? 8 : 4;106}107108llvm::endianness109MachOLinkGraphBuilder::getEndianness(const object::MachOObjectFile &Obj) {110return Obj.isLittleEndian() ? llvm::endianness::little111: llvm::endianness::big;112}113114Section &MachOLinkGraphBuilder::getCommonSection() {115if (!CommonSection)116CommonSection = &G->createSection(CommonSectionName,117orc::MemProt::Read | orc::MemProt::Write);118return *CommonSection;119}120121Error MachOLinkGraphBuilder::createNormalizedSections() {122// Build normalized sections. Verifies that section data is in-range (for123// sections with content) and that address ranges are non-overlapping.124125LLVM_DEBUG(dbgs() << "Creating normalized sections...\n");126127for (auto &SecRef : Obj.sections()) {128NormalizedSection NSec;129uint32_t DataOffset = 0;130131auto SecIndex = Obj.getSectionIndex(SecRef.getRawDataRefImpl());132133if (Obj.is64Bit()) {134const MachO::section_64 &Sec64 =135Obj.getSection64(SecRef.getRawDataRefImpl());136137memcpy(&NSec.SectName, &Sec64.sectname, 16);138NSec.SectName[16] = '\0';139memcpy(&NSec.SegName, Sec64.segname, 16);140NSec.SegName[16] = '\0';141142NSec.Address = orc::ExecutorAddr(Sec64.addr);143NSec.Size = Sec64.size;144NSec.Alignment = 1ULL << Sec64.align;145NSec.Flags = Sec64.flags;146DataOffset = Sec64.offset;147} else {148const MachO::section &Sec32 = Obj.getSection(SecRef.getRawDataRefImpl());149150memcpy(&NSec.SectName, &Sec32.sectname, 16);151NSec.SectName[16] = '\0';152memcpy(&NSec.SegName, Sec32.segname, 16);153NSec.SegName[16] = '\0';154155NSec.Address = orc::ExecutorAddr(Sec32.addr);156NSec.Size = Sec32.size;157NSec.Alignment = 1ULL << Sec32.align;158NSec.Flags = Sec32.flags;159DataOffset = Sec32.offset;160}161162LLVM_DEBUG({163dbgs() << " " << NSec.SegName << "," << NSec.SectName << ": "164<< formatv("{0:x16}", NSec.Address) << " -- "165<< formatv("{0:x16}", NSec.Address + NSec.Size)166<< ", align: " << NSec.Alignment << ", index: " << SecIndex167<< "\n";168});169170// Get the section data if any.171if (!isZeroFillSection(NSec)) {172if (DataOffset + NSec.Size > Obj.getData().size())173return make_error<JITLinkError>(174"Section data extends past end of file");175176NSec.Data = Obj.getData().data() + DataOffset;177}178179// Get prot flags.180// FIXME: Make sure this test is correct (it's probably missing cases181// as-is).182orc::MemProt Prot;183if (NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS)184Prot = orc::MemProt::Read | orc::MemProt::Exec;185else186Prot = orc::MemProt::Read | orc::MemProt::Write;187188auto FullyQualifiedName =189G->allocateContent(StringRef(NSec.SegName) + "," + NSec.SectName);190NSec.GraphSection = &G->createSection(191StringRef(FullyQualifiedName.data(), FullyQualifiedName.size()), Prot);192193// TODO: Are there any other criteria for NoAlloc lifetime?194if (NSec.Flags & MachO::S_ATTR_DEBUG)195NSec.GraphSection->setMemLifetime(orc::MemLifetime::NoAlloc);196197IndexToSection.insert(std::make_pair(SecIndex, std::move(NSec)));198}199200std::vector<NormalizedSection *> Sections;201Sections.reserve(IndexToSection.size());202for (auto &KV : IndexToSection)203Sections.push_back(&KV.second);204205// If we didn't end up creating any sections then bail out. The code below206// assumes that we have at least one section.207if (Sections.empty())208return Error::success();209210llvm::sort(Sections,211[](const NormalizedSection *LHS, const NormalizedSection *RHS) {212assert(LHS && RHS && "Null section?");213if (LHS->Address != RHS->Address)214return LHS->Address < RHS->Address;215return LHS->Size < RHS->Size;216});217218for (unsigned I = 0, E = Sections.size() - 1; I != E; ++I) {219auto &Cur = *Sections[I];220auto &Next = *Sections[I + 1];221if (Next.Address < Cur.Address + Cur.Size)222return make_error<JITLinkError>(223"Address range for section " +224formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Cur.SegName,225Cur.SectName, Cur.Address, Cur.Address + Cur.Size) +226"overlaps section \"" + Next.SegName + "/" + Next.SectName + "\"" +227formatv("\"{0}/{1}\" [ {2:x16} -- {3:x16} ] ", Next.SegName,228Next.SectName, Next.Address, Next.Address + Next.Size));229}230231return Error::success();232}233234Error MachOLinkGraphBuilder::createNormalizedSymbols() {235LLVM_DEBUG(dbgs() << "Creating normalized symbols...\n");236237for (auto &SymRef : Obj.symbols()) {238239unsigned SymbolIndex = Obj.getSymbolIndex(SymRef.getRawDataRefImpl());240uint64_t Value;241uint32_t NStrX;242uint8_t Type;243uint8_t Sect;244uint16_t Desc;245246if (Obj.is64Bit()) {247const MachO::nlist_64 &NL64 =248Obj.getSymbol64TableEntry(SymRef.getRawDataRefImpl());249Value = NL64.n_value;250NStrX = NL64.n_strx;251Type = NL64.n_type;252Sect = NL64.n_sect;253Desc = NL64.n_desc;254} else {255const MachO::nlist &NL32 =256Obj.getSymbolTableEntry(SymRef.getRawDataRefImpl());257Value = NL32.n_value;258NStrX = NL32.n_strx;259Type = NL32.n_type;260Sect = NL32.n_sect;261Desc = NL32.n_desc;262}263264// Skip stabs.265// FIXME: Are there other symbols we should be skipping?266if (Type & MachO::N_STAB)267continue;268269std::optional<StringRef> Name;270if (NStrX) {271if (auto NameOrErr = SymRef.getName())272Name = *NameOrErr;273else274return NameOrErr.takeError();275} else if (Type & MachO::N_EXT)276return make_error<JITLinkError>("Symbol at index " +277formatv("{0}", SymbolIndex) +278" has no name (string table index 0), "279"but N_EXT bit is set");280281LLVM_DEBUG({282dbgs() << " ";283if (!Name)284dbgs() << "<anonymous symbol>";285else286dbgs() << *Name;287dbgs() << ": value = " << formatv("{0:x16}", Value)288<< ", type = " << formatv("{0:x2}", Type)289<< ", desc = " << formatv("{0:x4}", Desc) << ", sect = ";290if (Sect)291dbgs() << static_cast<unsigned>(Sect - 1);292else293dbgs() << "none";294dbgs() << "\n";295});296297// If this symbol has a section, verify that the addresses line up.298if (Sect != 0) {299auto NSec = findSectionByIndex(Sect - 1);300if (!NSec)301return NSec.takeError();302303if (orc::ExecutorAddr(Value) < NSec->Address ||304orc::ExecutorAddr(Value) > NSec->Address + NSec->Size)305return make_error<JITLinkError>("Address " + formatv("{0:x}", Value) +306" for symbol " + *Name +307" does not fall within section");308309if (!NSec->GraphSection) {310LLVM_DEBUG({311dbgs() << " Skipping: Symbol is in section " << NSec->SegName << "/"312<< NSec->SectName313<< " which has no associated graph section.\n";314});315continue;316}317}318319IndexToSymbol[SymbolIndex] =320&createNormalizedSymbol(*Name, Value, Type, Sect, Desc,321getLinkage(Desc), getScope(*Name, Type));322}323324return Error::success();325}326327void MachOLinkGraphBuilder::addSectionStartSymAndBlock(328unsigned SecIndex, Section &GraphSec, orc::ExecutorAddr Address,329const char *Data, orc::ExecutorAddrDiff Size, uint32_t Alignment,330bool IsLive) {331Block &B =332Data ? G->createContentBlock(GraphSec, ArrayRef<char>(Data, Size),333Address, Alignment, 0)334: G->createZeroFillBlock(GraphSec, Size, Address, Alignment, 0);335auto &Sym = G->addAnonymousSymbol(B, 0, Size, false, IsLive);336auto SecI = IndexToSection.find(SecIndex);337assert(SecI != IndexToSection.end() && "SecIndex invalid");338auto &NSec = SecI->second;339assert(!NSec.CanonicalSymbols.count(Sym.getAddress()) &&340"Anonymous block start symbol clashes with existing symbol address");341NSec.CanonicalSymbols[Sym.getAddress()] = &Sym;342}343344Error MachOLinkGraphBuilder::graphifyRegularSymbols() {345346LLVM_DEBUG(dbgs() << "Creating graph symbols...\n");347348/// We only have 256 section indexes: Use a vector rather than a map.349std::vector<std::vector<NormalizedSymbol *>> SecIndexToSymbols;350SecIndexToSymbols.resize(256);351352// Create commons, externs, and absolutes, and partition all other symbols by353// section.354for (auto &KV : IndexToSymbol) {355auto &NSym = *KV.second;356357switch (NSym.Type & MachO::N_TYPE) {358case MachO::N_UNDF:359if (NSym.Value) {360if (!NSym.Name)361return make_error<JITLinkError>("Anonymous common symbol at index " +362Twine(KV.first));363NSym.GraphSymbol = &G->addDefinedSymbol(364G->createZeroFillBlock(getCommonSection(),365orc::ExecutorAddrDiff(NSym.Value),366orc::ExecutorAddr(),3671ull << MachO::GET_COMM_ALIGN(NSym.Desc), 0),3680, *NSym.Name, orc::ExecutorAddrDiff(NSym.Value), Linkage::Strong,369NSym.S, false, NSym.Desc & MachO::N_NO_DEAD_STRIP);370} else {371if (!NSym.Name)372return make_error<JITLinkError>("Anonymous external symbol at "373"index " +374Twine(KV.first));375NSym.GraphSymbol = &G->addExternalSymbol(376*NSym.Name, 0, (NSym.Desc & MachO::N_WEAK_REF) != 0);377}378break;379case MachO::N_ABS:380if (!NSym.Name)381return make_error<JITLinkError>("Anonymous absolute symbol at index " +382Twine(KV.first));383NSym.GraphSymbol = &G->addAbsoluteSymbol(384*NSym.Name, orc::ExecutorAddr(NSym.Value), 0, Linkage::Strong,385getScope(*NSym.Name, NSym.Type), NSym.Desc & MachO::N_NO_DEAD_STRIP);386break;387case MachO::N_SECT:388SecIndexToSymbols[NSym.Sect - 1].push_back(&NSym);389break;390case MachO::N_PBUD:391return make_error<JITLinkError>(392"Unupported N_PBUD symbol " +393(NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +394" at index " + Twine(KV.first));395case MachO::N_INDR:396return make_error<JITLinkError>(397"Unupported N_INDR symbol " +398(NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +399" at index " + Twine(KV.first));400default:401return make_error<JITLinkError>(402"Unrecognized symbol type " + Twine(NSym.Type & MachO::N_TYPE) +403" for symbol " +404(NSym.Name ? ("\"" + *NSym.Name + "\"") : Twine("<anon>")) +405" at index " + Twine(KV.first));406}407}408409// Loop over sections performing regular graphification for those that410// don't have custom parsers.411for (auto &KV : IndexToSection) {412auto SecIndex = KV.first;413auto &NSec = KV.second;414415if (!NSec.GraphSection) {416LLVM_DEBUG({417dbgs() << " " << NSec.SegName << "/" << NSec.SectName418<< " has no graph section. Skipping.\n";419});420continue;421}422423// Skip sections with custom parsers.424if (CustomSectionParserFunctions.count(NSec.GraphSection->getName())) {425LLVM_DEBUG({426dbgs() << " Skipping section " << NSec.GraphSection->getName()427<< " as it has a custom parser.\n";428});429continue;430} else if ((NSec.Flags & MachO::SECTION_TYPE) ==431MachO::S_CSTRING_LITERALS) {432if (auto Err = graphifyCStringSection(433NSec, std::move(SecIndexToSymbols[SecIndex])))434return Err;435continue;436} else437LLVM_DEBUG({438dbgs() << " Graphifying regular section "439<< NSec.GraphSection->getName() << "...\n";440});441442bool SectionIsNoDeadStrip = NSec.Flags & MachO::S_ATTR_NO_DEAD_STRIP;443bool SectionIsText = NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;444445auto &SecNSymStack = SecIndexToSymbols[SecIndex];446447// If this section is non-empty but there are no symbols covering it then448// create one block and anonymous symbol to cover the entire section.449if (SecNSymStack.empty()) {450if (NSec.Size > 0) {451LLVM_DEBUG({452dbgs() << " Section non-empty, but contains no symbols. "453"Creating anonymous block to cover "454<< formatv("{0:x16}", NSec.Address) << " -- "455<< formatv("{0:x16}", NSec.Address + NSec.Size) << "\n";456});457addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,458NSec.Data, NSec.Size, NSec.Alignment,459SectionIsNoDeadStrip);460} else461LLVM_DEBUG({462dbgs() << " Section empty and contains no symbols. Skipping.\n";463});464continue;465}466467// Sort the symbol stack in by address, alt-entry status, scope, and name.468// We sort in reverse order so that symbols will be visited in the right469// order when we pop off the stack below.470llvm::sort(SecNSymStack, [](const NormalizedSymbol *LHS,471const NormalizedSymbol *RHS) {472if (LHS->Value != RHS->Value)473return LHS->Value > RHS->Value;474if (isAltEntry(*LHS) != isAltEntry(*RHS))475return isAltEntry(*RHS);476if (LHS->S != RHS->S)477return static_cast<uint8_t>(LHS->S) < static_cast<uint8_t>(RHS->S);478return LHS->Name < RHS->Name;479});480481// The first symbol in a section can not be an alt-entry symbol.482if (!SecNSymStack.empty() && isAltEntry(*SecNSymStack.back()))483return make_error<JITLinkError>(484"First symbol in " + NSec.GraphSection->getName() + " is alt-entry");485486// If the section is non-empty but there is no symbol covering the start487// address then add an anonymous one.488if (orc::ExecutorAddr(SecNSymStack.back()->Value) != NSec.Address) {489auto AnonBlockSize =490orc::ExecutorAddr(SecNSymStack.back()->Value) - NSec.Address;491LLVM_DEBUG({492dbgs() << " Section start not covered by symbol. "493<< "Creating anonymous block to cover [ " << NSec.Address494<< " -- " << (NSec.Address + AnonBlockSize) << " ]\n";495});496addSectionStartSymAndBlock(SecIndex, *NSec.GraphSection, NSec.Address,497NSec.Data, AnonBlockSize, NSec.Alignment,498SectionIsNoDeadStrip);499}500501// Visit section symbols in order by popping off the reverse-sorted stack,502// building graph symbols as we go.503//504// If MH_SUBSECTIONS_VIA_SYMBOLS is set we'll build a block for each505// alt-entry chain.506//507// If MH_SUBSECTIONS_VIA_SYMBOLS is not set then we'll just build one block508// for the whole section.509while (!SecNSymStack.empty()) {510SmallVector<NormalizedSymbol *, 8> BlockSyms;511512// Get the symbols in this alt-entry chain, or the whole section (if513// !SubsectionsViaSymbols).514BlockSyms.push_back(SecNSymStack.back());515SecNSymStack.pop_back();516while (!SecNSymStack.empty() &&517(isAltEntry(*SecNSymStack.back()) ||518SecNSymStack.back()->Value == BlockSyms.back()->Value ||519!SubsectionsViaSymbols)) {520BlockSyms.push_back(SecNSymStack.back());521SecNSymStack.pop_back();522}523524// BlockNSyms now contains the block symbols in reverse canonical order.525auto BlockStart = orc::ExecutorAddr(BlockSyms.front()->Value);526orc::ExecutorAddr BlockEnd =527SecNSymStack.empty() ? NSec.Address + NSec.Size528: orc::ExecutorAddr(SecNSymStack.back()->Value);529orc::ExecutorAddrDiff BlockOffset = BlockStart - NSec.Address;530orc::ExecutorAddrDiff BlockSize = BlockEnd - BlockStart;531532LLVM_DEBUG({533dbgs() << " Creating block for " << formatv("{0:x16}", BlockStart)534<< " -- " << formatv("{0:x16}", BlockEnd) << ": "535<< NSec.GraphSection->getName() << " + "536<< formatv("{0:x16}", BlockOffset) << " with "537<< BlockSyms.size() << " symbol(s)...\n";538});539540Block &B =541NSec.Data542? G->createContentBlock(543*NSec.GraphSection,544ArrayRef<char>(NSec.Data + BlockOffset, BlockSize),545BlockStart, NSec.Alignment, BlockStart % NSec.Alignment)546: G->createZeroFillBlock(*NSec.GraphSection, BlockSize,547BlockStart, NSec.Alignment,548BlockStart % NSec.Alignment);549550std::optional<orc::ExecutorAddr> LastCanonicalAddr;551auto SymEnd = BlockEnd;552while (!BlockSyms.empty()) {553auto &NSym = *BlockSyms.back();554BlockSyms.pop_back();555556bool SymLive =557(NSym.Desc & MachO::N_NO_DEAD_STRIP) || SectionIsNoDeadStrip;558559auto &Sym = createStandardGraphSymbol(560NSym, B, SymEnd - orc::ExecutorAddr(NSym.Value), SectionIsText,561SymLive, LastCanonicalAddr != orc::ExecutorAddr(NSym.Value));562563if (LastCanonicalAddr != Sym.getAddress()) {564if (LastCanonicalAddr)565SymEnd = *LastCanonicalAddr;566LastCanonicalAddr = Sym.getAddress();567}568}569}570}571572return Error::success();573}574575Symbol &MachOLinkGraphBuilder::createStandardGraphSymbol(NormalizedSymbol &NSym,576Block &B, size_t Size,577bool IsText,578bool IsNoDeadStrip,579bool IsCanonical) {580581LLVM_DEBUG({582dbgs() << " " << formatv("{0:x16}", NSym.Value) << " -- "583<< formatv("{0:x16}", NSym.Value + Size) << ": ";584if (!NSym.Name)585dbgs() << "<anonymous symbol>";586else587dbgs() << NSym.Name;588if (IsText)589dbgs() << " [text]";590if (IsNoDeadStrip)591dbgs() << " [no-dead-strip]";592if (!IsCanonical)593dbgs() << " [non-canonical]";594dbgs() << "\n";595});596597auto SymOffset = orc::ExecutorAddr(NSym.Value) - B.getAddress();598auto &Sym =599NSym.Name600? G->addDefinedSymbol(B, SymOffset, *NSym.Name, Size, NSym.L, NSym.S,601IsText, IsNoDeadStrip)602: G->addAnonymousSymbol(B, SymOffset, Size, IsText, IsNoDeadStrip);603NSym.GraphSymbol = &Sym;604605if (IsCanonical)606setCanonicalSymbol(getSectionByIndex(NSym.Sect - 1), Sym);607608return Sym;609}610611Error MachOLinkGraphBuilder::graphifySectionsWithCustomParsers() {612// Graphify special sections.613for (auto &KV : IndexToSection) {614auto &NSec = KV.second;615616// Skip non-graph sections.617if (!NSec.GraphSection)618continue;619620auto HI = CustomSectionParserFunctions.find(NSec.GraphSection->getName());621if (HI != CustomSectionParserFunctions.end()) {622auto &Parse = HI->second;623if (auto Err = Parse(NSec))624return Err;625}626}627628return Error::success();629}630631Error MachOLinkGraphBuilder::graphifyCStringSection(632NormalizedSection &NSec, std::vector<NormalizedSymbol *> NSyms) {633assert(NSec.GraphSection && "C string literal section missing graph section");634assert(NSec.Data && "C string literal section has no data");635636LLVM_DEBUG({637dbgs() << " Graphifying C-string literal section "638<< NSec.GraphSection->getName() << "\n";639});640641if (NSec.Data[NSec.Size - 1] != '\0')642return make_error<JITLinkError>("C string literal section " +643NSec.GraphSection->getName() +644" does not end with null terminator");645646/// Sort into reverse order to use as a stack.647llvm::sort(NSyms,648[](const NormalizedSymbol *LHS, const NormalizedSymbol *RHS) {649if (LHS->Value != RHS->Value)650return LHS->Value > RHS->Value;651if (LHS->L != RHS->L)652return LHS->L > RHS->L;653if (LHS->S != RHS->S)654return LHS->S > RHS->S;655if (RHS->Name) {656if (!LHS->Name)657return true;658return *LHS->Name > *RHS->Name;659}660return false;661});662663bool SectionIsNoDeadStrip = NSec.Flags & MachO::S_ATTR_NO_DEAD_STRIP;664bool SectionIsText = NSec.Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;665orc::ExecutorAddrDiff BlockStart = 0;666667// Scan section for null characters.668for (size_t I = 0; I != NSec.Size; ++I) {669if (NSec.Data[I] == '\0') {670size_t BlockSize = I + 1 - BlockStart;671// Create a block for this null terminated string.672auto &B = G->createContentBlock(*NSec.GraphSection,673{NSec.Data + BlockStart, BlockSize},674NSec.Address + BlockStart, NSec.Alignment,675BlockStart % NSec.Alignment);676677LLVM_DEBUG({678dbgs() << " Created block " << B.getRange()679<< ", align = " << B.getAlignment()680<< ", align-ofs = " << B.getAlignmentOffset() << " for \"";681for (size_t J = 0; J != std::min(B.getSize(), size_t(16)); ++J)682switch (B.getContent()[J]) {683case '\0': break;684case '\n': dbgs() << "\\n"; break;685case '\t': dbgs() << "\\t"; break;686default: dbgs() << B.getContent()[J]; break;687}688if (B.getSize() > 16)689dbgs() << "...";690dbgs() << "\"\n";691});692693// If there's no symbol at the start of this block then create one.694if (NSyms.empty() ||695orc::ExecutorAddr(NSyms.back()->Value) != B.getAddress()) {696auto &S = G->addAnonymousSymbol(B, 0, BlockSize, false, false);697setCanonicalSymbol(NSec, S);698LLVM_DEBUG({699dbgs() << " Adding symbol for c-string block " << B.getRange()700<< ": <anonymous symbol> at offset 0\n";701});702}703704// Process any remaining symbols that point into this block.705auto LastCanonicalAddr = B.getAddress() + BlockSize;706while (!NSyms.empty() && orc::ExecutorAddr(NSyms.back()->Value) <707B.getAddress() + BlockSize) {708auto &NSym = *NSyms.back();709size_t SymSize = (B.getAddress() + BlockSize) -710orc::ExecutorAddr(NSyms.back()->Value);711bool SymLive =712(NSym.Desc & MachO::N_NO_DEAD_STRIP) || SectionIsNoDeadStrip;713714bool IsCanonical = false;715if (LastCanonicalAddr != orc::ExecutorAddr(NSym.Value)) {716IsCanonical = true;717LastCanonicalAddr = orc::ExecutorAddr(NSym.Value);718}719720auto &Sym = createStandardGraphSymbol(NSym, B, SymSize, SectionIsText,721SymLive, IsCanonical);722(void)Sym;723LLVM_DEBUG({724dbgs() << " Adding symbol for c-string block " << B.getRange()725<< ": "726<< (Sym.hasName() ? Sym.getName() : "<anonymous symbol>")727<< " at offset " << formatv("{0:x}", Sym.getOffset()) << "\n";728});729730NSyms.pop_back();731}732733BlockStart += BlockSize;734}735}736737assert(llvm::all_of(NSec.GraphSection->blocks(),738[](Block *B) { return isCStringBlock(*B); }) &&739"All blocks in section should hold single c-strings");740741return Error::success();742}743744Error CompactUnwindSplitter::operator()(LinkGraph &G) {745auto *CUSec = G.findSectionByName(CompactUnwindSectionName);746if (!CUSec)747return Error::success();748749if (!G.getTargetTriple().isOSBinFormatMachO())750return make_error<JITLinkError>(751"Error linking " + G.getName() +752": compact unwind splitting not supported on non-macho target " +753G.getTargetTriple().str());754755unsigned CURecordSize = 0;756unsigned PersonalityEdgeOffset = 0;757unsigned LSDAEdgeOffset = 0;758switch (G.getTargetTriple().getArch()) {759case Triple::aarch64:760case Triple::x86_64:761// 64-bit compact-unwind record format:762// Range start: 8 bytes.763// Range size: 4 bytes.764// CU encoding: 4 bytes.765// Personality: 8 bytes.766// LSDA: 8 bytes.767CURecordSize = 32;768PersonalityEdgeOffset = 16;769LSDAEdgeOffset = 24;770break;771default:772return make_error<JITLinkError>(773"Error linking " + G.getName() +774": compact unwind splitting not supported on " +775G.getTargetTriple().getArchName());776}777778std::vector<Block *> OriginalBlocks(CUSec->blocks().begin(),779CUSec->blocks().end());780LLVM_DEBUG({781dbgs() << "In " << G.getName() << " splitting compact unwind section "782<< CompactUnwindSectionName << " containing "783<< OriginalBlocks.size() << " initial blocks...\n";784});785786while (!OriginalBlocks.empty()) {787auto *B = OriginalBlocks.back();788OriginalBlocks.pop_back();789790if (B->getSize() == 0) {791LLVM_DEBUG({792dbgs() << " Skipping empty block at "793<< formatv("{0:x16}", B->getAddress()) << "\n";794});795continue;796}797798LLVM_DEBUG({799dbgs() << " Splitting block at " << formatv("{0:x16}", B->getAddress())800<< " into " << (B->getSize() / CURecordSize)801<< " compact unwind record(s)\n";802});803804if (B->getSize() % CURecordSize)805return make_error<JITLinkError>(806"Error splitting compact unwind record in " + G.getName() +807": block at " + formatv("{0:x}", B->getAddress()) + " has size " +808formatv("{0:x}", B->getSize()) +809" (not a multiple of CU record size of " +810formatv("{0:x}", CURecordSize) + ")");811812unsigned NumBlocks = B->getSize() / CURecordSize;813LinkGraph::SplitBlockCache C;814815for (unsigned I = 0; I != NumBlocks; ++I) {816auto &CURec = G.splitBlock(*B, CURecordSize, &C);817bool AddedKeepAlive = false;818819for (auto &E : CURec.edges()) {820if (E.getOffset() == 0) {821LLVM_DEBUG({822dbgs() << " Updating compact unwind record at "823<< formatv("{0:x16}", CURec.getAddress()) << " to point to "824<< (E.getTarget().hasName() ? E.getTarget().getName()825: StringRef())826<< " (at " << formatv("{0:x16}", E.getTarget().getAddress())827<< ")\n";828});829830if (E.getTarget().isExternal())831return make_error<JITLinkError>(832"Error adding keep-alive edge for compact unwind record at " +833formatv("{0:x}", CURec.getAddress()) + ": target " +834E.getTarget().getName() + " is an external symbol");835auto &TgtBlock = E.getTarget().getBlock();836auto &CURecSym =837G.addAnonymousSymbol(CURec, 0, CURecordSize, false, false);838TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0);839AddedKeepAlive = true;840} else if (E.getOffset() != PersonalityEdgeOffset &&841E.getOffset() != LSDAEdgeOffset)842return make_error<JITLinkError>("Unexpected edge at offset " +843formatv("{0:x}", E.getOffset()) +844" in compact unwind record at " +845formatv("{0:x}", CURec.getAddress()));846}847848if (!AddedKeepAlive)849return make_error<JITLinkError>(850"Error adding keep-alive edge for compact unwind record at " +851formatv("{0:x}", CURec.getAddress()) +852": no outgoing target edge at offset 0");853}854}855return Error::success();856}857858} // end namespace jitlink859} // end namespace llvm860861862