Raland D87318 [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
This commit is contained in:
Fangrui Song 2020-10-01 12:36:08 -07:00
parent de47e7122f
commit 88f2fe5cad
3 changed files with 171 additions and 12 deletions

View File

@ -727,15 +727,38 @@ void PPC64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
writeFromHalf16(loc, 0x3c6d0000); // addis r3, r13
relocateNoSym(loc, R_PPC64_TPREL16_HA, val);
break;
case R_PPC64_TLSGD:
write32(loc, NOP);
write32(loc + 4, 0x38630000); // addi r3, r3
// Since we are relocating a half16 type relocation and Loc + 4 points to
// the start of an instruction we need to advance the buffer by an extra
// 2 bytes on BE.
relocateNoSym(loc + 4 + (config->ekind == ELF64BEKind ? 2 : 0),
R_PPC64_TPREL16_LO, val);
case R_PPC64_GOT_TLSGD_PCREL34:
// Relax from paddi r3, 0, x@got@tlsgd@pcrel, 1 to
// paddi r3, r13, x@tprel, 0
writePrefixedInstruction(loc, 0x06000000386d0000);
relocateNoSym(loc, R_PPC64_TPREL34, val);
break;
case R_PPC64_TLSGD: {
// PC Relative Relaxation:
// Relax from bl __tls_get_addr@notoc(x@tlsgd) to
// nop
// TOC Relaxation:
// Relax from bl __tls_get_addr(x@tlsgd)
// nop
// to
// nop
// addi r3, r3, x@tprel@l
const uintptr_t locAsInt = reinterpret_cast<uintptr_t>(loc);
if (locAsInt % 4 == 0) {
write32(loc, NOP); // nop
write32(loc + 4, 0x38630000); // addi r3, r3
// Since we are relocating a half16 type relocation and Loc + 4 points to
// the start of an instruction we need to advance the buffer by an extra
// 2 bytes on BE.
relocateNoSym(loc + 4 + (config->ekind == ELF64BEKind ? 2 : 0),
R_PPC64_TPREL16_LO, val);
} else if (locAsInt % 4 == 1) {
write32(loc - 1, NOP);
} else {
errorOrWarn("R_PPC64_TLSGD has unexpected byte alignment");
}
break;
}
default:
llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
}
@ -947,6 +970,8 @@ RelExpr PPC64::getRelExpr(RelType type, const Symbol &s,
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSGD16_LO:
return R_TLSGD_GOT;
case R_PPC64_GOT_TLSGD_PCREL34:
return R_TLSGD_PC;
case R_PPC64_GOT_TLSLD16:
case R_PPC64_GOT_TLSLD16_HA:
case R_PPC64_GOT_TLSLD16_HI:
@ -1261,6 +1286,7 @@ void PPC64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
break;
case R_PPC64_PCREL34:
case R_PPC64_GOT_PCREL34:
case R_PPC64_GOT_TLSGD_PCREL34:
case R_PPC64_GOT_TPREL_PCREL34:
case R_PPC64_TPREL34: {
const uint64_t si0Mask = 0x00000003ffff0000;
@ -1340,7 +1366,8 @@ RelExpr PPC64::adjustRelaxExpr(RelType type, const uint8_t *data,
if ((readPrefixedInstruction(data) & 0xfc000000) == 0xe4000000)
return R_PPC64_RELAX_GOT_PC;
}
if (expr == R_RELAX_TLS_GD_TO_IE)
if (type != R_PPC64_GOT_TLSGD_PCREL34 && expr == R_RELAX_TLS_GD_TO_IE)
return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
if (expr == R_RELAX_TLS_LD_TO_LE)
return R_RELAX_TLS_LD_TO_LE_ABS;
@ -1381,10 +1408,35 @@ void PPC64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
relocateNoSym(loc, R_PPC64_GOT_TPREL16_LO_DS, val);
return;
}
case R_PPC64_TLSGD:
write32(loc, NOP); // bl __tls_get_addr(sym@tlsgd) --> nop
write32(loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
case R_PPC64_GOT_TLSGD_PCREL34: {
// Relax from paddi r3, 0, sym@got@tlsgd@pcrel, 1 to
// pld r3, sym@got@tprel@pcrel
writePrefixedInstruction(loc, 0x04100000e4600000);
relocateNoSym(loc, R_PPC64_GOT_TPREL_PCREL34, val);
return;
}
case R_PPC64_TLSGD: {
// PC Relative Relaxation:
// Relax from bl __tls_get_addr@notoc(x@tlsgd) to
// nop
// TOC Relaxation:
// Relax from bl __tls_get_addr(x@tlsgd)
// nop
// to
// nop
// add r3, r3, r13
const uintptr_t locAsInt = reinterpret_cast<uintptr_t>(loc);
if (locAsInt % 4 == 0) {
write32(loc, NOP); // bl __tls_get_addr(sym@tlsgd) --> nop
write32(loc + 4, 0x7c636A14); // nop --> add r3, r3, r13
} else if (locAsInt % 4 == 1) {
// bl __tls_get_addr(sym@tlsgd) --> add r3, r3, r13
write32(loc - 1, 0x7c636a14);
} else {
errorOrWarn("R_PPC64_TLSGD has unexpected byte alignment");
}
return;
}
default:
llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
}

View File

@ -1357,6 +1357,19 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
if (type == R_PPC64_TOC16_LO && sym.isSection() && isa<Defined>(sym) &&
cast<Defined>(sym).section->name == ".toc")
ppc64noTocRelax.insert({&sym, addend});
if (type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) {
if (i == end) {
errorOrWarn("R_PPC64_TLSGD may not be the last relocation" +
getLocation(sec, sym, offset));
return;
}
// Offset the 4-byte aligned R_PPC64_TLSGD by one byte in the NOTOC case,
// so we can discern it later from the toc-case.
if (i->getType(/*isMips64EL=*/false) == R_PPC64_REL24_NOTOC)
++offset;
}
}
// Relax relocations.

