[PPC64] Add support for R_PPC64_GOT_DTPREL16* relocations

The local dynamic TLS access on PPC64 ELF v2 ABI uses R_PPC64_GOT_DTPREL16*
relocations when a TLS variables falls outside 2 GB of the thread storage
block. This patch adds support for these relocations by adding a new RelExpr
called R_TLSLD_GOT_OFF which emits a got entry for the TLS variable relative
to the dynamic thread pointer using the relocation R_PPC64_DTPREL64. It then
evaluates the R_PPC64_GOT_DTPREL16* relocations as the got offset for the
R_PPC64_DTPREL64 got entries.

Differential Revision: https://reviews.llvm.org/D48484

llvm-svn: 335732
This commit is contained in:
Zaara Syeda 2018-06-27 13:55:41 +00:00
parent 5254e64a8e
commit de54f584cc
6 changed files with 80 additions and 8 deletions

View File

@ -230,6 +230,11 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
case R_PPC64_GOT_TPREL16_DS:
case R_PPC64_GOT_TPREL16_HI:
return R_GOT_OFF;
case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_GOT_DTPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_DS:
case R_PPC64_GOT_DTPREL16_HI:
return R_TLSLD_GOT_OFF;
case R_PPC64_TPREL16:
case R_PPC64_TPREL16_HA:
case R_PPC64_TPREL16_LO:
@ -312,15 +317,18 @@ static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
return {R_PPC64_ADDR16, TocBiasedVal};
case R_PPC64_TOC16_DS:
case R_PPC64_GOT_TPREL16_DS:
case R_PPC64_GOT_DTPREL16_DS:
return {R_PPC64_ADDR16_DS, TocBiasedVal};
case R_PPC64_GOT_TLSGD16_HA:
case R_PPC64_GOT_TLSLD16_HA:
case R_PPC64_GOT_TPREL16_HA:
case R_PPC64_GOT_DTPREL16_HA:
case R_PPC64_TOC16_HA:
return {R_PPC64_ADDR16_HA, TocBiasedVal};
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_GOT_DTPREL16_HI:
case R_PPC64_TOC16_HI:
return {R_PPC64_ADDR16_HI, TocBiasedVal};
case R_PPC64_GOT_TLSGD16_LO:
@ -329,6 +337,7 @@ static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
return {R_PPC64_ADDR16_LO, TocBiasedVal};
case R_PPC64_TOC16_LO_DS:
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_LO_DS:
return {R_PPC64_ADDR16_LO_DS, TocBiasedVal};
// Dynamic Thread pointer biased relocation types.
@ -434,6 +443,9 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
break;
}
case R_PPC64_DTPREL64:
write64(Loc, Val - DynamicThreadPointerOffset);
break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
}

View File

@ -503,6 +503,7 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
case R_GOT_FROM_END:
case R_RELAX_TLS_GD_TO_IE_END:
return Sym.getGotOffset() + A - InX::Got->getSize();
case R_TLSLD_GOT_OFF:
case R_GOT_OFF:
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
return Sym.getGotOffset() + A;

View File

