Skip to content

Commit c4a1440

Browse files
authored
[lld][ELF] Add basic TLSDESC support for LoongArch
LoongArch does not yet implement transition from TLSDESC to LE/IE, so TLSDESC dynamic relocation needs to be generated for each desc, which is ultimately handled by the dynamic linker. The test cases reference RISC-V: #79239 Reviewed By: MaskRay, SixWeining Pull Request: #94451
1 parent 4ab37e4 commit c4a1440

File tree

6 files changed

+210
-0
lines changed

6 files changed

+210
-0
lines changed

lld/ELF/Arch/LoongArch.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,13 @@ uint64_t elf::getLoongArchPageDelta(uint64_t dest, uint64_t pc, RelType type) {
9898
case R_LARCH_PCALA64_LO20:
9999
case R_LARCH_GOT64_PC_LO20:
100100
case R_LARCH_TLS_IE64_PC_LO20:
101+
case R_LARCH_TLS_DESC64_PC_LO20:
101102
pcalau12i_pc = pc - 8;
102103
break;
103104
case R_LARCH_PCALA64_HI12:
104105
case R_LARCH_GOT64_PC_HI12:
105106
case R_LARCH_TLS_IE64_PC_HI12:
107+
case R_LARCH_TLS_DESC64_PC_HI12:
106108
pcalau12i_pc = pc - 12;
107109
break;
108110
default:
@@ -190,11 +192,13 @@ LoongArch::LoongArch() {
190192
tlsModuleIndexRel = R_LARCH_TLS_DTPMOD64;
191193
tlsOffsetRel = R_LARCH_TLS_DTPREL64;
192194
tlsGotRel = R_LARCH_TLS_TPREL64;
195+
tlsDescRel = R_LARCH_TLS_DESC64;
193196
} else {
194197
symbolicRel = R_LARCH_32;
195198
tlsModuleIndexRel = R_LARCH_TLS_DTPMOD32;
196199
tlsOffsetRel = R_LARCH_TLS_DTPREL32;
197200
tlsGotRel = R_LARCH_TLS_TPREL32;
201+
tlsDescRel = R_LARCH_TLS_DESC32;
198202
}
199203

200204
gotRel = symbolicRel;
@@ -294,6 +298,10 @@ int64_t LoongArch::getImplicitAddend(const uint8_t *buf, RelType type) const {
294298
case R_LARCH_JUMP_SLOT:
295299
// These relocations are defined as not having an implicit addend.
296300
return 0;
301+
case R_LARCH_TLS_DESC32:
302+
return read32le(buf + 4);
303+
case R_LARCH_TLS_DESC64:
304+
return read64le(buf + 8);
297305
}
298306
}
299307

@@ -486,6 +494,19 @@ RelExpr LoongArch::getRelExpr(const RelType type, const Symbol &s,
486494
return config->relax ? R_RELAX_HINT : R_NONE;
487495
case R_LARCH_ALIGN:
488496
return R_RELAX_HINT;
497+
case R_LARCH_TLS_DESC_PC_HI20:
498+
case R_LARCH_TLS_DESC64_PC_LO20:
499+
case R_LARCH_TLS_DESC64_PC_HI12:
500+
return R_LOONGARCH_TLSDESC_PAGE_PC;
501+
case R_LARCH_TLS_DESC_PC_LO12:
502+
case R_LARCH_TLS_DESC_LD:
503+
case R_LARCH_TLS_DESC_HI20:
504+
case R_LARCH_TLS_DESC_LO12:
505+
case R_LARCH_TLS_DESC64_LO20:
506+
case R_LARCH_TLS_DESC64_HI12:
507+
return R_TLSDESC;
508+
case R_LARCH_TLS_DESC_CALL:
509+
return R_TLSDESC_CALL;
489510

490511
// Other known relocs that are explicitly unimplemented:
491512
//
@@ -510,6 +531,8 @@ bool LoongArch::usesOnlyLowPageBits(RelType type) const {
510531
case R_LARCH_GOT_LO12:
511532
case R_LARCH_GOT_PC_LO12:
512533
case R_LARCH_TLS_IE_PC_LO12:
534+
case R_LARCH_TLS_DESC_LO12:
535+
case R_LARCH_TLS_DESC_PC_LO12:
513536
return true;
514537
}
515538
}
@@ -594,6 +617,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
594617
case R_LARCH_TLS_LE_LO12:
595618
case R_LARCH_TLS_IE_PC_LO12:
596619
case R_LARCH_TLS_IE_LO12:
620+
case R_LARCH_TLS_DESC_PC_LO12:
621+
case R_LARCH_TLS_DESC_LO12:
597622
write32le(loc, setK12(read32le(loc), extractBits(val, 11, 0)));
598623
return;
599624

