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