diff options
Diffstat (limited to 'lib/Object/RecordStreamer.cpp')
| -rw-r--r-- | lib/Object/RecordStreamer.cpp | 123 | 
1 files changed, 119 insertions, 4 deletions
diff --git a/lib/Object/RecordStreamer.cpp b/lib/Object/RecordStreamer.cpp index e94e9cfed394..1f57867dd21a 100644 --- a/lib/Object/RecordStreamer.cpp +++ b/lib/Object/RecordStreamer.cpp @@ -8,6 +8,9 @@  //===----------------------------------------------------------------------===//  #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; @@ -70,7 +73,8 @@ void RecordStreamer::markUsed(const MCSymbol &Symbol) {  void RecordStreamer::visitUsedSymbol(const MCSymbol &Sym) { markUsed(Sym); } -RecordStreamer::RecordStreamer(MCContext &Context) : MCStreamer(Context) {} +RecordStreamer::RecordStreamer(MCContext &Context, const Module &M) +    : MCStreamer(Context), M(M) {}  RecordStreamer::const_iterator RecordStreamer::begin() {    return Symbols.begin(); @@ -103,7 +107,8 @@ bool RecordStreamer::EmitSymbolAttribute(MCSymbol *Symbol,  }  void RecordStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, -                                  uint64_t Size, unsigned ByteAlignment) { +                                  uint64_t Size, unsigned ByteAlignment, +                                  SMLoc Loc) {    markDefined(*Symbol);  } @@ -112,7 +117,117 @@ void RecordStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,    markDefined(*Symbol);  } -void RecordStreamer::emitELFSymverDirective(MCSymbol *Alias, +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(Alias); +  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); +    } +  }  }  | 
