diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.cpp index 6760d3e7cbb5b1..993111552a3143 100644 --- 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 @@ LoongArchMCExpr::getVariantKindForName(StringRef name) { .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/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h index 4706c2e65fea3c..0945cf82db865c 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCExpr.h @@ -86,7 +86,7 @@ class LoongArchMCExpr : public MCTargetExpr { 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/test/MC/LoongArch/Misc/tls-symbols.s b/llvm/test/MC/LoongArch/Misc/tls-symbols.s new file mode 100644 index 00000000000000..2f91cbe004d27d --- /dev/null +++ b/llvm/test/MC/LoongArch/Misc/tls-symbols.s @@ -0,0 +1,79 @@ +# RUN: llvm-mc --triple=loongarch64 --filetype=obj %s -o %t +# RUN: llvm-readobj -s %t | FileCheck %s + +lu12i.w $a1, %gd_hi20(gd_abs) +# CHECK: Symbol { +# CHECK: Name: gd_abs +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: TLS +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } + +pcalau12i $a1, %gd_pc_hi20(gd_pcrel) +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: gd_pcrel +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: TLS +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } + +lu12i.w $a1, %ld_hi20(ld_abs) +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: ld_abs +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: TLS +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } + +pcalau12i $a1, %ld_pc_hi20(ld_pcrel) +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: ld_pcrel +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: TLS +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } + +lu12i.w $a1, %ie_hi20(ie_abs) +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: ie_abs +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: TLS +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } + +pcalau12i $a1, %ie_pc_hi20(ie_pcrel) +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: ie_pcrel +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: TLS +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } + +lu12i.w $a1, %le_hi20(le) +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: le +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: TLS +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: }