View File

@ -0,0 +1,94 @@
# REQUIRES: ppc
# RUN: split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/asm -o %t.o
# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/defs -o %t-defs.o
# RUN: ld.lld --shared %t-defs.o --soname=t-defs -o %t-defs.so
# RUN: ld.lld -T %t/lds --shared %t.o -o %t-gd.so
# RUN: ld.lld -T %t/lds %t.o %t-defs.so -o %t-gdtoie
# RUN: ld.lld -T %t/lds %t.o %t-defs.o -o %t-gdtole
# RUN: llvm-readelf -r %t-gd.so | FileCheck %s --check-prefix=GD-RELOC
# RUN: llvm-readelf -s %t-gd.so | FileCheck %s --check-prefix=GD-SYM
# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-gd.so | FileCheck %s --check-prefix=GD
# RUN: llvm-readelf -r %t-gdtoie | FileCheck %s --check-prefix=GDTOIE-RELOC
# RUN: llvm-readelf -s %t-gdtoie | FileCheck %s --check-prefix=GDTOIE-SYM
# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-gdtoie | FileCheck %s --check-prefix=GDTOIE
# RUN: llvm-readelf -r %t-gdtole | FileCheck %s --check-prefix=GDTOLE-RELOC
# RUN: llvm-readelf -s %t-gdtole | FileCheck %s --check-prefix=GDTOLE-SYM
# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-gdtole | FileCheck %s --check-prefix=GDTOLE
## This test checks the General Dynamic PC Relative TLS implementation for lld.
## GD - General Dynamic with no relaxation possible
## GDTOIE - General Dynamic relaxed to Initial Exec
## GDTOLE - General Dynamic relaxed to Local Exec
#--- lds
SECTIONS {
.text_addr 0x1001000 : { *(.text_addr) }
}
#--- defs
.section .tbss,"awT",@nobits
.globl x
x:
.long 0
.globl y
y:
.long 0
#--- asm
# GD-RELOC: Relocation section '.rela.dyn' at offset 0x100b8 contains 4 entries:
# GD-RELOC: 0000000001001160 0000000200000044 R_PPC64_DTPMOD64 0000000000000000 x + 0
# GD-RELOC: 0000000001001168 000000020000004e R_PPC64_DTPREL64 0000000000000000 x + 0
# GD-RELOC: 0000000001001170 0000000300000044 R_PPC64_DTPMOD64 0000000000000000 y + 0
# GD-RELOC: 0000000001001178 000000030000004e R_PPC64_DTPREL64 0000000000000000 y + 0
# GD-SYM: Symbol table '.dynsym' contains 4 entries:
# GD-SYM: 2: 0000000000000000 0 TLS GLOBAL DEFAULT UND x
# GD-SYM: 3: 0000000000000000 0 TLS GLOBAL DEFAULT UND y
# GDTOIE-RELOC: Relocation section '.rela.dyn' at offset 0x{{.*}} contains 2 entries:
# GDTOIE-RELOC: 00000000010010e0 0000000200000049 R_PPC64_TPREL64 0000000000000000 x + 0
# GDTOIE-RELOC: 00000000010010e8 0000000300000049 R_PPC64_TPREL64 0000000000000000 y + 0
# GDTOIE-SYM: Symbol table '.dynsym' contains 4 entries:
# GDTOIE-SYM: 2: 0000000000000000 0 TLS GLOBAL DEFAULT UND x
# GDTOIE-SYM: 3: 0000000000000000 0 TLS GLOBAL DEFAULT UND y
# GDTOLE-RELOC: There are no relocations in this file.
# GDTOLE-SYM: Symbol table '.symtab' contains 5 entries:
# GDTOLE-SYM: 3: 0000000000000000 0 TLS GLOBAL DEFAULT 3 x
# GDTOLE-SYM: 4: 0000000000000004 0 TLS GLOBAL DEFAULT 3 y
# GD-LABEL: <GDTwoVal>:
# GD-NEXT: paddi 3, 0, 352, 1
# GD-NEXT: bl
# GD-NEXT: paddi 3, 0, 356, 1
# GD-NEXT: bl
# GD-NEXT: blr
# GDTOIE-LABEL: <GDTwoVal>:
# GDTOIE-NEXT: pld 3, 224(0), 1
# GDTOIE-NEXT: add 3, 3, 13
# GDTOIE-NEXT: pld 3, 220(0), 1
# GDTOIE-NEXT: add 3, 3, 13
# GDTOIE-NEXT: blr
# GDTOLE-LABEL: <GDTwoVal>:
# GDTOLE-NEXT: paddi 3, 13, -28672, 0
# GDTOLE-NEXT: nop
# GDTOLE-NEXT: paddi 3, 13, -28668, 0
# GDTOLE-NEXT: nop
# GDTOLE-NEXT: blr
.section .text_addr, "ax", %progbits
GDTwoVal:
paddi 3, 0, x@got@tlsgd@pcrel, 1
bl __tls_get_addr@notoc(x@tlsgd)
paddi 3, 0, y@got@tlsgd@pcrel, 1
bl __tls_get_addr@notoc(y@tlsgd)
blr