@@ -609,6 +634,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
609634
case R_LARCH_TLS_LD_HI20:
610635
case R_LARCH_TLS_GD_PC_HI20:
611636
case R_LARCH_TLS_GD_HI20:
637+
case R_LARCH_TLS_DESC_PC_HI20:
638+
case R_LARCH_TLS_DESC_HI20:
612639
write32le(loc, setJ20(read32le(loc), extractBits(val, 31, 12)));
613640
return;
614641

@@ -620,6 +647,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
620647
case R_LARCH_TLS_LE64_LO20:
621648
case R_LARCH_TLS_IE64_PC_LO20:
622649
case R_LARCH_TLS_IE64_LO20:
650+
case R_LARCH_TLS_DESC64_PC_LO20:
651+
case R_LARCH_TLS_DESC64_LO20:
623652
write32le(loc, setJ20(read32le(loc), extractBits(val, 51, 32)));
624653
return;
625654

@@ -631,6 +660,8 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
631660
case R_LARCH_TLS_LE64_HI12:
632661
case R_LARCH_TLS_IE64_PC_HI12:
633662
case R_LARCH_TLS_IE64_HI12:
663+
case R_LARCH_TLS_DESC64_PC_HI12:
664+
case R_LARCH_TLS_DESC64_HI12:
634665
write32le(loc, setK12(read32le(loc), extractBits(val, 63, 52)));
635666
return;
636667

@@ -679,6 +710,15 @@ void LoongArch::relocate(uint8_t *loc, const Relocation &rel,
679710
case R_LARCH_RELAX:
680711
return; // Ignored (for now)
681712

713+
case R_LARCH_TLS_DESC_LD:
714+
return; // nothing to do.
715+
case R_LARCH_TLS_DESC32:
716+
write32le(loc + 4, val);
717+
return;
718+
case R_LARCH_TLS_DESC64:
719+
write64le(loc + 8, val);
720+
return;
721+
682722
default:
683723
llvm_unreachable("unknown relocation");
684724
}

lld/ELF/InputSection.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,8 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
877877
return in.got->getTlsDescAddr(sym) + a - in.gotPlt->getVA();
878878
case R_AARCH64_TLSDESC_PAGE:
879879
return getAArch64Page(in.got->getTlsDescAddr(sym) + a) - getAArch64Page(p);
880+
case R_LOONGARCH_TLSDESC_PAGE_PC:
881+
return getLoongArchPageDelta(in.got->getTlsDescAddr(sym) + a, p, type);
880882
case R_TLSGD_GOT:
881883
return in.got->getGlobalDynOffset(sym) + a;
882884
case R_TLSGD_GOTPLT:

lld/ELF/Relocations.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,18 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
12971297

12981298
if (config->emachine == EM_MIPS)
12991299
return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
1300+
1301+
// LoongArch does not yet implement transition from TLSDESC to LE/IE, so
1302+
// generate TLSDESC dynamic relocation for the dynamic linker to handle.
1303+
if (config->emachine == EM_LOONGARCH &&
1304+
oneof<R_LOONGARCH_TLSDESC_PAGE_PC, R_TLSDESC, R_TLSDESC_CALL>(expr)) {
1305+
if (expr != R_TLSDESC_CALL) {
1306+
sym.setFlags(NEEDS_TLSDESC);
1307+
c.addReloc({expr, type, offset, addend, &sym});
1308+
}
1309+
return 1;
1310+
}
1311+
13001312
bool isRISCV = config->emachine == EM_RISCV;
13011313

13021314
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,

lld/ELF/Relocations.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ enum RelExpr {
116116
R_LOONGARCH_GOT,
117117
R_LOONGARCH_GOT_PAGE_PC,
118118
R_LOONGARCH_TLSGD_PAGE_PC,
119+
R_LOONGARCH_TLSDESC_PAGE_PC,
119120
};
120121

