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