xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/DefineExternalSectionStartAndEndSymbols.h (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
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     return SectionRanges.try_emplace(&Sec, 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(StartSymbolPrefix)) {
116     if (auto *Sec = G.findSectionByName(
117             (*SymName).drop_front(StartSymbolPrefix.size())))
118       return {*Sec, true};
119   } else if ((*SymName).starts_with(EndSymbolPrefix)) {
120     if (auto *Sec =
121             G.findSectionByName((*SymName).drop_front(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(StartSymbolPrefix)) {
135     auto [SegName, SecName] =
136         (*SymName).drop_front(StartSymbolPrefix.size()).split('$');
137     std::string SectionName = (SegName + "," + SecName).str();
138     if (auto *Sec = G.findSectionByName(SectionName))
139       return {*Sec, true};
140   } else if ((*SymName).starts_with(EndSymbolPrefix)) {
141     auto [SegName, SecName] =
142         (*SymName).drop_front(EndSymbolPrefix.size()).split('$');
143     std::string SectionName = (SegName + "," + SecName).str();
144     if (auto *Sec = G.findSectionByName(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