Index: llvm/lib/Object/RecordStreamer.cpp =================================================================== --- llvm/lib/Object/RecordStreamer.cpp +++ llvm/lib/Object/RecordStreamer.cpp @@ -143,9 +143,40 @@ void RecordStreamer::emitELFSymverDirective(StringRef AliasName, const MCSymbol *Aliasee) { - MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName); - // TODO: Handle "@@@". Depending on SymbolAttribute value it needs to be - // converted into @ or @@. + std::pair 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 + bool IsDefined = false; + // First check if the aliasee was recorded in the asm. + switch (getSymbolState(Aliasee)) { + 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 (!IsDefined) { + // If we don't have it in assembly, then check if the aliasee was + // defined in the IR. + const GlobalValue *GV = M.getNamedValue(Aliasee->getName()); + if (!GV) { + auto MI = MangledNameMap.find(Aliasee->getName()); + if (MI != MangledNameMap.end()) + GV = MI->second; + } + IsDefined = GV && GV->isDefinitionExact(); + } + const char *Separator = IsDefined ? "@@" : "@"; + AliasName = (Split.first + Separator + Split.second).toStringRef(NewName); + } + MCSymbol* Alias = getContext().getOrCreateSymbol(AliasName); const MCExpr *Value = MCSymbolRefExpr::create(Aliasee, getContext()); EmitAssignment(Alias, Value); SymverAliasMap[Aliasee].push_back(Alias); Index: llvm/test/LTO/X86/symver-asm3.ll =================================================================== --- /dev/null +++ llvm/test/LTO/X86/symver-asm3.ll @@ -0,0 +1,17 @@ +; Test special handling of @@@. + +; RUN: llvm-as < %s >%t1 +; RUN: llvm-nm %t1 | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +module asm "_start1:" +module asm ".symver _start1, foo@@@SOME_VERSION1" +module asm ".symver _start2, foo@@@SOME_VERSION2" +module asm ".local _start1" + +; CHECK-DAG: t _start1 +; CHECK-DAG: U _start2 +; CHECK-DAG: t foo@@SOME_VERSION1 +; CHECK-DAG: t foo@SOME_VERSION2