241 lines · c
1//===----- MachOLinkGraphBuilder.h - MachO LinkGraph builder ----*- C++ -*-===//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#ifndef LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H14#define LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H15 16#include "llvm/ADT/DenseMap.h"17#include "llvm/ADT/StringMap.h"18#include "llvm/ExecutionEngine/JITLink/JITLink.h"19#include "llvm/Object/MachO.h"20 21#include "EHFrameSupportImpl.h"22#include "JITLinkGeneric.h"23 24namespace llvm {25namespace jitlink {26 27class MachOLinkGraphBuilder {28public:29 virtual ~MachOLinkGraphBuilder();30 Expected<std::unique_ptr<LinkGraph>> buildGraph();31 32protected:33 34 struct NormalizedSymbol {35 friend class MachOLinkGraphBuilder;36 37 private:38 NormalizedSymbol(std::optional<StringRef> Name, uint64_t Value,39 uint8_t Type, uint8_t Sect, uint16_t Desc, Linkage L,40 Scope S)41 : Name(Name), Value(Value), Type(Type), Sect(Sect), Desc(Desc), L(L),42 S(S) {43 assert((!Name || !Name->empty()) && "Name must be none or non-empty");44 }45 46 public:47 NormalizedSymbol(const NormalizedSymbol &) = delete;48 NormalizedSymbol &operator=(const NormalizedSymbol &) = delete;49 NormalizedSymbol(NormalizedSymbol &&) = delete;50 NormalizedSymbol &operator=(NormalizedSymbol &&) = delete;51 52 std::optional<StringRef> Name;53 uint64_t Value = 0;54 uint8_t Type = 0;55 uint8_t Sect = 0;56 uint16_t Desc = 0;57 Linkage L = Linkage::Strong;58 Scope S = Scope::Default;59 Symbol *GraphSymbol = nullptr;60 };61 62 // Normalized section representation. Section and segment names are guaranteed63 // to be null-terminated, hence the extra bytes on SegName and SectName.64 class NormalizedSection {65 friend class MachOLinkGraphBuilder;66 67 private:68 NormalizedSection() = default;69 70 public:71 char SectName[17];72 char SegName[17];73 orc::ExecutorAddr Address;74 uint64_t Size = 0;75 uint64_t Alignment = 0;76 uint32_t Flags = 0;77 const char *Data = nullptr;78 Section *GraphSection = nullptr;79 std::map<orc::ExecutorAddr, Symbol *> CanonicalSymbols;80 };81 82 using SectionParserFunction = std::function<Error(NormalizedSection &S)>;83 84 MachOLinkGraphBuilder(const object::MachOObjectFile &Obj,85 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,86 SubtargetFeatures Features,87 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);88 LinkGraph &getGraph() const { return *G; }89 90 const object::MachOObjectFile &getObject() const { return Obj; }91 92 void addCustomSectionParser(StringRef SectionName,93 SectionParserFunction Parse);94 95 virtual Error addRelocations() = 0;96 97 /// Create a symbol.98 template <typename... ArgTs>99 NormalizedSymbol &createNormalizedSymbol(ArgTs &&... Args) {100 NormalizedSymbol *Sym = reinterpret_cast<NormalizedSymbol *>(101 Allocator.Allocate<NormalizedSymbol>());102 new (Sym) NormalizedSymbol(std::forward<ArgTs>(Args)...);103 return *Sym;104 }105 106 /// Index is zero-based (MachO section indexes are usually one-based) and107 /// assumed to be in-range. Client is responsible for checking.108 NormalizedSection &getSectionByIndex(unsigned Index) {109 auto I = IndexToSection.find(Index);110 assert(I != IndexToSection.end() && "No section recorded at index");111 return I->second;112 }113 114 /// Try to get the section at the given index. Will return an error if the115 /// given index is out of range, or if no section has been added for the given116 /// index.117 Expected<NormalizedSection &> findSectionByIndex(unsigned Index) {118 auto I = IndexToSection.find(Index);119 if (I == IndexToSection.end())120 return make_error<JITLinkError>("No section recorded for index " +121 formatv("{0:d}", Index));122 return I->second;123 }124 125 /// Try to get the symbol at the given index. Will return an error if the126 /// given index is out of range, or if no symbol has been added for the given127 /// index.128 Expected<NormalizedSymbol &> findSymbolByIndex(uint64_t Index) {129 auto I = IndexToSymbol.find(Index);130 if (I == IndexToSymbol.end())131 return make_error<JITLinkError>("No symbol at index " +132 formatv("{0:d}", Index));133 assert(I->second && "Null symbol at index");134 return *I->second;135 }136 137 /// Returns the symbol with the highest address not greater than the search138 /// address, or null if no such symbol exists.139 Symbol *getSymbolByAddress(NormalizedSection &NSec,140 orc::ExecutorAddr Address) {141 auto I = NSec.CanonicalSymbols.upper_bound(Address);142 if (I == NSec.CanonicalSymbols.begin())143 return nullptr;144 return std::prev(I)->second;145 }146 147 /// Returns the symbol with the highest address not greater than the search148 /// address, or an error if no such symbol exists.149 Expected<Symbol &> findSymbolByAddress(NormalizedSection &NSec,150 orc::ExecutorAddr Address) {151 auto *Sym = getSymbolByAddress(NSec, Address);152 if (Sym)153 if (Address <= Sym->getAddress() + Sym->getSize())154 return *Sym;155 return make_error<JITLinkError>("No symbol covering address " +156 formatv("{0:x16}", Address));157 }158 159 static Linkage getLinkage(uint16_t Desc);160 static Scope getScope(StringRef Name, uint8_t Type);161 static bool isAltEntry(const NormalizedSymbol &NSym);162 163 static bool isDebugSection(const NormalizedSection &NSec);164 static bool isZeroFillSection(const NormalizedSection &NSec);165 166 MachO::relocation_info167 getRelocationInfo(const object::relocation_iterator RelItr) {168 MachO::any_relocation_info ARI =169 getObject().getRelocation(RelItr->getRawDataRefImpl());170 MachO::relocation_info RI;171 RI.r_address = ARI.r_word0;172 RI.r_symbolnum = ARI.r_word1 & 0xffffff;173 RI.r_pcrel = (ARI.r_word1 >> 24) & 1;174 RI.r_length = (ARI.r_word1 >> 25) & 3;175 RI.r_extern = (ARI.r_word1 >> 27) & 1;176 RI.r_type = (ARI.r_word1 >> 28);177 return RI;178 }179 180private:181 static unsigned getPointerSize(const object::MachOObjectFile &Obj);182 static llvm::endianness getEndianness(const object::MachOObjectFile &Obj);183 184 void setCanonicalSymbol(NormalizedSection &NSec, Symbol &Sym) {185 auto *&CanonicalSymEntry = NSec.CanonicalSymbols[Sym.getAddress()];186 // There should be no symbol at this address, or, if there is,187 // it should be a zero-sized symbol from an empty section (which188 // we can safely override).189 assert((!CanonicalSymEntry || CanonicalSymEntry->getSize() == 0) &&190 "Duplicate canonical symbol at address");191 CanonicalSymEntry = &Sym;192 }193 194 Section &getCommonSection();195 void addSectionStartSymAndBlock(unsigned SecIndex, Section &GraphSec,196 orc::ExecutorAddr Address, const char *Data,197 orc::ExecutorAddrDiff Size,198 uint32_t Alignment, bool IsLive);199 200 Error createNormalizedSections();201 Error createNormalizedSymbols();202 203 /// Create graph blocks and symbols for externals, absolutes, commons and204 /// all defined symbols in sections without custom parsers.205 Error graphifyRegularSymbols();206 207 /// Create and return a graph symbol for the given normalized symbol.208 ///209 /// NSym's GraphSymbol member will be updated to point at the newly created210 /// symbol.211 Symbol &createStandardGraphSymbol(NormalizedSymbol &Sym, Block &B,212 size_t Size, bool IsText,213 bool IsNoDeadStrip, bool IsCanonical);214 215 /// Create graph blocks and symbols for all sections.216 Error graphifySectionsWithCustomParsers();217 218 /// Graphify cstring section.219 Error graphifyCStringSection(NormalizedSection &NSec,220 std::vector<NormalizedSymbol *> NSyms);221 222 // Put the BumpPtrAllocator first so that we don't free any of the underlying223 // memory until the Symbol/Addressable destructors have been run.224 BumpPtrAllocator Allocator;225 226 const object::MachOObjectFile &Obj;227 std::unique_ptr<LinkGraph> G;228 229 bool SubsectionsViaSymbols = false;230 DenseMap<unsigned, NormalizedSection> IndexToSection;231 Section *CommonSection = nullptr;232 233 DenseMap<uint32_t, NormalizedSymbol *> IndexToSymbol;234 StringMap<SectionParserFunction> CustomSectionParserFunctions;235};236 237} // end namespace jitlink238} // end namespace llvm239 240#endif // LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H241