@ -209,6 +209,23 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
return 1;
}
// Local-Dynamic sequence where offset of tls variable relative to dynamic
// thread pointer is stored in the got.
if (Expr == R_TLSLD_GOT_OFF) {
// Local-Dynamic relocs can be relaxed to local-exec
if (!Config->Shared) {
C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym});
return 1;
}
if (!Sym.isInGot()) {
InX::Got->addEntry(Sym);
uint64_t Off = Sym.getGotOffset();
InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym});
}
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT,
R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
@ -335,12 +352,13 @@ static bool isRelExpr(RelExpr Expr) {
static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
InputSectionBase &S, uint64_t RelOff) {
// These expressions always compute a constant
if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32,
R_MIPS_GOT_GP_PC, R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC,
R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT,
R_TLSGD_GOT_FROM_END, R_TLSGD_PC, R_PPC_CALL_PLT,
R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
if (isRelExprOneOf<
R_GOT_FROM_END, R_GOT_OFF, R_TLSLD_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END,
R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(
E))
return true;
// These never do, except if the entire file is position dependent or if

View File

@ -81,8 +81,9 @@ enum RelExpr {
R_TLSGD_GOT,
R_TLSGD_GOT_FROM_END,
R_TLSGD_PC,
R_TLSLD_GOT_FROM_END,
R_TLSLD_GOT,
R_TLSLD_GOT_FROM_END,
R_TLSLD_GOT_OFF,
R_TLSLD_PC,
};

View File

@ -633,7 +633,6 @@ void GotSection::writeTo(uint8_t *Buf) {
// whereas InputSectionBase::relocateAlloc() expects its argument
// to point to the start of the output section.
Target->writeGotHeader(Buf);
Buf += Target->GotHeaderEntriesNum * Target->GotEntrySize;
relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
}

View File

@ -5,12 +5,14 @@
// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=GotDisLE %s
// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
// RUN: ld.lld -shared %t.o -o %t.so
// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s
// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s
// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=GotDisBE %s
.text
.abiversion 2
@ -95,6 +97,15 @@ test_not_adjusted:
mtlr 0
blr
.globl test_got_dtprel
.p2align 4
.type test_got_dtprel,@function
test_got_dtprel:
addis 3, 2, i@got@dtprel@ha
ld 3, i@got@dtprel@l(3)
addis 3, 2, i@got@dtprel@h
addi 3, 2, i@got@dtprel
.section .debug_addr,"",@progbits
.quad i@dtprel+32768
@ -126,6 +137,10 @@ k:
// InputRelocs: R_PPC64_DTPREL16_HIGHER {{[0-9a-f]+}} k + 0
// InputRelocs: R_PPC64_DTPREL16_HI {{[0-9a-f]+}} k + 0
// InputRelocs: R_PPC64_DTPREL16_LO {{[0-9a-f]+}} k + 0
// InputRelocs: R_PPC64_GOT_DTPREL16_HA {{[0-9a-f]+}} i + 0
// InputRelocs: R_PPC64_GOT_DTPREL16_LO_DS {{[0-9a-f]+}} i + 0
// InputRelocs: R_PPC64_GOT_DTPREL16_HI {{[0-9a-f]+}} i + 0
// InputRelocs: R_PPC64_GOT_DTPREL16_DS {{[0-9a-f]+}} i + 0
// InputRelocs: Relocation section '.rela.debug_addr'
// InputRelocs: R_PPC64_DTPREL64 {{[0-9a-f]+}} i + 8000
@ -161,3 +176,29 @@ k:
// Dis: ori 4, 4, 0
// Dis: oris 4, 4, 63
// Dis: ori 4, 4, 33796
// Check for GOT entry for i. There should be a got entry which holds the offset
// of i relative to the dynamic thread pointer.
// i@dtprel -> (1024 - 0x8000) = 0xffff8400
// GotDisBE: Disassembly of section .got:
// GotDisBE: 4204f8: 00 00 00 00
// GotDisBE: 4204fc: 00 42 84 f8
// GotDisBE: 420510: ff ff ff ff
// GotDisBE: 420514: ff ff 84 00
// GotDisLE: Disassembly of section .got:
// GotDisLE: 4204f8: f8 84 42 00
// GotDisLE: 420510: 00 84 ff ff
// GotDisLE: 420514: ff ff ff ff
// Check that we have the correct offset to the got entry for i@got@dtprel
// The got entry for i is 0x420510, and the TOC pointer is 0x4284f8.
// #ha(i@got@dtprel) --> ((0x420510 - 0x4284f8 + 0x8000) >> 16) & 0xffff = 0
// #lo(i@got@dtprel) --> (0x420510 - 0x4284f8) & 0xffff = -32744
// #hi(i@got@dtprel) --> ((0x420510 - 0x4284f8) >> 16) & 0xffff = -1
// i@got@dtprel --> 0x420510 - 0x4284f8 = -32744
// Dis: test_got_dtprel:
// Dis: addis 3, 2, 0
// Dis: ld 3, -32744(3)
// Dis: addis 3, 2, -1
// Dis: addi 3, 2, -32744