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 | auto I = SectionRanges.find(Val: &Sec); |
75 | if (I == SectionRanges.end()) |
76 | I = SectionRanges.insert(KV: std::make_pair(x: &Sec, y: 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(Prefix: StartSymbolPrefix)) { |
119 | if (auto *Sec = |
120 | G.findSectionByName(Name: SymName.drop_front(N: StartSymbolPrefix.size()))) |
121 | return {*Sec, true}; |
122 | } else if (SymName.starts_with(Prefix: EndSymbolPrefix)) { |
123 | if (auto *Sec = |
124 | G.findSectionByName(Name: SymName.drop_front(N: 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(Prefix: StartSymbolPrefix)) { |
138 | auto [SegName, SecName] = |
139 | SymName.drop_front(N: StartSymbolPrefix.size()).split(Separator: '$'); |
140 | std::string SectionName = (SegName + "," + SecName).str(); |
141 | if (auto *Sec = G.findSectionByName(Name: SectionName)) |
142 | return {*Sec, true}; |
143 | } else if (SymName.starts_with(Prefix: EndSymbolPrefix)) { |
144 | auto [SegName, SecName] = |
145 | SymName.drop_front(N: EndSymbolPrefix.size()).split(Separator: '$'); |
146 | std::string SectionName = (SegName + "," + SecName).str(); |
147 | if (auto *Sec = G.findSectionByName(Name: 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 | |