Skip to content

Commit 7912286

Browse files
[LLD][PowerPC] Add support for R_PPC64_GOT_TLSGD_PCREL34 used in TLS General Dynamic
Add Thread Local Storage support for the 34 bit relocation R_PPC64_GOT_TLSGD_PCREL34 used in General Dynamic. The compiler will produce code that looks like: ``` pla r3, x@got@tlsgd@pcrel R_PPC64_GOT_TLSGD_PCREL34 bl __tls_get_addr@notoc(x@tlsgd) R_PPC64_TLSGD R_PPC64_REL24_NOTOC ``` LLD should be able to correctly compute the relocation for R_PPC64_GOT_TLSGD_PCREL34 as well as do the following two relaxations where possible: General Dynamic to Local Exec: ``` paddi r3, r13, x@tprel nop ``` and General Dynamic to Initial Exec: ``` pld r3, x@got@tprel@pcrel add r3, r3, r13 ``` Note: This patch adds support for the PC Relative (no TOC) version of General Dynamic on top of the existing support for the TOC version of General Dynamic. The ABI does not provide any way to tell by looking only at the relocation `R_PPC64_TLSGD` when it is being used in a TOC instruction sequence or and when it is being used in a no TOC sequence. The TOC sequence should always be 4 byte aligned. This patch adds one to the offset of the relocation when it is being used in a no TOC sequence. In this way LLD can tell by looking at the alignment of the offset of `R_PPC64_TLSGD` whether or not it is being used as part of a TOC or no TOC sequence. Reviewed By: NeHuang, sfertile, MaskRay Differential Revision: https://reviews.llvm.org/D87318
1 parent c1b209c commit 7912286

File tree

3 files changed

+171
-12
lines changed

3 files changed

+171
-12
lines changed

