1 //===--------- DefineExternalSectionStartAndEndSymbols.h --------*- 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 // Utility class for recognizing external section start and end symbols and 10 // transforming them into defined symbols for the start and end blocks of the 11 // associated Section. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H 16 #define LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H 17 18 #include "llvm/ExecutionEngine/JITLink/JITLink.h" 19 #include "llvm/Support/Debug.h" 20 21 #define DEBUG_TYPE "jitlink" 22 23 namespace llvm { 24 namespace jitlink { 25 26 struct SectionRangeSymbolDesc { 27 SectionRangeSymbolDesc() = default; 28 SectionRangeSymbolDesc(Section &Sec, bool IsStart) 29 : Sec(&Sec), IsStart(IsStart) {} 30 Section *Sec = nullptr; 31 bool IsStart = false; 32 }; 33 34 /// Pass implementation for the createDefineExternalSectionStartAndEndSymbols 35 /// function. 36 template <typename SymbolIdentifierFunction> 37 class DefineExternalSectionStartAndEndSymbols { 38 public: 39 DefineExternalSectionStartAndEndSymbols(SymbolIdentifierFunction F) 40 : F(std::move(F)) {} 41 42 Error operator()(LinkGraph &G) { 43 44 // This pass will affect the external symbols set, so copy them out into a 45 // vector and iterate over that. 46 std::vector<Symbol *> Externals(G.external_symbols().begin(), 47 G.external_symbols().end()); 48 49 for (auto *Sym : Externals) { 50 SectionRangeSymbolDesc D = F(G, *Sym); 51 if (D.Sec) { 52 auto &SR = getSectionRange(*D.Sec); 53 if (D.IsStart) { 54 if (SR.empty()) 55 G.makeAbsolute(*Sym, orc::ExecutorAddr()); 56 else 57 G.makeDefined(*Sym, *SR.getFirstBlock(), 0, 0, Linkage::Strong, 58 Scope::Local, false); 59 } else { 60 if (SR.empty()) 61 G.makeAbsolute(*Sym, orc::ExecutorAddr()); 62 else 63 G.makeDefined(*Sym, *SR.getLastBlock(), 64 SR.getLastBlock()->getSize(), 0, Linkage::Strong, 65 Scope::Local, false); 66 } 67 } 68 } 69 return Error::success(); 70 } 71 72 private: 73 SectionRange &getSectionRange(Section &Sec) { 74 auto I = SectionRanges.find(&Sec); 75 if (I == SectionRanges.end()) 76 I = SectionRanges.insert(std::make_pair(&Sec, SectionRange(Sec))).first; 77 return I->second; 78 } 79 80 DenseMap<Section *, SectionRange> SectionRanges; 81 SymbolIdentifierFunction F; 82 }; 83 84 /// Returns a JITLink pass (as a function class) that uses the given symbol 85 /// identification function to identify external section start and end symbols 86 /// (and their associated Section*s) and transform the identified externals 87 /// into defined symbols pointing to the start of the first block in the 88 /// section and the end of the last (start and end symbols for empty sections 89 /// will be transformed into absolute symbols at address 0). 90 /// 91 /// The identification function should be callable as 92 /// 93 /// SectionRangeSymbolDesc (LinkGraph &G, Symbol &Sym) 94 /// 95 /// If Sym is not a section range start or end symbol then a default 96 /// constructed SectionRangeSymbolDesc should be returned. If Sym is a start 97 /// symbol then SectionRangeSymbolDesc(Sec, true), where Sec is a reference to 98 /// the target Section. If Sym is an end symbol then 99 /// SectionRangeSymbolDesc(Sec, false) should be returned. 100 /// 101 /// This pass should be run in the PostAllocationPass pipeline, at which point 102 /// all blocks should have been assigned their final addresses. 103 template <typename SymbolIdentifierFunction> 104 DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction> 105 createDefineExternalSectionStartAndEndSymbolsPass( 106 SymbolIdentifierFunction &&F) { 107 return DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction>( 108 std::forward<SymbolIdentifierFunction>(F)); 109 } 110 111 /// ELF section start/end symbol detection. 112 inline SectionRangeSymbolDesc 113 identifyELFSectionStartAndEndSymbols(LinkGraph &G, Symbol &Sym) { 114 constexpr StringRef StartSymbolPrefix = "__start_"; 115 constexpr StringRef EndSymbolPrefix = "__stop_"; 116 117 auto SymName = Sym.getName(); 118 if (SymName.starts_with(StartSymbolPrefix)) { 119 if (auto *Sec = 120 G.findSectionByName(SymName.drop_front(StartSymbolPrefix.size()))) 121 return {*Sec, true}; 122 } else if (SymName.starts_with(EndSymbolPrefix)) { 123 if (auto *Sec = 124 G.findSectionByName(SymName.drop_front(EndSymbolPrefix.size()))) 125 return {*Sec, false}; 126 } 127 return {}; 128 } 129 130 /// MachO section start/end symbol detection. 131 inline SectionRangeSymbolDesc 132 identifyMachOSectionStartAndEndSymbols(LinkGraph &G, Symbol &Sym) { 133 constexpr StringRef StartSymbolPrefix = "section$start$"; 134 constexpr StringRef EndSymbolPrefix = "section$end$"; 135 136 auto SymName = Sym.getName(); 137 if (SymName.starts_with(StartSymbolPrefix)) { 138 auto [SegName, SecName] = 139 SymName.drop_front(StartSymbolPrefix.size()).split('$'); 140 std::string SectionName = (SegName + "," + SecName).str(); 141 if (auto *Sec = G.findSectionByName(SectionName)) 142 return {*Sec, true}; 143 } else if (SymName.starts_with(EndSymbolPrefix)) { 144 auto [SegName, SecName] = 145 SymName.drop_front(EndSymbolPrefix.size()).split('$'); 146 std::string SectionName = (SegName + "," + SecName).str(); 147 if (auto *Sec = G.findSectionByName(SectionName)) 148 return {*Sec, false}; 149 } 150 return {}; 151 } 152 153 } // end namespace jitlink 154 } // end namespace llvm 155 156 #undef DEBUG_TYPE 157 158 #endif // LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H 159