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 
15 using namespace llvm;
16 
markDefined(const MCSymbol & Symbol)17 void 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 
markGlobal(const MCSymbol & Symbol,MCSymbolAttr Attribute)36 void 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 
markUsed(const MCSymbol & Symbol)56 void 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 
visitUsedSymbol(const MCSymbol & Sym)73 void RecordStreamer::visitUsedSymbol(const MCSymbol &Sym) { markUsed(Sym); }
74 
RecordStreamer(MCContext & Context,const Module & M)75 RecordStreamer::RecordStreamer(MCContext &Context, const Module &M)
76     : MCStreamer(Context), M(M) {}
77 
begin()78 RecordStreamer::const_iterator RecordStreamer::begin() {
79   return Symbols.begin();
80 }
81 
end()82 RecordStreamer::const_iterator RecordStreamer::end() { return Symbols.end(); }
83 
emitLabel(MCSymbol * Symbol,SMLoc Loc)84 void RecordStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
85   MCStreamer::emitLabel(Symbol);
86   markDefined(*Symbol);
87 }
88 
emitAssignment(MCSymbol * Symbol,const MCExpr * Value)89 void RecordStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
90   markDefined(*Symbol);
91   MCStreamer::emitAssignment(Symbol, Value);
92 }
93 
emitSymbolAttribute(MCSymbol * Symbol,MCSymbolAttr Attribute)94 bool RecordStreamer::emitSymbolAttribute(MCSymbol *Symbol,
95                                          MCSymbolAttr Attribute) {
96   if (Attribute == MCSA_Global || Attribute == MCSA_Weak)
97     markGlobal(*Symbol, Attribute);
98   if (Attribute == MCSA_LazyReference)
99     markUsed(*Symbol);
100   return true;
101 }
102 
emitZerofill(MCSection * Section,MCSymbol * Symbol,uint64_t Size,Align ByteAlignment,SMLoc Loc)103 void RecordStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
104                                   uint64_t Size, Align ByteAlignment,
105                                   SMLoc Loc) {
106   markDefined(*Symbol);
107 }
108 
emitCommonSymbol(MCSymbol * Symbol,uint64_t Size,Align ByteAlignment)109 void RecordStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
110                                       Align ByteAlignment) {
111   markDefined(*Symbol);
112 }
113 
getSymbolState(const MCSymbol * Sym)114 RecordStreamer::State RecordStreamer::getSymbolState(const MCSymbol *Sym) {
115   auto SI = Symbols.find(Sym->getName());
116   if (SI == Symbols.end())
117     return NeverSeen;
118   return SI->second;
119 }
120 
emitELFSymverDirective(const MCSymbol * OriginalSym,StringRef Name,bool KeepOriginalSym)121 void RecordStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
122                                             StringRef Name,
123                                             bool KeepOriginalSym) {
124   SymverAliasMap[OriginalSym].push_back(Name);
125 }
126 
127 iterator_range<RecordStreamer::const_symver_iterator>
symverAliases()128 RecordStreamer::symverAliases() {
129   return {SymverAliasMap.begin(), SymverAliasMap.end()};
130 }
131 
flushSymverDirectives()132 void 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(GV.getName().size() + 1);
144     Mang.getNameWithPrefix(MangledName, &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(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(Aliasee->getName());
185       if (!GV) {
186         auto MI = MangledNameMap.find(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("@@@");
208       SmallString<128> NewName;
209       if (!Split.second.empty() && !Split.second.starts_with("@")) {
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(NewName);
215       }
216       MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
217       // TODO: Handle "@@@". Depending on SymbolAttribute value it needs to be
218       // converted into @ or @@.
219       const MCExpr *Value = MCSymbolRefExpr::create(Aliasee, getContext());
220       if (IsDefined)
221         markDefined(*Alias);
222       // Don't use EmitAssignment override as it always marks alias as defined.
223       MCStreamer::emitAssignment(Alias, Value);
224       if (Attr != MCSA_Invalid)
225         emitSymbolAttribute(Alias, Attr);
226     }
227   }
228 }
229