xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/DefineExternalSectionStartAndEndSymbols.h (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
10a74ec32SLang Hames //===--------- DefineExternalSectionStartAndEndSymbols.h --------*- C++ -*-===//
20a74ec32SLang Hames //
30a74ec32SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40a74ec32SLang Hames // See https://llvm.org/LICENSE.txt for license information.
50a74ec32SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60a74ec32SLang Hames //
70a74ec32SLang Hames //===----------------------------------------------------------------------===//
80a74ec32SLang Hames //
90a74ec32SLang Hames // Utility class for recognizing external section start and end symbols and
100a74ec32SLang Hames // transforming them into defined symbols for the start and end blocks of the
110a74ec32SLang Hames // associated Section.
120a74ec32SLang Hames //
130a74ec32SLang Hames //===----------------------------------------------------------------------===//
140a74ec32SLang Hames 
150a74ec32SLang Hames #ifndef LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H
160a74ec32SLang Hames #define LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H
170a74ec32SLang Hames 
180a74ec32SLang Hames #include "llvm/ExecutionEngine/JITLink/JITLink.h"
190a74ec32SLang Hames #include "llvm/Support/Debug.h"
200a74ec32SLang Hames 
210a74ec32SLang Hames #define DEBUG_TYPE "jitlink"
220a74ec32SLang Hames 
230a74ec32SLang Hames namespace llvm {
240a74ec32SLang Hames namespace jitlink {
250a74ec32SLang Hames 
260a74ec32SLang Hames struct SectionRangeSymbolDesc {
270a74ec32SLang Hames   SectionRangeSymbolDesc() = default;
280a74ec32SLang Hames   SectionRangeSymbolDesc(Section &Sec, bool IsStart)
290a74ec32SLang Hames       : Sec(&Sec), IsStart(IsStart) {}
300a74ec32SLang Hames   Section *Sec = nullptr;
310a74ec32SLang Hames   bool IsStart = false;
320a74ec32SLang Hames };
330a74ec32SLang Hames 
340a74ec32SLang Hames /// Pass implementation for the createDefineExternalSectionStartAndEndSymbols
350a74ec32SLang Hames /// function.
360a74ec32SLang Hames template <typename SymbolIdentifierFunction>
370a74ec32SLang Hames class DefineExternalSectionStartAndEndSymbols {
380a74ec32SLang Hames public:
390a74ec32SLang Hames   DefineExternalSectionStartAndEndSymbols(SymbolIdentifierFunction F)
400a74ec32SLang Hames       : F(std::move(F)) {}
410a74ec32SLang Hames 
420a74ec32SLang Hames   Error operator()(LinkGraph &G) {
43fc36a511SLang Hames 
44fc36a511SLang Hames     // This pass will affect the external symbols set, so copy them out into a
45fc36a511SLang Hames     // vector and iterate over that.
46fc36a511SLang Hames     std::vector<Symbol *> Externals(G.external_symbols().begin(),
47fc36a511SLang Hames                                     G.external_symbols().end());
48fc36a511SLang Hames 
49fc36a511SLang Hames     for (auto *Sym : Externals) {
500a74ec32SLang Hames       SectionRangeSymbolDesc D = F(G, *Sym);
510a74ec32SLang Hames       if (D.Sec) {
520a74ec32SLang Hames         auto &SR = getSectionRange(*D.Sec);
530a74ec32SLang Hames         if (D.IsStart) {
54fc36a511SLang Hames           if (SR.empty())
55118e953bSLang Hames             G.makeAbsolute(*Sym, orc::ExecutorAddr());
560a74ec32SLang Hames           else
570a74ec32SLang Hames             G.makeDefined(*Sym, *SR.getFirstBlock(), 0, 0, Linkage::Strong,
580a74ec32SLang Hames                           Scope::Local, false);
590a74ec32SLang Hames         } else {
60fc36a511SLang Hames           if (SR.empty())
61118e953bSLang Hames             G.makeAbsolute(*Sym, orc::ExecutorAddr());
620a74ec32SLang Hames           else
630a74ec32SLang Hames             G.makeDefined(*Sym, *SR.getLastBlock(),
640a74ec32SLang Hames                           SR.getLastBlock()->getSize(), 0, Linkage::Strong,
650a74ec32SLang Hames                           Scope::Local, false);
660a74ec32SLang Hames         }
670a74ec32SLang Hames       }
680a74ec32SLang Hames     }
690a74ec32SLang Hames     return Error::success();
700a74ec32SLang Hames   }
710a74ec32SLang Hames 
720a74ec32SLang Hames private:
730a74ec32SLang Hames   SectionRange &getSectionRange(Section &Sec) {
74c219ebd9SKazu Hirata     return SectionRanges.try_emplace(&Sec, Sec).first->second;
750a74ec32SLang Hames   }
760a74ec32SLang Hames 
770a74ec32SLang Hames   DenseMap<Section *, SectionRange> SectionRanges;
780a74ec32SLang Hames   SymbolIdentifierFunction F;
790a74ec32SLang Hames };
800a74ec32SLang Hames 
810a74ec32SLang Hames /// Returns a JITLink pass (as a function class) that uses the given symbol
820a74ec32SLang Hames /// identification function to identify external section start and end symbols
830a74ec32SLang Hames /// (and their associated Section*s) and transform the identified externals
840a74ec32SLang Hames /// into defined symbols pointing to the start of the first block in the
850a74ec32SLang Hames /// section and the end of the last (start and end symbols for empty sections
860a74ec32SLang Hames /// will be transformed into absolute symbols at address 0).
870a74ec32SLang Hames ///
880a74ec32SLang Hames /// The identification function should be callable as
890a74ec32SLang Hames ///
900a74ec32SLang Hames ///   SectionRangeSymbolDesc (LinkGraph &G, Symbol &Sym)
910a74ec32SLang Hames ///
920a74ec32SLang Hames /// If Sym is not a section range start or end symbol then a default
930a74ec32SLang Hames /// constructed SectionRangeSymbolDesc should be returned. If Sym is a start
940a74ec32SLang Hames /// symbol then SectionRangeSymbolDesc(Sec, true), where Sec is a reference to
950a74ec32SLang Hames /// the target Section. If Sym is an end symbol then
960a74ec32SLang Hames /// SectionRangeSymbolDesc(Sec, false) should be returned.
970a74ec32SLang Hames ///
980a74ec32SLang Hames /// This pass should be run in the PostAllocationPass pipeline, at which point
990a74ec32SLang Hames /// all blocks should have been assigned their final addresses.
1000a74ec32SLang Hames template <typename SymbolIdentifierFunction>
1010a74ec32SLang Hames DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction>
1020a74ec32SLang Hames createDefineExternalSectionStartAndEndSymbolsPass(
1030a74ec32SLang Hames     SymbolIdentifierFunction &&F) {
1040a74ec32SLang Hames   return DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction>(
1050a74ec32SLang Hames       std::forward<SymbolIdentifierFunction>(F));
1060a74ec32SLang Hames }
1070a74ec32SLang Hames 
108488a1873SLang Hames /// ELF section start/end symbol detection.
109488a1873SLang Hames inline SectionRangeSymbolDesc
110488a1873SLang Hames identifyELFSectionStartAndEndSymbols(LinkGraph &G, Symbol &Sym) {
111488a1873SLang Hames   constexpr StringRef StartSymbolPrefix = "__start_";
112488a1873SLang Hames   constexpr StringRef EndSymbolPrefix = "__stop_";
113488a1873SLang Hames 
114488a1873SLang Hames   auto SymName = Sym.getName();
115*2ccf7ed2SJared Wyles   if ((*SymName).starts_with(StartSymbolPrefix)) {
116*2ccf7ed2SJared Wyles     if (auto *Sec = G.findSectionByName(
117*2ccf7ed2SJared Wyles             (*SymName).drop_front(StartSymbolPrefix.size())))
118488a1873SLang Hames       return {*Sec, true};
119*2ccf7ed2SJared Wyles   } else if ((*SymName).starts_with(EndSymbolPrefix)) {
120488a1873SLang Hames     if (auto *Sec =
121*2ccf7ed2SJared Wyles             G.findSectionByName((*SymName).drop_front(EndSymbolPrefix.size())))
122488a1873SLang Hames       return {*Sec, false};
123488a1873SLang Hames   }
124488a1873SLang Hames   return {};
125488a1873SLang Hames }
126488a1873SLang Hames 
127c4d58815SLang Hames /// MachO section start/end symbol detection.
128c4d58815SLang Hames inline SectionRangeSymbolDesc
129c4d58815SLang Hames identifyMachOSectionStartAndEndSymbols(LinkGraph &G, Symbol &Sym) {
130c4d58815SLang Hames   constexpr StringRef StartSymbolPrefix = "section$start$";
131c4d58815SLang Hames   constexpr StringRef EndSymbolPrefix = "section$end$";
132c4d58815SLang Hames 
133c4d58815SLang Hames   auto SymName = Sym.getName();
134*2ccf7ed2SJared Wyles   if ((*SymName).starts_with(StartSymbolPrefix)) {
135c4d58815SLang Hames     auto [SegName, SecName] =
136*2ccf7ed2SJared Wyles         (*SymName).drop_front(StartSymbolPrefix.size()).split('$');
137c4d58815SLang Hames     std::string SectionName = (SegName + "," + SecName).str();
138c4d58815SLang Hames     if (auto *Sec = G.findSectionByName(SectionName))
139c4d58815SLang Hames       return {*Sec, true};
140*2ccf7ed2SJared Wyles   } else if ((*SymName).starts_with(EndSymbolPrefix)) {
141c4d58815SLang Hames     auto [SegName, SecName] =
142*2ccf7ed2SJared Wyles         (*SymName).drop_front(EndSymbolPrefix.size()).split('$');
143c4d58815SLang Hames     std::string SectionName = (SegName + "," + SecName).str();
144c4d58815SLang Hames     if (auto *Sec = G.findSectionByName(SectionName))
145c4d58815SLang Hames       return {*Sec, false};
146c4d58815SLang Hames   }
147c4d58815SLang Hames   return {};
148c4d58815SLang Hames }
149c4d58815SLang Hames 
1500a74ec32SLang Hames } // end namespace jitlink
1510a74ec32SLang Hames } // end namespace llvm
1520a74ec32SLang Hames 
1530a74ec32SLang Hames #undef DEBUG_TYPE
1540a74ec32SLang Hames 
1550a74ec32SLang Hames #endif // LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H
156