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
23namespace llvm {
24namespace jitlink {
25
26struct 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.
36template <typename SymbolIdentifierFunction>
37class DefineExternalSectionStartAndEndSymbols {
38public:
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
72private:
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.
100template <typename SymbolIdentifierFunction>
101DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction>
102createDefineExternalSectionStartAndEndSymbolsPass(
103 SymbolIdentifierFunction &&F) {
104 return DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction>(
105 std::forward<SymbolIdentifierFunction>(F));
106}
107
108/// ELF section start/end symbol detection.
109inline SectionRangeSymbolDesc
110identifyELFSectionStartAndEndSymbols(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.
128inline SectionRangeSymbolDesc
129identifyMachOSectionStartAndEndSymbols(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