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