forked from OSchip/llvm-project
[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:
parent
5254e64a8e
commit
de54f584cc
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue