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 20 #include "EHFrameSupportImpl.h" 21 #include "JITLinkGeneric.h" 22 #include "llvm/Object/MachO.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); 85 86 LinkGraph &getGraph() const { return *G; } 87 88 const object::MachOObjectFile &getObject() const { return Obj; } 89 90 void addCustomSectionParser(StringRef SectionName, 91 SectionParserFunction Parse); 92 93 virtual Error addRelocations() = 0; 94 95 /// Create a symbol. 96 template <typename... ArgTs> 97 NormalizedSymbol &createNormalizedSymbol(ArgTs &&... Args) { 98 NormalizedSymbol *Sym = reinterpret_cast<NormalizedSymbol *>( 99 Allocator.Allocate<NormalizedSymbol>()); 100 new (Sym) NormalizedSymbol(std::forward<ArgTs>(Args)...); 101 return *Sym; 102 } 103 104 /// Index is zero-based (MachO section indexes are usually one-based) and 105 /// assumed to be in-range. Client is responsible for checking. 106 NormalizedSection &getSectionByIndex(unsigned Index) { 107 auto I = IndexToSection.find(Index); 108 assert(I != IndexToSection.end() && "No section recorded at index"); 109 return I->second; 110 } 111 112 /// Try to get the section at the given index. Will return an error if the 113 /// given index is out of range, or if no section has been added for the given 114 /// index. 115 Expected<NormalizedSection &> findSectionByIndex(unsigned Index) { 116 auto I = IndexToSection.find(Index); 117 if (I == IndexToSection.end()) 118 return make_error<JITLinkError>("No section recorded for index " + 119 formatv("{0:d}", Index)); 120 return I->second; 121 } 122 123 /// Try to get the symbol at the given index. Will return an error if the 124 /// given index is out of range, or if no symbol has been added for the given 125 /// index. 126 Expected<NormalizedSymbol &> findSymbolByIndex(uint64_t Index) { 127 if (Index >= IndexToSymbol.size()) 128 return make_error<JITLinkError>("Symbol index out of range"); 129 auto *Sym = IndexToSymbol[Index]; 130 if (!Sym) 131 return make_error<JITLinkError>("No symbol at index " + 132 formatv("{0:d}", Index)); 133 return *Sym; 134 } 135 136 /// Returns the symbol with the highest address not greater than the search 137 /// address, or null if no such symbol exists. 138 Symbol *getSymbolByAddress(JITTargetAddress Address) { 139 auto I = AddrToCanonicalSymbol.upper_bound(Address); 140 if (I == AddrToCanonicalSymbol.begin()) 141 return nullptr; 142 return std::prev(I)->second; 143 } 144 145 /// Returns the symbol with the highest address not greater than the search 146 /// address, or an error if no such symbol exists. 147 Expected<Symbol &> findSymbolByAddress(JITTargetAddress Address) { 148 auto *Sym = getSymbolByAddress(Address); 149 if (Sym) 150 if (Address < Sym->getAddress() + Sym->getSize()) 151 return *Sym; 152 return make_error<JITLinkError>("No symbol covering address " + 153 formatv("{0:x16}", Address)); 154 } 155 156 static Linkage getLinkage(uint16_t Desc); 157 static Scope getScope(StringRef Name, uint8_t Type); 158 static bool isAltEntry(const NormalizedSymbol &NSym); 159 160 static bool isDebugSection(const NormalizedSection &NSec); 161 162 MachO::relocation_info 163 getRelocationInfo(const object::relocation_iterator RelItr) { 164 MachO::any_relocation_info ARI = 165 getObject().getRelocation(RelItr->getRawDataRefImpl()); 166 MachO::relocation_info RI; 167 RI.r_address = ARI.r_word0; 168 RI.r_symbolnum = ARI.r_word1 & 0xffffff; 169 RI.r_pcrel = (ARI.r_word1 >> 24) & 1; 170 RI.r_length = (ARI.r_word1 >> 25) & 3; 171 RI.r_extern = (ARI.r_word1 >> 27) & 1; 172 RI.r_type = (ARI.r_word1 >> 28); 173 return RI; 174 } 175 176 private: 177 static unsigned getPointerSize(const object::MachOObjectFile &Obj); 178 static support::endianness getEndianness(const object::MachOObjectFile &Obj); 179 180 void setCanonicalSymbol(Symbol &Sym) { 181 auto *&CanonicalSymEntry = AddrToCanonicalSymbol[Sym.getAddress()]; 182 // There should be no symbol at this address, or, if there is, 183 // it should be a zero-sized symbol from an empty section (which 184 // we can safely override). 185 assert((!CanonicalSymEntry || CanonicalSymEntry->getSize() == 0) && 186 "Duplicate canonical symbol at address"); 187 CanonicalSymEntry = &Sym; 188 } 189 190 Section &getCommonSection(); 191 void addSectionStartSymAndBlock(Section &GraphSec, uint64_t Address, 192 const char *Data, uint64_t Size, 193 uint32_t Alignment, bool IsLive); 194 195 Error createNormalizedSections(); 196 Error createNormalizedSymbols(); 197 198 /// Create graph blocks and symbols for externals, absolutes, commons and 199 /// all defined symbols in sections without custom parsers. 200 Error graphifyRegularSymbols(); 201 202 /// Create graph blocks and symbols for all sections. 203 Error graphifySectionsWithCustomParsers(); 204 205 // Put the BumpPtrAllocator first so that we don't free any of the underlying 206 // memory until the Symbol/Addressable destructors have been run. 207 BumpPtrAllocator Allocator; 208 209 const object::MachOObjectFile &Obj; 210 std::unique_ptr<LinkGraph> G; 211 212 DenseMap<unsigned, NormalizedSection> IndexToSection; 213 Section *CommonSection = nullptr; 214 215 DenseMap<uint32_t, NormalizedSymbol *> IndexToSymbol; 216 std::map<JITTargetAddress, Symbol *> AddrToCanonicalSymbol; 217 StringMap<SectionParserFunction> CustomSectionParserFunctions; 218 }; 219 220 } // end namespace jitlink 221 } // end namespace llvm 222 223 #endif // LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H 224