| //===-- RecordStreamer.cpp - Record asm defined and used symbols ----------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "RecordStreamer.h" |
| #include "llvm/IR/Mangler.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/MC/MCContext.h" |
| #include "llvm/MC/MCSymbol.h" |
| |
| using namespace llvm; |
| |
| void RecordStreamer::markDefined(const MCSymbol &Symbol) { |
| State &S = Symbols[Symbol.getName()]; |
| switch (S) { |
| case DefinedGlobal: |
| case Global: |
| S = DefinedGlobal; |
| break; |
| case NeverSeen: |
| case Defined: |
| case Used: |
| S = Defined; |
| break; |
| case DefinedWeak: |
| break; |
| case UndefinedWeak: |
| S = DefinedWeak; |
| } |
| } |
| |
| void RecordStreamer::markGlobal(const MCSymbol &Symbol, |
| MCSymbolAttr Attribute) { |
| State &S = Symbols[Symbol.getName()]; |
| switch (S) { |
| case DefinedGlobal: |
| case Defined: |
| S = (Attribute == MCSA_Weak) ? DefinedWeak : DefinedGlobal; |
| break; |
| |
| case NeverSeen: |
| case Global: |
| case Used: |
| S = (Attribute == MCSA_Weak) ? UndefinedWeak : Global; |
| break; |
| case UndefinedWeak: |
| case DefinedWeak: |
| break; |
| } |
| } |
| |
| void RecordStreamer::markUsed(const MCSymbol &Symbol) { |
| State &S = Symbols[Symbol.getName()]; |
| switch (S) { |
| case DefinedGlobal: |
| case Defined: |
| case Global: |
| case DefinedWeak: |
| case UndefinedWeak: |
| break; |
| |
| case NeverSeen: |
| case Used: |
| S = Used; |
| break; |
| } |
| } |
| |
| void RecordStreamer::visitUsedSymbol(const MCSymbol &Sym) { markUsed(Sym); } |
| |
| RecordStreamer::RecordStreamer(MCContext &Context, const Module &M) |
| : MCStreamer(Context), M(M) {} |
| |
| RecordStreamer::const_iterator RecordStreamer::begin() { |
| return Symbols.begin(); |
| } |
| |
| RecordStreamer::const_iterator RecordStreamer::end() { return Symbols.end(); } |
| |
| void RecordStreamer::emitInstruction(const MCInst &Inst, |
| const MCSubtargetInfo &STI) { |
| MCStreamer::emitInstruction(Inst, STI); |
| } |
| |
| void RecordStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { |
| MCStreamer::emitLabel(Symbol); |
| markDefined(*Symbol); |
| } |
| |
| void RecordStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) { |
| markDefined(*Symbol); |
| MCStreamer::emitAssignment(Symbol, Value); |
| } |
| |
| bool RecordStreamer::emitSymbolAttribute(MCSymbol *Symbol, |
| MCSymbolAttr Attribute) { |
| if (Attribute == MCSA_Global || Attribute == MCSA_Weak) |
| markGlobal(*Symbol, Attribute); |
| if (Attribute == MCSA_LazyReference) |
| markUsed(*Symbol); |
| return true; |
| } |
| |
| void RecordStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol, |
| uint64_t Size, unsigned ByteAlignment, |
| SMLoc Loc) { |
| markDefined(*Symbol); |
| } |
| |
| void RecordStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, |
| unsigned ByteAlignment) { |
| markDefined(*Symbol); |
| } |
| |
| RecordStreamer::State RecordStreamer::getSymbolState(const MCSymbol *Sym) { |
| auto SI = Symbols.find(Sym->getName()); |
| if (SI == Symbols.end()) |
| return NeverSeen; |
| return SI->second; |
| } |
| |
| void RecordStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym, |
| StringRef Name, |
| bool KeepOriginalSym) { |
| SymverAliasMap[OriginalSym].push_back(Name); |
| } |
| |
| iterator_range<RecordStreamer::const_symver_iterator> |
| RecordStreamer::symverAliases() { |
| return {SymverAliasMap.begin(), SymverAliasMap.end()}; |
| } |
| |
| void RecordStreamer::flushSymverDirectives() { |
| // Mapping from mangled name to GV. |
| StringMap<const GlobalValue *> MangledNameMap; |
| // The name in the assembler will be mangled, but the name in the IR |
| // might not, so we first compute a mapping from mangled name to GV. |
| Mangler Mang; |
| SmallString<64> MangledName; |
| for (const GlobalValue &GV : M.global_values()) { |
| if (!GV.hasName()) |
| continue; |
| MangledName.clear(); |
| MangledName.reserve(GV.getName().size() + 1); |
| Mang.getNameWithPrefix(MangledName, &GV, /*CannotUsePrivateLabel=*/false); |
| MangledNameMap[MangledName] = &GV; |
| } |
| |
| // Walk all the recorded .symver aliases, and set up the binding |
| // for each alias. |
| for (auto &Symver : SymverAliasMap) { |
| const MCSymbol *Aliasee = Symver.first; |
| MCSymbolAttr Attr = MCSA_Invalid; |
| bool IsDefined = false; |
| |
| // First check if the aliasee binding was recorded in the asm. |
| RecordStreamer::State state = getSymbolState(Aliasee); |
| switch (state) { |
| case RecordStreamer::Global: |
| case RecordStreamer::DefinedGlobal: |
| Attr = MCSA_Global; |
| break; |
| case RecordStreamer::UndefinedWeak: |
| case RecordStreamer::DefinedWeak: |
| Attr = MCSA_Weak; |
| break; |
| default: |
| break; |
| } |
| |
| switch (state) { |
| case RecordStreamer::Defined: |
| case RecordStreamer::DefinedGlobal: |
| case RecordStreamer::DefinedWeak: |
| IsDefined = true; |
| break; |
| case RecordStreamer::NeverSeen: |
| case RecordStreamer::Global: |
| case RecordStreamer::Used: |
| case RecordStreamer::UndefinedWeak: |
| break; |
| } |
| |
| if (Attr == MCSA_Invalid || !IsDefined) { |
| const GlobalValue *GV = M.getNamedValue(Aliasee->getName()); |
| if (!GV) { |
| auto MI = MangledNameMap.find(Aliasee->getName()); |
| if (MI != MangledNameMap.end()) |
| GV = MI->second; |
| } |
| if (GV) { |
| // If we don't have a symbol attribute from assembly, then check if |
| // the aliasee was defined in the IR. |
| if (Attr == MCSA_Invalid) { |
| if (GV->hasExternalLinkage()) |
| Attr = MCSA_Global; |
| else if (GV->hasLocalLinkage()) |
| Attr = MCSA_Local; |
| else if (GV->isWeakForLinker()) |
| Attr = MCSA_Weak; |
| } |
| IsDefined = IsDefined || !GV->isDeclarationForLinker(); |
| } |
| } |
| |
| // Set the detected binding on each alias with this aliasee. |
| for (auto AliasName : Symver.second) { |
| std::pair<StringRef, StringRef> Split = AliasName.split("@@@"); |
| SmallString<128> NewName; |
| if (!Split.second.empty() && !Split.second.startswith("@")) { |
| // Special processing for "@@@" according |
| // https://sourceware.org/binutils/docs/as/Symver.html |
| const char *Separator = IsDefined ? "@@" : "@"; |
| AliasName = |
| (Split.first + Separator + Split.second).toStringRef(NewName); |
| } |
| MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName); |
| // TODO: Handle "@@@". Depending on SymbolAttribute value it needs to be |
| // converted into @ or @@. |
| const MCExpr *Value = MCSymbolRefExpr::create(Aliasee, getContext()); |
| if (IsDefined) |
| markDefined(*Alias); |
| // Don't use EmitAssignment override as it always marks alias as defined. |
| MCStreamer::emitAssignment(Alias, Value); |
| if (Attr != MCSA_Invalid) |
| emitSymbolAttribute(Alias, Attr); |
| } |
| } |
| } |