121122
// Architecture-neutral representation of relocation.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# REQUIRES: loongarch
2+
# RUN: llvm-mc -filetype=obj -triple=loongarch64 %s -o %t.o
3+
# RUN: ld.lld -shared %t.o -o %t.so
4+
# RUN: llvm-readobj -r %t.so | FileCheck %s --check-prefix=RELA
5+
6+
## Both TLSDESC and DTPMOD64/DTPREL64 should be present.
7+
# RELA: .rela.dyn {
8+
# RELA-NEXT: 0x[[#%X,ADDR:]] R_LARCH_TLS_DESC64 a 0x0
9+
# RELA-NEXT: 0x[[#ADDR+16]] R_LARCH_TLS_DTPMOD64 a 0x0
10+
# RELA-NEXT: 0x[[#ADDR+24]] R_LARCH_TLS_DTPREL64 a 0x0
11+
# RELA-NEXT: }
12+
13+
la.tls.gd $a0,a
14+
bl %plt(__tls_get_addr)
15+
16+
la.tls.desc $a0, a
17+
add.d $a1, $a0, $tp
18+
19+
.section .tbss,"awT",@nobits
20+
.globl a
21+
.zero 8
22+
a:
23+
.zero 4

lld/test/ELF/loongarch-tlsdesc.s

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# REQUIRES: loongarch
2+
# RUN: rm -rf %t && split-file %s %t && cd %t
3+
# RUN: llvm-mc -filetype=obj -triple=loongarch64 a.s -o a.64.o
4+
# RUN: llvm-mc -filetype=obj -triple=loongarch64 c.s -o c.64.o
5+
# RUN: ld.lld -shared -soname=c.64.so c.64.o -o c.64.so
6+
# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 a.s -o a.32.o
7+
# RUN: llvm-mc -filetype=obj -triple=loongarch32 --defsym ELF32=1 c.s -o c.32.o
8+
# RUN: ld.lld -shared -soname=c.32.so c.32.o -o c.32.so
9+
10+
# RUN: ld.lld -shared -z now a.64.o c.64.o -o a.64.so
11+
# RUN: llvm-readobj -r -x .got a.64.so | FileCheck --check-prefix=GD64-RELA %s
12+
# RUN: llvm-objdump --no-show-raw-insn -h -d a.64.so | FileCheck %s --check-prefix=GD64
13+
14+
# RUN: ld.lld -shared -z now a.64.o c.64.o -o rel.64.so -z rel
15+
# RUN: llvm-readobj -r -x .got rel.64.so | FileCheck --check-prefix=GD64-REL %s
16+
17+
## FIXME: The transition frome TLSDESC to IE/LE has not yet been implemented.
18+
## Keep the dynamic relocations and hand them over to dynamic linker.
19+
20+
# RUN: ld.lld -e 0 -z now a.64.o c.64.o -o a.64.le
21+
# RUN: llvm-readobj -r -x .got a.64.le | FileCheck --check-prefix=LE64-RELA %s
22+
23+
# RUN: ld.lld -e 0 -z now a.64.o c.64.so -o a.64.ie
24+
# RUN: llvm-readobj -r -x .got a.64.ie | FileCheck --check-prefix=IE64-RELA %s
25+
26+
## 32-bit code is mostly the same. We only test a few variants.
27+
28+
# RUN: ld.lld -shared -z now a.32.o c.32.o -o rel.32.so -z rel
29+
# RUN: llvm-readobj -r -x .got rel.32.so | FileCheck --check-prefix=GD32-REL %s
30+
31+
# GD64-RELA: .rela.dyn {
32+
# GD64-RELA-NEXT: 0x20400 R_LARCH_TLS_DESC64 - 0x7FF
33+
# GD64-RELA-NEXT: 0x203E0 R_LARCH_TLS_DESC64 a 0x0
34+
# GD64-RELA-NEXT: 0x203F0 R_LARCH_TLS_DESC64 c 0x0
35+
# GD64-RELA-NEXT: }
36+
# GD64-RELA: Hex dump of section '.got':
37+
# GD64-RELA-NEXT: 0x000203e0 00000000 00000000 00000000 00000000 .
38+
# GD64-RELA-NEXT: 0x000203f0 00000000 00000000 00000000 00000000 .
39+
# GD64-RELA-NEXT: 0x00020400 00000000 00000000 00000000 00000000 .
40+
41+
# GD64-REL: .rel.dyn {
42+
# GD64-REL-NEXT: 0x203E8 R_LARCH_TLS_DESC64 -
43+
# GD64-REL-NEXT: 0x203C8 R_LARCH_TLS_DESC64 a
44+
# GD64-REL-NEXT: 0x203D8 R_LARCH_TLS_DESC64 c
45+
# GD64-REL-NEXT: }
46+
# GD64-REL: Hex dump of section '.got':
47+
# GD64-REL-NEXT: 0x000203c8 00000000 00000000 00000000 00000000 .
48+
# GD64-REL-NEXT: 0x000203d8 00000000 00000000 00000000 00000000 .
49+
# GD64-REL-NEXT: 0x000203e8 00000000 00000000 ff070000 00000000 .
50+
51+
# GD64: .got 00000030 00000000000203e0
52+
53+
## &.got[a]-. = 0x203e0 - 0x102e0: 0x10 pages, page offset 0x3e0
54+
# GD64: 102e0: pcalau12i $a0, 16
55+
# GD64-NEXT: addi.d $a0, $a0, 992
56+
# GD64-NEXT: ld.d $ra, $a0, 0
57+
# GD64-NEXT: jirl $ra, $ra, 0
58+
# GD64-NEXT: add.d $a1, $a0, $tp
59+
60+
## &.got[b]-. = 0x203e0+32 - 0x102f4: 0x10 pages, page offset 0x400
61+
# GD64: 102f4: pcalau12i $a0, 16
62+
# GD64-NEXT: addi.d $a0, $a0, 1024
63+
# GD64-NEXT: ld.d $ra, $a0, 0
64+
# GD64-NEXT: jirl $ra, $ra, 0
65+
# GD64-NEXT: add.d $a2, $a0, $tp
66+
67+
## &.got[c]-. = 0x23e0+16 - 0x10308: 0x10 pages, page offset 0x3f0
68+
# GD64: 10308: pcalau12i $a0, 16
69+
# GD64-NEXT: addi.d $a0, $a0, 1008
70+
# GD64-NEXT: ld.d $ra, $a0, 0
71+
# GD64-NEXT: jirl $ra, $ra, 0
72+
# GD64-NEXT: add.d $a3, $a0, $tp
73+
74+
# LE64-RELA: .rela.dyn {
75+
# LE64-RELA-NEXT: 0x30250 R_LARCH_TLS_DESC64 - 0x8
76+
# LE64-RELA-NEXT: 0x30260 R_LARCH_TLS_DESC64 - 0x800
77+
# LE64-RELA-NEXT: 0x30270 R_LARCH_TLS_DESC64 - 0x7FF
78+
# LE64-RELA-NEXT: }
79+
# LE64-RELA: Hex dump of section '.got':
80+
# LE64-RELA-NEXT: 0x00030250 00000000 00000000 00000000 00000000 .
81+
# LE64-RELA-NEXT: 0x00030260 00000000 00000000 00000000 00000000 .
82+
# LE64-RELA-NEXT: 0x00030270 00000000 00000000 00000000 00000000 .
83+
84+
# IE64-RELA: .rela.dyn {
85+
# IE64-RELA-NEXT: 0x303D8 R_LARCH_TLS_DESC64 - 0x8
86+
# IE64-RELA-NEXT: 0x303F8 R_LARCH_TLS_DESC64 - 0x7FF
87+
# IE64-RELA-NEXT: 0x303E8 R_LARCH_TLS_DESC64 c 0x0
88+
# IE64-RELA-NEXT: }
89+
# IE64-RELA: Hex dump of section '.got':
90+
# IE64-RELA-NEXT: 0x000303d8 00000000 00000000 00000000 00000000 .
91+
# IE64-RELA-NEXT: 0x000303e8 00000000 00000000 00000000 00000000 .
92+
# IE64-RELA-NEXT: 0x000303f8 00000000 00000000 00000000 00000000 .
93+
94+
# GD32-REL: .rel.dyn {
95+
# GD32-REL-NEXT: 0x20270 R_LARCH_TLS_DESC32 -
96+
# GD32-REL-NEXT: 0x20260 R_LARCH_TLS_DESC32 a
97+
# GD32-REL-NEXT: 0x20268 R_LARCH_TLS_DESC32 c
98+
# GD32-REL-NEXT: }
99+
# GD32-REL: Hex dump of section '.got':
100+
# GD32-REL-NEXT: 0x00020260 00000000 00000000 00000000 00000000 .
101+
# GD32-REL-NEXT: 0x00020270 00000000 ff070000 .
102+
103+
#--- a.s
104+
.macro add dst, src1, src2
105+
.ifdef ELF32
106+
add.w \dst, \src1, \src2
107+
.else
108+
add.d \dst, \src1, \src2
109+
.endif
110+
.endm
111+
112+
la.tls.desc $a0, a
113+
add $a1, $a0, $tp
114+
115+
la.tls.desc $a0, b
116+
add $a2, $a0, $tp
117+
118+
la.tls.desc $a0, c
119+
add $a3, $a0, $tp
120+
121+
.section .tbss,"awT",@nobits
122+
.globl a
123+
.zero 8
124+
a:
125+
.zero 2039 ## Place b at 0x7ff
126+
b:
127+
.zero 1
128+
129+
#--- c.s
130+
.section .tbss,"awT",@nobits
131+
.globl c
132+
c: .zero 4

0 commit comments

Comments
 (0)