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 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 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 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 73 void RecordStreamer::visitUsedSymbol(const MCSymbol &Sym) { markUsed(Sym); } 74 75 RecordStreamer::RecordStreamer(MCContext &Context, const Module &M) 76 : MCStreamer(Context), M(M) {} 77 78 RecordStreamer::const_iterator RecordStreamer::begin() { 79 return Symbols.begin(); 80 } 81 82 RecordStreamer::const_iterator RecordStreamer::end() { return Symbols.end(); } 83 84 void RecordStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { 85 MCStreamer::emitLabel(Symbol); 86 markDefined(*Symbol); 87 } 88 89 void RecordStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) { 90 markDefined(*Symbol); 91 MCStreamer::emitAssignment(Symbol, Value); 92 } 93 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 103 void RecordStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol, 104 uint64_t Size, Align ByteAlignment, 105 SMLoc Loc) { 106 markDefined(*Symbol); 107 } 108 109 void RecordStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, 110 Align ByteAlignment) { 111 markDefined(*Symbol); 112 } 113 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 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> 128 RecordStreamer::symverAliases() { 129 return {SymverAliasMap.begin(), SymverAliasMap.end()}; 130 } 131 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