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/ExecutionEngine/JITLink/JITLink.h" 17 18 #include "EHFrameSupportImpl.h" 19 #include "JITLinkGeneric.h" 20 #include "llvm/Object/MachO.h" 21 22 #include <list> 23 24 namespace llvm { 25 namespace jitlink { 26 27 class MachOLinkGraphBuilder { 28 public: 29 virtual ~MachOLinkGraphBuilder(); 30 Expected<std::unique_ptr<LinkGraph>> buildGraph(); 31 32 protected: 33 34 struct NormalizedSymbol { 35 friend class MachOLinkGraphBuilder; 36 37 private: 38 NormalizedSymbol(Optional<StringRef> Name, uint64_t Value, uint8_t Type, 39 uint8_t Sect, uint16_t Desc, Linkage L, Scope S) 40 : Name(Name), Value(Value), Type(Type), Sect(Sect), Desc(Desc), L(L), 41 S(S) { 42 assert((!Name || !Name->empty()) && "Name must be none or non-empty"); 43 } 44 45 public: 46 NormalizedSymbol(const NormalizedSymbol &) = delete; 47 NormalizedSymbol &operator=(const NormalizedSymbol &) = delete; 48 NormalizedSymbol(NormalizedSymbol &&) = delete; 49 NormalizedSymbol &operator=(NormalizedSymbol &&) = delete; 50 51 Optional<StringRef> Name; 52 uint64_t Value = 0; 53 uint8_t Type = 0; 54 uint8_t Sect = 0; 55 uint16_t Desc = 0; 56 Linkage L = Linkage::Strong; 57 Scope S = Scope::Default; 58 Symbol *GraphSymbol = nullptr; 59 }; 60 61 class NormalizedSection { 62 friend class MachOLinkGraphBuilder; 63 64 private: 65 NormalizedSection() = default; 66 67 public: 68 Section *GraphSection = nullptr; 69 uint64_t Address = 0; 70 uint64_t Size = 0; 71 uint64_t Alignment = 0; 72 uint32_t Flags = 0; 73 const char *Data = nullptr; 74 }; 75 76 using SectionParserFunction = std::function<Error(NormalizedSection &S)>; 77 78 MachOLinkGraphBuilder(const object::MachOObjectFile &Obj); 79 80 LinkGraph &getGraph() const { return *G; } 81 82 const object::MachOObjectFile &getObject() const { return Obj; } 83 84 void addCustomSectionParser(StringRef SectionName, 85 SectionParserFunction Parse); 86 87 virtual Error addRelocations() = 0; 88 89 /// Create a symbol. 90 template <typename... ArgTs> 91 NormalizedSymbol &createNormalizedSymbol(ArgTs &&... Args) { 92 NormalizedSymbol *Sym = reinterpret_cast<NormalizedSymbol *>( 93 Allocator.Allocate<NormalizedSymbol>()); 94 new (Sym) NormalizedSymbol(std::forward<ArgTs>(Args)...); 95 return *Sym; 96 } 97 98 /// Index is zero-based (MachO section indexes are usually one-based) and 99 /// assumed to be in-range. Client is responsible for checking. 100 NormalizedSection &getSectionByIndex(unsigned Index) { 101 auto I = IndexToSection.find(Index); 102 assert(I != IndexToSection.end() && "No section recorded at index"); 103 return I->second; 104 } 105 106 /// Try to get the section at the given index. Will return an error if the 107 /// given index is out of range, or if no section has been added for the given 108 /// index. 109 Expected<NormalizedSection &> findSectionByIndex(unsigned Index) { 110 auto I = IndexToSection.find(Index); 111 if (I == IndexToSection.end()) 112 return make_error<JITLinkError>("No section recorded for index " + 113 formatv("{0:u}", Index)); 114 return I->second; 115 } 116 117 /// Try to get the symbol at the given index. Will return an error if the 118 /// given index is out of range, or if no symbol has been added for the given 119 /// index. 120 Expected<NormalizedSymbol &> findSymbolByIndex(uint64_t Index) { 121 if (Index >= IndexToSymbol.size()) 122 return make_error<JITLinkError>("Symbol index out of range"); 123 auto *Sym = IndexToSymbol[Index]; 124 if (!Sym) 125 return make_error<JITLinkError>("No symbol at index " + 126 formatv("{0:u}", Index)); 127 return *Sym; 128 } 129 130 /// Returns the symbol with the highest address not greater than the search 131 /// address, or null if no such symbol exists. 132 Symbol *getSymbolByAddress(JITTargetAddress Address) { 133 auto I = AddrToCanonicalSymbol.upper_bound(Address); 134 if (I == AddrToCanonicalSymbol.begin()) 135 return nullptr; 136 return std::prev(I)->second; 137 } 138 139 /// Returns the symbol with the highest address not greater than the search 140 /// address, or an error if no such symbol exists. 141 Expected<Symbol &> findSymbolByAddress(JITTargetAddress Address) { 142 auto *Sym = getSymbolByAddress(Address); 143 if (Sym) 144 if (Address < Sym->getAddress() + Sym->getSize()) 145 return *Sym; 146 return make_error<JITLinkError>("No symbol covering address " + 147 formatv("{0:x16}", Address)); 148 } 149 150 static Linkage getLinkage(uint16_t Desc); 151 static Scope getScope(StringRef Name, uint8_t Type); 152 static bool isAltEntry(const NormalizedSymbol &NSym); 153 154 private: 155 static unsigned getPointerSize(const object::MachOObjectFile &Obj); 156 static support::endianness getEndianness(const object::MachOObjectFile &Obj); 157 158 void setCanonicalSymbol(Symbol &Sym) { 159 auto *&CanonicalSymEntry = AddrToCanonicalSymbol[Sym.getAddress()]; 160 // There should be no symbol at this address, or, if there is, 161 // it should be a zero-sized symbol from an empty section (which 162 // we can safely override). 163 assert((!CanonicalSymEntry || CanonicalSymEntry->getSize() == 0) && 164 "Duplicate canonical symbol at address"); 165 CanonicalSymEntry = &Sym; 166 } 167 168 Section &getCommonSection(); 169 void addSectionStartSymAndBlock(Section &GraphSec, uint64_t Address, 170 const char *Data, uint64_t Size, 171 uint32_t Alignment, bool IsLive); 172 173 Error createNormalizedSections(); 174 Error createNormalizedSymbols(); 175 176 /// Create graph blocks and symbols for externals, absolutes, commons and 177 /// all defined symbols in sections without custom parsers. 178 Error graphifyRegularSymbols(); 179 180 /// Create graph blocks and symbols for all sections. 181 Error graphifySectionsWithCustomParsers(); 182 183 // Put the BumpPtrAllocator first so that we don't free any of the underlying 184 // memory until the Symbol/Addressable destructors have been run. 185 BumpPtrAllocator Allocator; 186 187 const object::MachOObjectFile &Obj; 188 std::unique_ptr<LinkGraph> G; 189 190 DenseMap<unsigned, NormalizedSection> IndexToSection; 191 Section *CommonSection = nullptr; 192 193 DenseMap<uint32_t, NormalizedSymbol *> IndexToSymbol; 194 std::map<JITTargetAddress, Symbol *> AddrToCanonicalSymbol; 195 StringMap<SectionParserFunction> CustomSectionParserFunctions; 196 }; 197 198 } // end namespace jitlink 199 } // end namespace llvm 200 201 #endif // LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H 202