1//===-- RecordStreamer.cpp - Record asm defined and used symbols ----------===//
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#include "RecordStreamer.h"
10#include "llvm/IR/Mangler.h"
11#include "llvm/IR/Module.h"
12#include "llvm/MC/MCContext.h"
13#include "llvm/MC/MCSymbol.h"
14
15using namespace llvm;
16
17void RecordStreamer::markDefined(const MCSymbol &Symbol) {
18 State &S = Symbols[Symbol.getName()];
19 switch (S) {
20 case DefinedGlobal:
21 case Global:
22 S = DefinedGlobal;
23 break;
24 case NeverSeen:
25 case Defined:
26 case Used:
27 S = Defined;
28 break;
29 case DefinedWeak:
30 break;
31 case UndefinedWeak:
32 S = DefinedWeak;
33 }
34}
35
36void RecordStreamer::markGlobal(const MCSymbol &Symbol,
37 MCSymbolAttr Attribute) {
38 State &S = Symbols[Symbol.getName()];
39 switch (S) {
40 case DefinedGlobal:
41 case Defined:
42 S = (Attribute == MCSA_Weak) ? DefinedWeak : DefinedGlobal;
43 break;
44
45 case NeverSeen:
46 case Global:
47 case Used:
48 S = (Attribute == MCSA_Weak) ? UndefinedWeak : Global;
49 break;
50 case UndefinedWeak:
51 case DefinedWeak:
52 break;
53 }
54}
55
56void RecordStreamer::markUsed(const MCSymbol &Symbol) {
57 State &S = Symbols[Symbol.getName()];
58 switch (S) {
59 case DefinedGlobal:
60 case Defined:
61 case Global:
62 case DefinedWeak:
63 case UndefinedWeak:
64 break;
65
66 case NeverSeen:
67 case Used:
68 S = Used;
69 break;
70 }
71}
72
73void RecordStreamer::visitUsedSymbol(const MCSymbol &Sym) { markUsed(Symbol: Sym); }
74
75RecordStreamer::RecordStreamer(MCContext &Context, const Module &M)
76 : MCStreamer(Context), M(M) {}
77
78RecordStreamer::const_iterator RecordStreamer::begin() {
79 return Symbols.begin();
80}
81
82RecordStreamer::const_iterator RecordStreamer::end() { return Symbols.end(); }
83
84void RecordStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
85 MCStreamer::emitLabel(Symbol);
86 markDefined(Symbol: *Symbol);
87}
88
89void RecordStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
90 markDefined(Symbol: *Symbol);
91 MCStreamer::emitAssignment(Symbol, Value);
92}
93
94bool RecordStreamer::emitSymbolAttribute(MCSymbol *Symbol,
95 MCSymbolAttr Attribute) {
96 if (Attribute == MCSA_Global || Attribute == MCSA_Weak)
97 markGlobal(Symbol: *Symbol, Attribute);
98 if (Attribute == MCSA_LazyReference)
99 markUsed(Symbol: *Symbol);
100 return true;
101}
102
103void RecordStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
104 uint64_t Size, Align ByteAlignment,
105 SMLoc Loc) {
106 markDefined(Symbol: *Symbol);
107}
108
109void RecordStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
110 Align ByteAlignment) {
111 markDefined(Symbol: *Symbol);
112}
113
114RecordStreamer::State RecordStreamer::getSymbolState(const MCSymbol *Sym) {
115 auto SI = Symbols.find(Key: Sym->getName());
116 if (SI == Symbols.end())
117 return NeverSeen;
118 return SI->second;
119}
120
121void RecordStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
122 StringRef Name,
123 bool KeepOriginalSym) {
124 SymverAliasMap[OriginalSym].push_back(x: Name);
125}
126
127iterator_range<RecordStreamer::const_symver_iterator>
128RecordStreamer::symverAliases() {
129 return {SymverAliasMap.begin(), SymverAliasMap.end()};
130}
131
132void RecordStreamer::flushSymverDirectives() {
133 // Mapping from mangled name to GV.
134 StringMap<const GlobalValue *> MangledNameMap;
135 // The name in the assembler will be mangled, but the name in the IR
136 // might not, so we first compute a mapping from mangled name to GV.
137 Mangler Mang;
138 SmallString<64> MangledName;
139 for (const GlobalValue &GV : M.global_values()) {
140 if (!GV.hasName())
141 continue;
142 MangledName.clear();
143 MangledName.reserve(N: GV.getName().size() + 1);
144 Mang.getNameWithPrefix(OutName&: MangledName, GV: &GV, /*CannotUsePrivateLabel=*/false);
145 MangledNameMap[MangledName] = &GV;
146 }
147
148 // Walk all the recorded .symver aliases, and set up the binding
149 // for each alias.
150 for (auto &Symver : SymverAliasMap) {
151 const MCSymbol *Aliasee = Symver.first;
152 MCSymbolAttr Attr = MCSA_Invalid;
153 bool IsDefined = false;
154
155 // First check if the aliasee binding was recorded in the asm.
156 RecordStreamer::State state = getSymbolState(Sym: Aliasee);
157 switch (state) {
158 case RecordStreamer::Global:
159 case RecordStreamer::DefinedGlobal:
160 Attr = MCSA_Global;
161 break;
162 case RecordStreamer::UndefinedWeak:
163 case RecordStreamer::DefinedWeak:
164 Attr = MCSA_Weak;
165 break;
166 default:
167 break;
168 }
169
170 switch (state) {
171 case RecordStreamer::Defined:
172 case RecordStreamer::DefinedGlobal:
173 case RecordStreamer::DefinedWeak:
174 IsDefined = true;
175 break;
176 case RecordStreamer::NeverSeen:
177 case RecordStreamer::Global:
178 case RecordStreamer::Used:
179 case RecordStreamer::UndefinedWeak:
180 break;
181 }
182
183 if (Attr == MCSA_Invalid || !IsDefined) {
184 const GlobalValue *GV = M.getNamedValue(Name: Aliasee->getName());
185 if (!GV) {
186 auto MI = MangledNameMap.find(Key: Aliasee->getName());
187 if (MI != MangledNameMap.end())
188 GV = MI->second;
189 }
190 if (GV) {
191 // If we don't have a symbol attribute from assembly, then check if
192 // the aliasee was defined in the IR.
193 if (Attr == MCSA_Invalid) {
194 if (GV->hasExternalLinkage())
195 Attr = MCSA_Global;
196 else if (GV->hasLocalLinkage())
197 Attr = MCSA_Local;
198 else if (GV->isWeakForLinker())
199 Attr = MCSA_Weak;
200 }
201 IsDefined = IsDefined || !GV->isDeclarationForLinker();
202 }
203 }
204
205 // Set the detected binding on each alias with this aliasee.
206 for (auto AliasName : Symver.second) {
207 std::pair<StringRef, StringRef> Split = AliasName.split(Separator: "@@@");
208 SmallString<128> NewName;
209 if (!Split.second.empty() && !Split.second.starts_with(Prefix: "@")) {
210 // Special processing for "@@@" according
211 // https://sourceware.org/binutils/docs/as/Symver.html
212 const char *Separator = IsDefined ? "@@" : "@";
213 AliasName =
214 (Split.first + Separator + Split.second).toStringRef(Out&: NewName);
215 }
216 MCSymbol *Alias = getContext().getOrCreateSymbol(Name: AliasName);
217 // TODO: Handle "@@@". Depending on SymbolAttribute value it needs to be
218 // converted into @ or @@.
219 const MCExpr *Value = MCSymbolRefExpr::create(Symbol: Aliasee, Ctx&: getContext());
220 if (IsDefined)
221 markDefined(Symbol: *Alias);
222 // Don't use EmitAssignment override as it always marks alias as defined.
223 MCStreamer::emitAssignment(Symbol: Alias, Value);
224 if (Attr != MCSA_Invalid)
225 emitSymbolAttribute(Symbol: Alias, Attribute: Attr);
226 }
227 }
228}
229