lld/ELF/Arch/PPC64.cpp

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -727,15 +727,38 @@ void PPC64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
727727
writeFromHalf16(loc, 0x3c6d0000); // addis r3, r13
728728
relocateNoSym(loc, R_PPC64_TPREL16_HA, val);
729729
break;
730-
case R_PPC64_TLSGD:
731-
write32(loc, NOP);
732-
write32(loc + 4, 0x38630000); // addi r3, r3
733-
// Since we are relocating a half16 type relocation and Loc + 4 points to
734-
// the start of an instruction we need to advance the buffer by an extra
735-
// 2 bytes on BE.
736-
relocateNoSym(loc + 4 + (config->ekind == ELF64BEKind ? 2 : 0),
737-
R_PPC64_TPREL16_LO, val);
730+
case R_PPC64_GOT_TLSGD_PCREL34:
731+
// Relax from paddi r3, 0, x@got@tlsgd@pcrel, 1 to
732+
// paddi r3, r13, x@tprel, 0
733+
writePrefixedInstruction(loc, 0x06000000386d0000);
734+
relocateNoSym(loc, R_PPC64_TPREL34, val);
735+
break;
736+
case R_PPC64_TLSGD: {
737+
// PC Relative Relaxation:
738+
// Relax from bl __tls_get_addr@notoc(x@tlsgd) to
739+
// nop
740+
// TOC Relaxation:
741+
// Relax from bl __tls_get_addr(x@tlsgd)
742+
// nop
743+
// to
744+
// nop
745+
// addi r3, r3, x@tprel@l
746+
const uintptr_t locAsInt = reinterpret_cast<uintptr_t>(loc);
747+
if (locAsInt % 4 == 0) {
748+
write32(loc, NOP); // nop
749+
write32(loc + 4, 0x38630000); // addi r3, r3
750+
// Since we are relocating a half16 type relocation and Loc + 4 points to
751+
// the start of an instruction we need to advance the buffer by an extra
752+
// 2 bytes on BE.
753+
relocateNoSym(loc + 4 + (config->ekind == ELF64BEKind ? 2 : 0),
754+
R_PPC64_TPREL16_LO, val);
755+
} else if (locAsInt % 4 == 1) {
756+
write32(loc - 1, NOP);
757+
} else {
758+
errorOrWarn("R_PPC64_TLSGD has unexpected byte alignment");
759+
}
738760
break;
761+
}
739762
default:
740763
llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
741764
}
@@ -947,6 +970,8 @@ RelExpr PPC64::getRelExpr(RelType type, const Symbol &s,
947970
case R_PPC64_GOT_TLSGD16_HI:
948971
case R_PPC64_GOT_TLSGD16_LO:
949972
return R_TLSGD_GOT;
973+
case R_PPC64_GOT_TLSGD_PCREL34:
974+
return R_TLSGD_PC;
950975
case R_PPC64_GOT_TLSLD16:
951976
case R_PPC64_GOT_TLSLD16_HA:
952977
case R_PPC64_GOT_TLSLD16_HI:
@@ -1261,6 +1286,7 @@ void PPC64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
12611286
break;
12621287
case R_PPC64_PCREL34:
12631288
case R_PPC64_GOT_PCREL34:
1289+
case R_PPC64_GOT_TLSGD_PCREL34:
12641290
case R_PPC64_GOT_TPREL_PCREL34:
12651291
case R_PPC64_TPREL34: {
12661292
const uint64_t si0Mask = 0x00000003ffff0000;
@@ -1340,7 +1366,8 @@ RelExpr PPC64::adjustRelaxExpr(RelType type, const uint8_t *data,
13401366
if ((readPrefixedInstruction(data) & 0xfc000000) == 0xe4000000)
13411367
return R_PPC64_RELAX_GOT_PC;
13421368
}
1343-
if (expr == R_RELAX_TLS_GD_TO_IE)
1369+
1370+
if (type != R_PPC64_GOT_TLSGD_PCREL34 && expr == R_RELAX_TLS_GD_TO_IE)
13441371
return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
13451372
if (expr == R_RELAX_TLS_LD_TO_LE)
13461373
return R_RELAX_TLS_LD_TO_LE_ABS;
@@ -1381,10 +1408,35 @@ void PPC64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
13811408
relocateNoSym(loc, R_PPC64_GOT_TPREL16_LO_DS, val);
13821409
return;
13831410
}
1384-
case R_PPC64_TLSGD:
1385-
write32(loc, NOP); // bl __tls_get_addr(sym@tlsgd) --> nop
1386-
write32(loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
1411+
case R_PPC64_GOT_TLSGD_PCREL34: {
1412+
// Relax from paddi r3, 0, sym@got@tlsgd@pcrel, 1 to
1413+
// pld r3, sym@got@tprel@pcrel
1414+
writePrefixedInstruction(loc, 0x04100000e4600000);
1415+
relocateNoSym(loc, R_PPC64_GOT_TPREL_PCREL34, val);
1416+
return;
1417+
}
1418+
case R_PPC64_TLSGD: {
1419+
// PC Relative Relaxation:
1420+
// Relax from bl __tls_get_addr@notoc(x@tlsgd) to
1421+
// nop
1422+
// TOC Relaxation:
1423+
// Relax from bl __tls_get_addr(x@tlsgd)
1424+
// nop
1425+
// to
1426+
// nop
1427+
// add r3, r3, r13
1428+
const uintptr_t locAsInt = reinterpret_cast<uintptr_t>(loc);
1429+
if (locAsInt % 4 == 0) {
1430+
write32(loc, NOP); // bl __tls_get_addr(sym@tlsgd) --> nop
1431+
write32(loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
1432+
} else if (locAsInt % 4 == 1) {
1433+
// bl __tls_get_addr(sym@tlsgd) --> add r3, r3, r13
1434+
write32(loc - 1, 0x7c636a14);
1435+
} else {
1436+
errorOrWarn("R_PPC64_TLSGD has unexpected byte alignment");
1437+
}
13871438
return;
1439+
}
13881440
default:
13891441
llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
13901442
}

lld/ELF/Relocations.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,6 +1357,19 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
13571357
if (type == R_PPC64_TOC16_LO && sym.isSection() && isa<Defined>(sym) &&
13581358
cast<Defined>(sym).section->name == ".toc")
13591359
ppc64noTocRelax.insert({&sym, addend});
1360+
1361+
if (type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) {
1362+
if (i == end) {
1363+
errorOrWarn("R_PPC64_TLSGD may not be the last relocation" +
1364+
getLocation(sec, sym, offset));
1365+
return;
1366+
}
1367+
1368+
// Offset the 4-byte aligned R_PPC64_TLSGD by one byte in the NOTOC case,
1369+
// so we can discern it later from the toc-case.
1370+
if (i->getType(/*isMips64EL=*/false) == R_PPC64_REL24_NOTOC)
1371+
++offset;
1372+
}
13601373
}
13611374

13621375
// Relax relocations.

lld/test/ELF/ppc64-tls-pcrel-gd.s

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# REQUIRES: ppc
2+
# RUN: split-file %s %t
3+
4+
# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/asm -o %t.o
5+
# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/defs -o %t-defs.o
6+
# RUN: ld.lld --shared %t-defs.o -o %t-defs.so
7+
# RUN: ld.lld -T %t/lds --shared %t.o -o %t-gd.so
8+
# RUN: ld.lld -T %t/lds %t.o %t-defs.so -o %t-gdtoie
9+
# RUN: ld.lld -T %t/lds %t.o %t-defs.o -o %t-gdtole
10+
11+
# RUN: llvm-readelf -r %t-gd.so | FileCheck %s --check-prefix=GD-RELOC
12+
# RUN: llvm-readelf -s %t-gd.so | FileCheck %s --check-prefix=GD-SYM
13+
# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-gd.so | FileCheck %s --check-prefix=GD
14+
15+
# RUN: llvm-readelf -r %t-gdtoie | FileCheck %s --check-prefix=GDTOIE-RELOC
16+
# RUN: llvm-readelf -s %t-gdtoie | FileCheck %s --check-prefix=GDTOIE-SYM
17+
# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-gdtoie | FileCheck %s --check-prefix=GDTOIE
18+
19+
# RUN: llvm-readelf -r %t-gdtole | FileCheck %s --check-prefix=GDTOLE-RELOC
20+
# RUN: llvm-readelf -s %t-gdtole | FileCheck %s --check-prefix=GDTOLE-SYM
21+
# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-gdtole | FileCheck %s --check-prefix=GDTOLE
22+
23+
## This test checks the General Dynamic PC Relative TLS implementation for lld.
24+
## GD - General Dynamic with no relaxation possible
25+
## GDTOIE - General Dynamic relaxed to Initial Exec
26+
## GDTOLE - General Dynamic relaxed to Local Exec
27+
28+
#--- lds
29+
SECTIONS {
30+
.text_addr 0x1001000 : { *(.text_addr) }
31+
}
32+
33+
#--- defs
34+
.section .tbss,"awT",@nobits
35+
.globl x
36+
x:
37+
.long 0
38+
.globl y
39+
y:
40+
.long 0
41+
42+
#--- asm
43+
44+
# GD-RELOC: Relocation section '.rela.dyn' at offset 0x100b8 contains 4 entries:
45+
# GD-RELOC: 0000000001001160 0000000200000044 R_PPC64_DTPMOD64 0000000000000000 x + 0
46+
# GD-RELOC: 0000000001001168 000000020000004e R_PPC64_DTPREL64 0000000000000000 x + 0
47+
# GD-RELOC: 0000000001001170 0000000300000044 R_PPC64_DTPMOD64 0000000000000000 y + 0
48+
# GD-RELOC: 0000000001001178 000000030000004e R_PPC64_DTPREL64 0000000000000000 y + 0
49+
50+
# GD-SYM: Symbol table '.dynsym' contains 4 entries:
51+
# GD-SYM: 2: 0000000000000000 0 TLS GLOBAL DEFAULT UND x
52+
# GD-SYM: 3: 0000000000000000 0 TLS GLOBAL DEFAULT UND y
53+
54+
55+
# GDTOIE-RELOC: Relocation section '.rela.dyn' at offset 0x10118 contains 2 entries:
56+
# GDTOIE-RELOC: 00000000010010e0 0000000200000049 R_PPC64_TPREL64 0000000000000000 x + 0
57+
# GDTOIE-RELOC: 00000000010010e8 0000000300000049 R_PPC64_TPREL64 0000000000000000 y + 0
58+
59+
# GDTOIE-SYM: Symbol table '.dynsym' contains 4 entries:
60+
# GDTOIE-SYM: 2: 0000000000000000 0 TLS GLOBAL DEFAULT UND x
61+
# GDTOIE-SYM: 3: 0000000000000000 0 TLS GLOBAL DEFAULT UND y
62+
63+
64+
# GDTOLE-RELOC: There are no relocations in this file.
65+
66+
# GDTOLE-SYM: Symbol table '.symtab' contains 5 entries:
67+
# GDTOLE-SYM: 3: 0000000000000000 0 TLS GLOBAL DEFAULT 3 x
68+
# GDTOLE-SYM: 4: 0000000000000004 0 TLS GLOBAL DEFAULT 3 y
69+
70+
# GD-LABEL: <GDTwoVal>:
71+
# GD-NEXT: paddi 3, 0, 352, 1
72+
# GD-NEXT: bl
73+
# GD-NEXT: paddi 3, 0, 356, 1
74+
# GD-NEXT: bl
75+
# GD-NEXT: blr
76+
# GDTOIE-LABEL: <GDTwoVal>:
77+
# GDTOIE-NEXT: pld 3, 224(0), 1
78+
# GDTOIE-NEXT: add 3, 3, 13
79+
# GDTOIE-NEXT: pld 3, 220(0), 1
80+
# GDTOIE-NEXT: add 3, 3, 13
81+
# GDTOIE-NEXT: blr
82+
# GDTOLE-LABEL: <GDTwoVal>:
83+
# GDTOLE-NEXT: paddi 3, 13, -28672, 0
84+
# GDTOLE-NEXT: nop
85+
# GDTOLE-NEXT: paddi 3, 13, -28668, 0
86+
# GDTOLE-NEXT: nop
87+
# GDTOLE-NEXT: blr
88+
.section .text_addr, "ax", %progbits
89+
GDTwoVal:
90+
paddi 3, 0, x@got@tlsgd@pcrel, 1
91+
bl __tls_get_addr@notoc(x@tlsgd)
92+
paddi 3, 0, y@got@tlsgd@pcrel, 1
93+
bl __tls_get_addr@notoc(y@tlsgd)
94+
blr

0 commit comments

Comments
 (0)