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 class MachOEHFrameBinaryParser : public EHFrameBinaryParser { 34 public: 35 MachOEHFrameBinaryParser(MachOLinkGraphBuilder &Builder, 36 JITTargetAddress EHFrameAddress, 37 StringRef EHFrameContent, Section &EHFrameSection, 38 uint64_t CIEAlignment, uint64_t FDEAlignment, 39 Edge::Kind FDEToCIERelocKind, 40 Edge::Kind FDEToTargetRelocKind) 41 : EHFrameBinaryParser(EHFrameAddress, EHFrameContent, 42 Builder.getGraph().getPointerSize(), 43 Builder.getGraph().getEndianness()), 44 Builder(Builder), EHFrameSection(EHFrameSection), 45 CIEAlignment(CIEAlignment), FDEAlignment(FDEAlignment), 46 FDEToCIERelocKind(FDEToCIERelocKind), 47 FDEToTargetRelocKind(FDEToTargetRelocKind) {} 48 49 Symbol *getSymbolAtAddress(JITTargetAddress Address) override { 50 if (auto *Sym = Builder.getSymbolByAddress(Address)) 51 if (Sym->getAddress() == Address) 52 return Sym; 53 return nullptr; 54 } 55 56 Symbol &createCIERecord(JITTargetAddress RecordAddr, 57 StringRef RecordContent) override { 58 auto &G = Builder.getGraph(); 59 auto &B = G.createContentBlock(EHFrameSection, RecordContent, RecordAddr, 60 CIEAlignment, 0); 61 auto &CIESymbol = 62 G.addAnonymousSymbol(B, 0, RecordContent.size(), false, false); 63 Builder.setCanonicalSymbol(CIESymbol); 64 return CIESymbol; 65 } 66 67 Expected<Symbol &> createFDERecord(JITTargetAddress RecordAddr, 68 StringRef RecordContent, Symbol &CIE, 69 size_t CIEOffset, Symbol &Func, 70 size_t FuncOffset, Symbol *LSDA, 71 size_t LSDAOffset) override { 72 auto &G = Builder.getGraph(); 73 auto &B = G.createContentBlock(EHFrameSection, RecordContent, RecordAddr, 74 FDEAlignment, 0); 75 76 // Add edges to CIE, Func, and (conditionally) LSDA. 77 B.addEdge(FDEToCIERelocKind, CIEOffset, CIE, 0); 78 B.addEdge(FDEToTargetRelocKind, FuncOffset, Func, 0); 79 80 if (LSDA) 81 B.addEdge(FDEToTargetRelocKind, LSDAOffset, *LSDA, 0); 82 83 auto &FDESymbol = 84 G.addAnonymousSymbol(B, 0, RecordContent.size(), false, false); 85 86 // Add a keep-alive relocation from the function to the FDE to ensure it 87 // is not dead stripped. 88 Func.getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0); 89 90 return FDESymbol; 91 } 92 93 private: 94 MachOLinkGraphBuilder &Builder; 95 Section &EHFrameSection; 96 uint64_t CIEAlignment; 97 uint64_t FDEAlignment; 98 Edge::Kind FDEToCIERelocKind; 99 Edge::Kind FDEToTargetRelocKind; 100 }; 101 102 struct NormalizedSymbol { 103 friend class MachOLinkGraphBuilder; 104 105 private: 106 NormalizedSymbol(Optional<StringRef> Name, uint64_t Value, uint8_t Type, 107 uint8_t Sect, uint16_t Desc, Linkage L, Scope S) 108 : Name(Name), Value(Value), Type(Type), Sect(Sect), Desc(Desc), L(L), 109 S(S) { 110 assert((!Name || !Name->empty()) && "Name must be none or non-empty"); 111 } 112 113 public: 114 NormalizedSymbol(const NormalizedSymbol &) = delete; 115 NormalizedSymbol &operator=(const NormalizedSymbol &) = delete; 116 NormalizedSymbol(NormalizedSymbol &&) = delete; 117 NormalizedSymbol &operator=(NormalizedSymbol &&) = delete; 118 119 Optional<StringRef> Name; 120 uint64_t Value = 0; 121 uint8_t Type = 0; 122 uint8_t Sect = 0; 123 uint16_t Desc = 0; 124 Linkage L = Linkage::Strong; 125 Scope S = Scope::Default; 126 Symbol *GraphSymbol = nullptr; 127 }; 128 129 class NormalizedSection { 130 friend class MachOLinkGraphBuilder; 131 132 private: 133 NormalizedSection() = default; 134 135 public: 136 Section *GraphSection = nullptr; 137 uint64_t Address = 0; 138 uint64_t Size = 0; 139 uint64_t Alignment = 0; 140 uint32_t Flags = 0; 141 const char *Data = nullptr; 142 }; 143 144 using SectionParserFunction = std::function<Error(NormalizedSection &S)>; 145 146 MachOLinkGraphBuilder(const object::MachOObjectFile &Obj); 147 148 LinkGraph &getGraph() const { return *G; } 149 150 const object::MachOObjectFile &getObject() const { return Obj; } 151 152 void addCustomSectionParser(StringRef SectionName, 153 SectionParserFunction Parse); 154 155 virtual Error addRelocations() = 0; 156 157 /// Create a symbol. 158 template <typename... ArgTs> 159 NormalizedSymbol &createNormalizedSymbol(ArgTs &&... Args) { 160 NormalizedSymbol *Sym = reinterpret_cast<NormalizedSymbol *>( 161 Allocator.Allocate<NormalizedSymbol>()); 162 new (Sym) NormalizedSymbol(std::forward<ArgTs>(Args)...); 163 return *Sym; 164 } 165 166 /// Index is zero-based (MachO section indexes are usually one-based) and 167 /// assumed to be in-range. Client is responsible for checking. 168 NormalizedSection &getSectionByIndex(unsigned Index) { 169 auto I = IndexToSection.find(Index); 170 assert(I != IndexToSection.end() && "No section recorded at index"); 171 return I->second; 172 } 173 174 /// Try to get the section at the given index. Will return an error if the 175 /// given index is out of range, or if no section has been added for the given 176 /// index. 177 Expected<NormalizedSection &> findSectionByIndex(unsigned Index) { 178 auto I = IndexToSection.find(Index); 179 if (I == IndexToSection.end()) 180 return make_error<JITLinkError>("No section recorded for index " + 181 formatv("{0:u}", Index)); 182 return I->second; 183 } 184 185 /// Try to get the symbol at the given index. Will return an error if the 186 /// given index is out of range, or if no symbol has been added for the given 187 /// index. 188 Expected<NormalizedSymbol &> findSymbolByIndex(uint64_t Index) { 189 if (Index >= IndexToSymbol.size()) 190 return make_error<JITLinkError>("Symbol index out of range"); 191 auto *Sym = IndexToSymbol[Index]; 192 if (!Sym) 193 return make_error<JITLinkError>("No symbol at index " + 194 formatv("{0:u}", Index)); 195 return *Sym; 196 } 197 198 /// Returns the symbol with the highest address not greater than the search 199 /// address, or null if no such symbol exists. 200 Symbol *getSymbolByAddress(JITTargetAddress Address) { 201 auto I = AddrToCanonicalSymbol.upper_bound(Address); 202 if (I == AddrToCanonicalSymbol.begin()) 203 return nullptr; 204 return std::prev(I)->second; 205 } 206 207 /// Returns the symbol with the highest address not greater than the search 208 /// address, or an error if no such symbol exists. 209 Expected<Symbol &> findSymbolByAddress(JITTargetAddress Address) { 210 auto *Sym = getSymbolByAddress(Address); 211 if (Sym) 212 if (Address < Sym->getAddress() + Sym->getSize()) 213 return *Sym; 214 return make_error<JITLinkError>("No symbol covering address " + 215 formatv("{0:x16}", Address)); 216 } 217 218 static Linkage getLinkage(uint16_t Desc); 219 static Scope getScope(StringRef Name, uint8_t Type); 220 static bool isAltEntry(const NormalizedSymbol &NSym); 221 222 private: 223 static unsigned getPointerSize(const object::MachOObjectFile &Obj); 224 static support::endianness getEndianness(const object::MachOObjectFile &Obj); 225 226 void setCanonicalSymbol(Symbol &Sym) { 227 auto *&CanonicalSymEntry = AddrToCanonicalSymbol[Sym.getAddress()]; 228 // There should be no symbol at this address, or, if there is, 229 // it should be a zero-sized symbol from an empty section (which 230 // we can safely override). 231 assert((!CanonicalSymEntry || CanonicalSymEntry->getSize() == 0) && 232 "Duplicate canonical symbol at address"); 233 CanonicalSymEntry = &Sym; 234 } 235 236 Section &getCommonSection(); 237 void addSectionStartSymAndBlock(Section &GraphSec, uint64_t Address, 238 const char *Data, uint64_t Size, 239 uint32_t Alignment, bool IsLive); 240 241 Error createNormalizedSections(); 242 Error createNormalizedSymbols(); 243 244 /// Create graph blocks and symbols for externals, absolutes, commons and 245 /// all defined symbols in sections without custom parsers. 246 Error graphifyRegularSymbols(); 247 248 /// Create graph blocks and symbols for all sections. 249 Error graphifySectionsWithCustomParsers(); 250 251 // Put the BumpPtrAllocator first so that we don't free any of the underlying 252 // memory until the Symbol/Addressable destructors have been run. 253 BumpPtrAllocator Allocator; 254 255 const object::MachOObjectFile &Obj; 256 std::unique_ptr<LinkGraph> G; 257 258 DenseMap<unsigned, NormalizedSection> IndexToSection; 259 Section *CommonSection = nullptr; 260 261 DenseMap<uint32_t, NormalizedSymbol *> IndexToSymbol; 262 std::map<JITTargetAddress, Symbol *> AddrToCanonicalSymbol; 263 StringMap<SectionParserFunction> CustomSectionParserFunctions; 264 }; 265 266 } // end namespace jitlink 267 } // end namespace llvm 268 269 #endif // LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H 270