summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Arch/RISCV.cpp36
-rw-r--r--lld/ELF/InputSection.cpp5
-rw-r--r--lld/ELF/Relocations.cpp2
-rw-r--r--lld/test/ELF/riscv-tls-gd.s124
-rw-r--r--lld/test/ELF/riscv-tls-ie.s82
-rw-r--r--lld/test/ELF/riscv-tls-ld.s90
-rw-r--r--lld/test/ELF/riscv-tls-le.s41
7 files changed, 377 insertions, 3 deletions
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 6e87a0b7952..9a0c703ce68 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -36,6 +36,8 @@ public:
} // end anonymous namespace
+const uint64_t DTPOffset = 0x800;
+
enum Op {
ADDI = 0x13,
AUIPC = 0x17,
@@ -72,7 +74,17 @@ RISCV::RISCV() {
NoneRel = R_RISCV_NONE;
PltRel = R_RISCV_JUMP_SLOT;
RelativeRel = R_RISCV_RELATIVE;
- SymbolicRel = Config->Is64 ? R_RISCV_64 : R_RISCV_32;
+ if (Config->Is64) {
+ SymbolicRel = R_RISCV_64;
+ TlsModuleIndexRel = R_RISCV_TLS_DTPMOD64;
+ TlsOffsetRel = R_RISCV_TLS_DTPREL64;
+ TlsGotRel = R_RISCV_TLS_TPREL64;
+ } else {
+ SymbolicRel = R_RISCV_32;
+ TlsModuleIndexRel = R_RISCV_TLS_DTPMOD32;
+ TlsOffsetRel = R_RISCV_TLS_DTPREL32;
+ TlsGotRel = R_RISCV_TLS_TPREL32;
+ }
GotRel = SymbolicRel;
// .got[0] = _DYNAMIC
@@ -199,8 +211,18 @@ RelExpr RISCV::getRelExpr(const RelType Type, const Symbol &S,
case R_RISCV_PCREL_LO12_I:
case R_RISCV_PCREL_LO12_S:
return R_RISCV_PC_INDIRECT;
+ case R_RISCV_TLS_GD_HI20:
+ return R_TLSGD_PC;
+ case R_RISCV_TLS_GOT_HI20:
+ Config->HasStaticTlsModel = true;
+ return R_GOT_PC;
+ case R_RISCV_TPREL_HI20:
+ case R_RISCV_TPREL_LO12_I:
+ case R_RISCV_TPREL_LO12_S:
+ return R_TLS;
case R_RISCV_RELAX:
case R_RISCV_ALIGN:
+ case R_RISCV_TPREL_ADD:
return R_HINT;
default:
return R_ABS;
@@ -314,6 +336,9 @@ void RISCV::relocateOne(uint8_t *Loc, const RelType Type,
case R_RISCV_GOT_HI20:
case R_RISCV_PCREL_HI20:
+ case R_RISCV_TLS_GD_HI20:
+ case R_RISCV_TLS_GOT_HI20:
+ case R_RISCV_TPREL_HI20:
case R_RISCV_HI20: {
uint64_t Hi = Val + 0x800;
checkInt(Loc, SignExtend64(Hi, Bits) >> 12, 20, Type);
@@ -322,6 +347,7 @@ void RISCV::relocateOne(uint8_t *Loc, const RelType Type,
}
case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_TPREL_LO12_I:
case R_RISCV_LO12_I: {
uint64_t Hi = (Val + 0x800) >> 12;
uint64_t Lo = Val - (Hi << 12);
@@ -330,6 +356,7 @@ void RISCV::relocateOne(uint8_t *Loc, const RelType Type,
}
case R_RISCV_PCREL_LO12_S:
+ case R_RISCV_TPREL_LO12_S:
case R_RISCV_LO12_S: {
uint64_t Hi = (Val + 0x800) >> 12;
uint64_t Lo = Val - (Hi << 12);
@@ -380,6 +407,13 @@ void RISCV::relocateOne(uint8_t *Loc, const RelType Type,
write32le(Loc, Val);
return;
+ case R_RISCV_TLS_DTPREL32:
+ write32le(Loc, Val - DTPOffset);
+ break;
+ case R_RISCV_TLS_DTPREL64:
+ write64le(Loc, Val - DTPOffset);
+ break;
+
case R_RISCV_ALIGN:
case R_RISCV_RELAX:
return; // Ignored (for now)
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 397bb84a6f9..7fc7b011602 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -587,7 +587,8 @@ static Relocation *getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) {
});
for (auto It = Range.first; It != Range.second; ++It)
- if (It->Type == R_RISCV_PCREL_HI20 || It->Type == R_RISCV_GOT_HI20)
+ if (It->Type == R_RISCV_PCREL_HI20 || It->Type == R_RISCV_GOT_HI20 ||
+ It->Type == R_RISCV_TLS_GD_HI20 || It->Type == R_RISCV_TLS_GOT_HI20)
return &*It;
error("R_RISCV_PCREL_LO12 relocation points to " + IS->getObjMsg(D->Value) +
@@ -620,6 +621,8 @@ static int64_t getTlsTpOffset(const Symbol &S) {
// offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the
// program's TLS segment.
return S.getVA(0) - 0x7000;
+ case EM_RISCV:
+ return S.getVA(0);
default:
llvm_unreachable("unhandled Config->EMachine");
}
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 8b8a3b1d4f9..61080eca7a1 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -177,7 +177,7 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
return 1;
}
- bool CanRelax = Config->EMachine != EM_ARM;
+ bool CanRelax = Config->EMachine != EM_ARM && Config->EMachine != EM_RISCV;
// If we are producing an executable and the symbol is non-preemptable, it
// must be defined and the code sequence can be relaxed to use Local-Exec.
diff --git a/lld/test/ELF/riscv-tls-gd.s b/lld/test/ELF/riscv-tls-gd.s
new file mode 100644
index 00000000000..21a86954056
--- /dev/null
+++ b/lld/test/ELF/riscv-tls-gd.s
@@ -0,0 +1,124 @@
+# REQUIRES: riscv
+# RUN: echo '.tbss; .globl b, c; b: .zero 4; c:' > %t.s
+# RUN: echo '.globl __tls_get_addr; __tls_get_addr:' > %tga.s
+
+## RISC-V psABI doesn't specify TLS relaxation. Though the code sequences are not
+## relaxed, dynamic relocations can be omitted for GD->LE relaxation.
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o
+# RUN: llvm-mc -filetype=obj -triple=riscv32 %t.s -o %t1.32.o
+# RUN: ld.lld -shared -soname=t1.so %t1.32.o -o %t1.32.so
+# RUN: llvm-mc -filetype=obj -triple=riscv32 %tga.s -o %tga.32.o
+## rv32 GD
+# RUN: ld.lld -shared %t.32.o %t1.32.o -o %t.32.so
+# RUN: llvm-readobj -r %t.32.so | FileCheck --check-prefix=GD32-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.32.so | FileCheck --check-prefix=GD32 %s
+## rv32 GD -> LE
+# RUN: ld.lld %t.32.o %t1.32.o %tga.32.o -o %t.32
+# RUN: llvm-readelf -r %t.32 | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=LE32-GOT %s
+# RUN: ld.lld -pie %t.32.o %t1.32.o %tga.32.o -o %t.32
+# RUN: llvm-readelf -r %t.32 | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=LE32-GOT %s
+## rv32 GD -> IE
+# RUN: ld.lld %t.32.o %t1.32.so %tga.32.o -o %t.32
+# RUN: llvm-readobj -r %t.32 | FileCheck --check-prefix=IE32-REL %s
+# RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=IE32-GOT %s
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64 %t.s -o %t1.64.o
+# RUN: ld.lld -shared -soname=t1.so %t1.64.o -o %t1.64.so
+# RUN: llvm-mc -filetype=obj -triple=riscv64 %tga.s -o %tga.64.o
+## rv64 GD
+# RUN: ld.lld -shared %t.64.o %t1.64.o -o %t.64.so
+# RUN: llvm-readobj -r %t.64.so | FileCheck --check-prefix=GD64-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64.so | FileCheck --check-prefix=GD64 %s
+## rv64 GD -> LE
+# RUN: ld.lld %t.64.o %t1.64.o %tga.64.o -o %t.64
+# RUN: llvm-readelf -r %t.64 | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=LE64-GOT %s
+# RUN: ld.lld -pie %t.64.o %t1.64.o %tga.64.o -o %t.64
+# RUN: llvm-readelf -r %t.64 | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=LE64-GOT %s
+## rv64 GD -> IE
+# RUN: ld.lld %t.64.o %t1.64.so %tga.64.o -o %t.64
+# RUN: llvm-readobj -r %t.64 | FileCheck --check-prefix=IE64-REL %s
+# RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=IE64-GOT %s
+
+# GD32-REL: .rela.dyn {
+# GD32-REL-NEXT: 0x2070 R_RISCV_TLS_DTPMOD32 a 0x0
+# GD32-REL-NEXT: 0x2074 R_RISCV_TLS_DTPREL32 a 0x0
+# GD32-REL-NEXT: 0x2078 R_RISCV_TLS_DTPMOD32 b 0x0
+# GD32-REL-NEXT: 0x207C R_RISCV_TLS_DTPREL32 b 0x0
+# GD32-REL-NEXT: }
+
+## &DTPMOD(a) - . = 0x2070 - 0x1000 = 4096*1+112
+# GD32: 1000: auipc a0, 1
+# GD32-NEXT: addi a0, a0, 112
+# GD32-NEXT: auipc ra, 0
+# GD32-NEXT: jalr ra, ra, 56
+
+## &DTPMOD(b) - . = 0x2078 - 0x1010 = 4096*1+104
+# GD32: 1010: auipc a0, 1
+# GD32-NEXT: addi a0, a0, 104
+# GD32-NEXT: auipc ra, 0
+# GD32-NEXT: jalr ra, ra, 40
+
+# GD64-REL: .rela.dyn {
+# GD64-REL-NEXT: 0x20E0 R_RISCV_TLS_DTPMOD64 a 0x0
+# GD64-REL-NEXT: 0x20E8 R_RISCV_TLS_DTPREL64 a 0x0
+# GD64-REL-NEXT: 0x20F0 R_RISCV_TLS_DTPMOD64 b 0x0
+# GD64-REL-NEXT: 0x20F8 R_RISCV_TLS_DTPREL64 b 0x0
+# GD64-REL-NEXT: }
+
+## &DTPMOD(a) - . = 0x20e0 - 0x1000 = 4096*1+224
+# GD64: 1000: auipc a0, 1
+# GD64-NEXT: addi a0, a0, 224
+# GD64-NEXT: auipc ra, 0
+# GD64-NEXT: jalr ra, ra, 56
+
+## &DTPMOD(b) - . = 0x20f0 - 0x1010 = 4096*1+224
+# GD64: 1010: auipc a0, 1
+# GD64-NEXT: addi a0, a0, 224
+# GD64-NEXT: auipc ra, 0
+# GD64-NEXT: jalr ra, ra, 40
+
+# NOREL: no relocations
+
+## .got contains pre-populated values: [a@dtpmod, a@dtprel, b@dtpmod, b@dtprel]
+## a@dtprel = st_value(a)-0x800 = 0xfffff808
+## b@dtprel = st_value(b)-0x800 = 0xfffff80c
+# LE32-GOT: section '.got':
+# LE32-GOT-NEXT: 0x{{[0-9a-f]+}} 01000000 08f8ffff 01000000 0cf8ffff
+# LE64-GOT: section '.got':
+# LE64-GOT-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 08f8ffff ffffffff
+# LE64-GOT-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 0cf8ffff ffffffff
+
+## a is local - relaxed to LE - its DTPMOD/DTPREL slots are link-time constants.
+## b is external - DTPMOD/DTPREL dynamic relocations are required.
+# IE32-REL: .rela.dyn {
+# IE32-REL-NEXT: 0x12068 R_RISCV_TLS_DTPMOD32 b 0x0
+# IE32-REL-NEXT: 0x1206C R_RISCV_TLS_DTPREL32 b 0x0
+# IE32-REL-NEXT: }
+# IE32-GOT: section '.got':
+# IE32-GOT-NEXT: 0x00012060 01000000 08f8ffff 00000000 00000000
+
+# IE64-REL: .rela.dyn {
+# IE64-REL-NEXT: 0x120D0 R_RISCV_TLS_DTPMOD64 b 0x0
+# IE64-REL-NEXT: 0x120D8 R_RISCV_TLS_DTPREL64 b 0x0
+# IE64-REL-NEXT: }
+# IE64-GOT: section '.got':
+# IE64-GOT-NEXT: 0x000120c0 01000000 00000000 08f8ffff ffffffff
+# IE64-GOT-NEXT: 0x000120d0 00000000 00000000 00000000 00000000
+
+la.tls.gd a0,a
+call __tls_get_addr@plt
+
+la.tls.gd a0,b
+call __tls_get_addr@plt
+
+.section .tbss
+.globl a
+.zero 8
+a:
+.zero 4
diff --git a/lld/test/ELF/riscv-tls-ie.s b/lld/test/ELF/riscv-tls-ie.s
new file mode 100644
index 00000000000..b7497c3093d
--- /dev/null
+++ b/lld/test/ELF/riscv-tls-ie.s
@@ -0,0 +1,82 @@
+# REQUIRES: riscv
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o
+## rv32 IE
+# RUN: ld.lld -shared %t.32.o -o %t.32.so
+# RUN: llvm-readobj -r -d %t.32.so | FileCheck --check-prefix=IE32-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.32.so | FileCheck --check-prefixes=IE,IE32 %s
+## rv32 IE -> LE
+# RUN: ld.lld %t.32.o -o %t.32
+# RUN: llvm-readelf -r %t.32 | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=LE32-GOT %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o
+## rv64 IE
+# RUN: ld.lld -shared %t.64.o -o %t.64.so
+# RUN: llvm-readobj -r -d %t.64.so | FileCheck --check-prefix=IE64-REL %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64.so | FileCheck --check-prefixes=IE,IE64 %s
+## rv64 IE -> LE
+# RUN: ld.lld %t.64.o -o %t.64
+# RUN: llvm-readelf -r %t.64 | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=LE64-GOT %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s
+
+# IE32-REL: .rela.dyn {
+# IE32-REL-NEXT: 0x205C R_RISCV_TLS_TPREL32 - 0xC
+# IE32-REL-NEXT: 0x2058 R_RISCV_TLS_TPREL32 a 0x0
+# IE32-REL-NEXT: }
+# IE32-REL: FLAGS STATIC_TLS
+
+# IE64-REL: .rela.dyn {
+# IE64-REL-NEXT: 0x20B8 R_RISCV_TLS_TPREL64 - 0xC
+# IE64-REL-NEXT: 0x20B0 R_RISCV_TLS_TPREL64 a 0x0
+# IE64-REL-NEXT: }
+# IE64-REL: FLAGS STATIC_TLS
+
+## rv32: &.got[1] - . = 0x2058 - . = 4096*1+88
+## rv64: &.got[1] - . = 0x20B0 - . = 4096*1+176
+# IE: 1000: auipc a4, 1
+# IE32-NEXT: lw a4, 88(a4)
+# IE64-NEXT: ld a4, 176(a4)
+# IE-NEXT: add a4, a4, tp
+## rv32: &.got[0] - . = 0x205C - . = 4096*1+80
+## rv64: &.got[0] - . = 0x20B8 - . = 4096*1+172
+# IE: 100c: auipc a5, 1
+# IE32-NEXT: lw a5, 80(a5)
+# IE64-NEXT: ld a5, 172(a5)
+# IE-NEXT: add a5, a5, tp
+
+# NOREL: no relocations
+
+# a@tprel = st_value(a) = 0x8
+# b@tprel = st_value(a) = 0xc
+# LE32-GOT: section '.got':
+# LE32-GOT-NEXT: 0x00012000 08000000 0c000000
+# LE64-GOT: section '.got':
+# LE64-GOT-NEXT: 0x00012000 08000000 00000000 0c000000 00000000
+
+## rv32: &.got[0] - . = 0x12000 - 0x11000 = 4096*1+0
+## rv64: &.got[0] - . = 0x12000 - 0x11000 = 4096*1+0
+# LE: 11000: auipc a4, 1
+# LE32-NEXT: lw a4, 0(a4)
+# LE64-NEXT: ld a4, 0(a4)
+# LE-NEXT: add a4, a4, tp
+## rv32: &.got[1] - . = 0x12004 - 0x1100c = 4096*1-8
+## rv64: &.got[1] - . = 0x12008 - 0x1100c = 4096*1-4
+# LE: 1100c: auipc a5, 1
+# LE32-NEXT: lw a5, -8(a5)
+# LE64-NEXT: ld a5, -4(a5)
+# LE-NEXT: add a5, a5, tp
+
+la.tls.ie a4,a
+add a4,a4,tp
+la.tls.ie a5,b
+add a5,a5,tp
+
+.section .tbss
+.globl a
+.zero 8
+a:
+.zero 4
+b:
diff --git a/lld/test/ELF/riscv-tls-ld.s b/lld/test/ELF/riscv-tls-ld.s
new file mode 100644
index 00000000000..a2a67688990
--- /dev/null
+++ b/lld/test/ELF/riscv-tls-ld.s
@@ -0,0 +1,90 @@
+# REQUIRES: riscv
+# RUN: echo '.tbss; .globl b, c; b: .zero 4; c:' > %t.s
+# RUN: echo '.globl __tls_get_addr; __tls_get_addr:' > %tga.s
+
+## RISC-V psABI doesn't specify TLS relaxation. Though the code sequences are not
+## relaxed, dynamic relocations can be omitted for LD->LE relaxation.
+## LD uses the same relocation as GD: R_RISCV_GD_HI20, the difference is that it
+## references a local symbol (.LANCHOR0).
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -position-independent %s -o %t.32.o
+# RUN: llvm-mc -filetype=obj -triple=riscv32 %tga.s -o %tga.o
+## rv32 LD
+# RUN: ld.lld -shared %t.32.o -o %t.32.so
+# RUN: llvm-readobj -r %t.32.so | FileCheck --check-prefix=LD32-REL %s
+# RUN: llvm-readelf -x .got %t.32.so | FileCheck --check-prefix=LD32-GOT %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.32.so | FileCheck --check-prefixes=LD,LD32 %s
+## rv32 LD -> LE
+# RUN: ld.lld %t.32.o %tga.o -o %t.32
+# RUN: llvm-readelf -r %t.32 | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-readelf -x .got %t.32 | FileCheck --check-prefix=LE32-GOT %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE,LE32 %s
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -position-independent %s -o %t.64.o
+# RUN: llvm-mc -filetype=obj -triple=riscv64 %tga.s -o %tga.o
+## rv64 LD
+# RUN: ld.lld -shared %t.64.o -o %t.64.so
+# RUN: llvm-readobj -r %t.64.so | FileCheck --check-prefix=LD64-REL %s
+# RUN: llvm-readelf -x .got %t.64.so | FileCheck --check-prefix=LD64-GOT %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64.so | FileCheck --check-prefixes=LD,LD64 %s
+## rv64 LD -> LE
+# RUN: ld.lld %t.64.o %tga.o -o %t.64
+# RUN: llvm-readelf -r %t.64 | FileCheck --check-prefix=NOREL %s
+# RUN: llvm-readelf -x .got %t.64 | FileCheck --check-prefix=LE64-GOT %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE,LE64 %s
+
+## a@dtprel = st_value(a)-0x800 = 0xfffff808 is a link-time constant.
+# LD32-REL: .rela.dyn {
+# LD32-REL-NEXT: 0x2084
+# LD32-REL-NEXT: 0x207C R_RISCV_TLS_DTPMOD32 - 0x0
+# LD32-REL-NEXT: }
+# LD32-GOT: section '.got':
+# LD32-GOT-NEXT: 0x00002078 00200000 00000000 00f8ffff 00000000
+
+# LD64-REL: .rela.dyn {
+# LD64-REL-NEXT: 0x2108
+# LD64-REL-NEXT: 0x20F8 R_RISCV_TLS_DTPMOD64 - 0x0
+# LD64-REL-NEXT: }
+# LD64-GOT: section '.got':
+# LD64-GOT-NEXT: 0x000020f0 00200000 00000000 00000000 00000000
+# LD64-GOT-NEXT: 0x00002100 00f8ffff ffffffff 00000000 00000000
+
+## rv32: &DTPMOD(a) - . = 0x207c - 0x1000 = 4096*1+124
+## rv64: &DTPMOD(a) - . = 0x20e0 - 0x1000 = 4096*1+248
+# LD: 1000: auipc a0, 1
+# LD32-NEXT: addi a0, a0, 124
+# LD64-NEXT: addi a0, a0, 248
+# LD-NEXT: auipc ra, 0
+# LD-NEXT: jalr ra, ra, 56
+
+# NOREL: no relocations
+
+## a is local - its DTPMOD/DTPREL slots are link-time constants.
+## a@dtpmod = 1 (main module)
+# LE32-GOT: section '.got':
+# LE32-GOT-NEXT: 0x00012000 00000000 01000000 00f8ffff 00200100
+
+# LE64-GOT: section '.got':
+# LE64-GOT-NEXT: 0x00012000 00000000 00000000 01000000 00000000
+# LE64-GOT-NEXT: 0x00012010 00f8ffff ffffffff 00200100 00000000
+
+## rv32: DTPMOD(.LANCHOR0) - . = 0x12004 - 0x11000 = 4096*1+4
+## rv64: DTPMOD(.LANCHOR0) - . = 0x12008 - 0x11000 = 4096*1+8
+# LE: 11000: auipc a0, 1
+# LE32-NEXT: addi a0, a0, 4
+# LE64-NEXT: addi a0, a0, 8
+# LE-NEXT: auipc ra, 0
+# LE-NEXT: jalr ra, ra, 24
+
+la.tls.gd a0, .LANCHOR0
+call __tls_get_addr@plt
+lw a4, 0(a0)
+lh a0, 4(a0)
+
+## This is irrelevant to TLS. We use it to take 2 GOT slots to check DTPREL
+## offsets are correct.
+la a5, _GLOBAL_OFFSET_TABLE_
+
+.section .tbss,"awT",@nobits
+.set .LANCHOR0, . + 0
+.zero 8
diff --git a/lld/test/ELF/riscv-tls-le.s b/lld/test/ELF/riscv-tls-le.s
new file mode 100644
index 00000000000..860e6884c5d
--- /dev/null
+++ b/lld/test/ELF/riscv-tls-le.s
@@ -0,0 +1,41 @@
+# REQUIRES: riscv
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o
+# RUN: ld.lld %t.32.o -o %t.32
+# RUN: llvm-nm -p %t.32 | FileCheck --check-prefixes=NM %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE %s
+# RUN: ld.lld -pie %t.32.o -o %t.32
+# RUN: llvm-objdump -d --no-show-raw-insn %t.32 | FileCheck --check-prefixes=LE %s
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o
+# RUN: ld.lld %t.64.o -o %t.64
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE %s
+# RUN: ld.lld -pie %t.64.o -o %t.64
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64 | FileCheck --check-prefixes=LE %s
+
+# NM: {{0*}}00000008 b .LANCHOR0
+# NM: {{0*}}0000000c B a
+
+## .LANCHOR0@tprel = 8
+## a@tprel = 12
+# LE: lui a5, 0
+# LE-NEXT: add a5, a5, tp
+# LE-NEXT: addi a5, a5, 8
+# LE-NEXT: lui a5, 0
+# LE-NEXT: add a5, a5, tp
+# LE-NEXT: sw a0, 12(a5)
+
+lui a5, %tprel_hi(.LANCHOR0)
+add a5, a5, tp, %tprel_add(.LANCHOR0)
+addi a5, a5, %tprel_lo(.LANCHOR0)
+
+lui a5, %tprel_hi(a)
+add a5, a5, tp, %tprel_add(a)
+sw a0, %tprel_lo(a)(a5)
+
+.section .tbss
+.space 8
+.LANCHOR0:
+.zero 4
+.globl a
+a:
OpenPOWER on IntegriCloud