| 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(Sec&: *D.Sec); |
| 53 | if (D.IsStart) { |
| 54 | if (SR.empty()) |
| 55 | G.makeAbsolute(Sym&: *Sym, Address: orc::ExecutorAddr()); |
| 56 | else |
| 57 | G.makeDefined(Sym&: *Sym, Content&: *SR.getFirstBlock(), Offset: 0, Size: 0, L: Linkage::Strong, |
| 58 | S: Scope::Local, IsLive: false); |
| 59 | } else { |
| 60 | if (SR.empty()) |
| 61 | G.makeAbsolute(Sym&: *Sym, Address: orc::ExecutorAddr()); |
| 62 | else |
| 63 | G.makeDefined(Sym&: *Sym, Content&: *SR.getLastBlock(), |
| 64 | Offset: SR.getLastBlock()->getSize(), Size: 0, L: Linkage::Strong, |
| 65 | S: Scope::Local, IsLive: false); |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 | return Error::success(); |
| 70 | } |
| 71 | |
| 72 | private: |
| 73 | SectionRange &getSectionRange(Section &Sec) { |
| 74 | return SectionRanges.try_emplace(Key: &Sec, Args&: Sec).first->second; |
| 75 | } |
| 76 | |
| 77 | DenseMap<Section *, SectionRange> SectionRanges; |
| 78 | SymbolIdentifierFunction F; |
| 79 | }; |
| 80 | |
| 81 | /// Returns a JITLink pass (as a function class) that uses the given symbol |
| 82 | /// identification function to identify external section start and end symbols |
| 83 | /// (and their associated Section*s) and transform the identified externals |
| 84 | /// into defined symbols pointing to the start of the first block in the |
| 85 | /// section and the end of the last (start and end symbols for empty sections |
| 86 | /// will be transformed into absolute symbols at address 0). |
| 87 | /// |
| 88 | /// The identification function should be callable as |
| 89 | /// |
| 90 | /// SectionRangeSymbolDesc (LinkGraph &G, Symbol &Sym) |
| 91 | /// |
| 92 | /// If Sym is not a section range start or end symbol then a default |
| 93 | /// constructed SectionRangeSymbolDesc should be returned. If Sym is a start |
| 94 | /// symbol then SectionRangeSymbolDesc(Sec, true), where Sec is a reference to |
| 95 | /// the target Section. If Sym is an end symbol then |
| 96 | /// SectionRangeSymbolDesc(Sec, false) should be returned. |
| 97 | /// |
| 98 | /// This pass should be run in the PostAllocationPass pipeline, at which point |
| 99 | /// all blocks should have been assigned their final addresses. |
| 100 | template <typename SymbolIdentifierFunction> |
| 101 | DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction> |
| 102 | createDefineExternalSectionStartAndEndSymbolsPass( |
| 103 | SymbolIdentifierFunction &&F) { |
| 104 | return DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction>( |
| 105 | std::forward<SymbolIdentifierFunction>(F)); |
| 106 | } |
| 107 | |
| 108 | /// ELF section start/end symbol detection. |
| 109 | inline SectionRangeSymbolDesc |
| 110 | identifyELFSectionStartAndEndSymbols(LinkGraph &G, Symbol &Sym) { |
| 111 | constexpr StringRef StartSymbolPrefix = "__start_" ; |
| 112 | constexpr StringRef EndSymbolPrefix = "__stop_" ; |
| 113 | |
| 114 | auto SymName = Sym.getName(); |
| 115 | if ((*SymName).starts_with(Prefix: StartSymbolPrefix)) { |
| 116 | if (auto *Sec = G.findSectionByName( |
| 117 | Name: (*SymName).drop_front(N: StartSymbolPrefix.size()))) |
| 118 | return {*Sec, true}; |
| 119 | } else if ((*SymName).starts_with(Prefix: EndSymbolPrefix)) { |
| 120 | if (auto *Sec = |
| 121 | G.findSectionByName(Name: (*SymName).drop_front(N: EndSymbolPrefix.size()))) |
| 122 | return {*Sec, false}; |
| 123 | } |
| 124 | return {}; |
| 125 | } |
| 126 | |
| 127 | /// MachO section start/end symbol detection. |
| 128 | inline SectionRangeSymbolDesc |
| 129 | identifyMachOSectionStartAndEndSymbols(LinkGraph &G, Symbol &Sym) { |
| 130 | constexpr StringRef StartSymbolPrefix = "section$start$" ; |
| 131 | constexpr StringRef EndSymbolPrefix = "section$end$" ; |
| 132 | |
| 133 | auto SymName = Sym.getName(); |
| 134 | if ((*SymName).starts_with(Prefix: StartSymbolPrefix)) { |
| 135 | auto [SegName, SecName] = |
| 136 | (*SymName).drop_front(N: StartSymbolPrefix.size()).split(Separator: '$'); |
| 137 | std::string SectionName = (SegName + "," + SecName).str(); |
| 138 | if (auto *Sec = G.findSectionByName(Name: SectionName)) |
| 139 | return {*Sec, true}; |
| 140 | } else if ((*SymName).starts_with(Prefix: EndSymbolPrefix)) { |
| 141 | auto [SegName, SecName] = |
| 142 | (*SymName).drop_front(N: EndSymbolPrefix.size()).split(Separator: '$'); |
| 143 | std::string SectionName = (SegName + "," + SecName).str(); |
| 144 | if (auto *Sec = G.findSectionByName(Name: SectionName)) |
| 145 | return {*Sec, false}; |
| 146 | } |
| 147 | return {}; |
| 148 | } |
| 149 | |
| 150 | } // end namespace jitlink |
| 151 | } // end namespace llvm |
| 152 | |
| 153 | #undef DEBUG_TYPE |
| 154 | |
| 155 | #endif // LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H |
| 156 | |