diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp @@ -14,6 +14,7 @@ #include "MCTargetDesc/PPCInstPrinter.h" #include "MCTargetDesc/PPCMCAsmInfo.h" #include "PPCTargetStreamer.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/ELF.h" @@ -181,16 +182,33 @@ void emitAssignment(MCSymbol *S, const MCExpr *Value) override { auto *Symbol = cast(S); + // When encoding an assignment to set symbol A to symbol B, also copy // the st_other bits encoding the local entry point offset. - if (Value->getKind() != MCExpr::SymbolRef) - return; - const auto &RhsSym = cast( - static_cast(Value)->getSymbol()); - unsigned Other = Symbol->getOther(); + if (copyLocalEntry(Symbol, Value)) + UpdateOther.insert(Symbol); + else + UpdateOther.erase(Symbol); + } + + void finish() override { + for (auto *Sym : UpdateOther) + copyLocalEntry(Sym, Sym->getVariableValue()); + } + +private: + SmallPtrSet UpdateOther; + + bool copyLocalEntry(MCSymbolELF *D, const MCExpr *S) { + auto *Ref = dyn_cast(S); + if (!Ref) + return false; + const auto &RhsSym = cast(Ref->getSymbol()); + unsigned Other = D->getOther(); Other &= ~ELF::STO_PPC64_LOCAL_MASK; Other |= RhsSym.getOther() & ELF::STO_PPC64_LOCAL_MASK; - Symbol->setOther(Other); + D->setOther(Other); + return true; } }; diff --git a/llvm/test/MC/PowerPC/ppc64-localentry-symver.s b/llvm/test/MC/PowerPC/ppc64-localentry-symbols.s rename from llvm/test/MC/PowerPC/ppc64-localentry-symver.s rename to llvm/test/MC/PowerPC/ppc64-localentry-symbols.s --- a/llvm/test/MC/PowerPC/ppc64-localentry-symver.s +++ b/llvm/test/MC/PowerPC/ppc64-localentry-symbols.s @@ -4,6 +4,11 @@ # CHECK: 0000000000000000 gw F .text 00000000 0x60 __impl_foo # CHECK: 0000000000000000 g F .text 00000000 0x60 foo # CHECK: 0000000000000000 gw F .text 00000000 0x60 foo@FBSD_1.1 +# CHECK: 0000000000000008 g F .text 00000000 0x60 func +# CHECK: 0000000000000008 gw F .text 00000000 0x60 weak_func + +.text +.abiversion 2 .globl foo .type foo,@function @@ -15,3 +20,15 @@ .symver __impl_foo, foo@FBSD_1.1 .weak __impl_foo .set __impl_foo, foo + +.globl func +# Mimick FreeBSD weak function/reference +.weak weak_func +.equ weak_func, func + +.p2align 2 +.type func,@function +func: + nop + nop + .localentry func, 8