diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h @@ -86,7 +86,7 @@ return getSubExpr()->findAssociatedFragment(); } - void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override; static bool classof(const MCExpr *E) { return E->getKind() == MCExpr::Target; diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp @@ -16,7 +16,9 @@ #include "LoongArchFixupKinds.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/MCValue.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; @@ -179,3 +181,45 @@ .Case("gd_hi20", VK_LoongArch_TLS_GD_HI20) .Default(VK_LoongArch_Invalid); } + +static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { + switch (Expr->getKind()) { + case MCExpr::Target: + llvm_unreachable("Can't handle nested target expression"); + break; + case MCExpr::Constant: + break; + case MCExpr::Unary: + fixELFSymbolsInTLSFixupsImpl(cast(Expr)->getSubExpr(), Asm); + break; + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(Expr); + fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm); + fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm); + break; + } + case MCExpr::SymbolRef: { + // We're known to be under a TLS fixup, so any symbol should be + // modified. There should be only one. + const MCSymbolRefExpr &SymRef = *cast(Expr); + cast(SymRef.getSymbol()).setType(ELF::STT_TLS); + break; + } + } +} + +void LoongArchMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { + switch (getKind()) { + default: + return; + case VK_LoongArch_TLS_LE_HI20: + case VK_LoongArch_TLS_IE_PC_HI20: + case VK_LoongArch_TLS_IE_HI20: + case VK_LoongArch_TLS_LD_PC_HI20: + case VK_LoongArch_TLS_LD_HI20: + case VK_LoongArch_TLS_GD_PC_HI20: + case VK_LoongArch_TLS_GD_HI20: + break; + } + fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm); +} diff --git a/llvm/test/CodeGen/LoongArch/tls-symbols.ll b/llvm/test/CodeGen/LoongArch/tls-symbols.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/tls-symbols.ll @@ -0,0 +1,32 @@ +; RUN: llc --mtriple=loongarch64 --relocation-model=pic --filetype=obj < %s \ +; RUN: -o - | llvm-readelf -s - | FileCheck %s + +@unspecified = external thread_local global i32 +@ld = external thread_local(localdynamic) global i32 +@ie = external thread_local(initialexec) global i32 +@le = external thread_local(localexec) global i32 + +; CHECK-LABEL: Symbol table +define ptr @f1() nounwind { +entry: +; CHECK: TLS{{.*}}UND unspecified + ret ptr @unspecified +} + +define ptr @f2() nounwind { +entry: +; CHECK: TLS{{.*}}UND ld + ret ptr @ld +} + +define ptr @f3() nounwind { +entry: +; CHECK: TLS{{.*}}UND ie + ret ptr @ie +} + +define ptr @f4() nounwind { +entry: +; CHECK: TLS{{.*}}UND le + ret ptr @le +}