229 lines · cpp
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-exception6//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(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);87}88 89void RecordStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {90 markDefined(*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, Attribute);98 if (Attribute == MCSA_LazyReference)99 markUsed(*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);107}108 109void RecordStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,110 Align ByteAlignment) {111 markDefined(*Symbol);112}113 114RecordStreamer::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 121void RecordStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,122 StringRef Name,123 bool KeepOriginalSym) {124 SymverAliasMap[OriginalSym].push_back(Name);125}126 127iterator_range<RecordStreamer::const_symver_iterator>128RecordStreamer::symverAliases() {129 return SymverAliasMap;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 IR136 // 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 binding149 // 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 if192 // 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 "@@@" according211 // https://sourceware.org/binutils/docs/as/Symver.html212 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 be218 // 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