233 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			233 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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(StringRef AliasName,
 | |
|                                             const MCSymbol *Aliasee) {
 | |
|   SymverAliasMap[Aliasee].push_back(AliasName);
 | |
| }
 | |
| 
 | |
| 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);
 | |
|     }
 | |
|   }
 | |
| }
 |