[PPC64] Add TLS initial exec to local exec relaxation
This patch adds the target call back relaxTlsIeToLe to support TLS relaxation from initial exec to local exec model. Differential Revision: https://reviews.llvm.org/D48091 llvm-svn: 340281
This commit is contained in:
parent
06209cb466
commit
662d146c5b
|
@ -23,6 +23,32 @@ using namespace lld::elf;
|
|||
static uint64_t PPC64TocOffset = 0x8000;
|
||||
static uint64_t DynamicThreadPointerOffset = 0x8000;
|
||||
|
||||
// The instruction encoding of bits 21-30 from the ISA for the Xform and Dform
|
||||
// instructions that can be used as part of the initial exec TLS sequence.
|
||||
enum XFormOpcd {
|
||||
LBZX = 87,
|
||||
LHZX = 279,
|
||||
LWZX = 23,
|
||||
LDX = 21,
|
||||
STBX = 215,
|
||||
STHX = 407,
|
||||
STWX = 151,
|
||||
STDX = 149,
|
||||
ADD = 266,
|
||||
};
|
||||
|
||||
enum DFormOpcd {
|
||||
LBZ = 34,
|
||||
LHZ = 40,
|
||||
LWZ = 32,
|
||||
LD = 58,
|
||||
STB = 38,
|
||||
STH = 44,
|
||||
STW = 36,
|
||||
STD = 62,
|
||||
ADDI = 14
|
||||
};
|
||||
|
||||
uint64_t elf::getPPC64TocBase() {
|
||||
// The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
|
||||
// TOC starts where the first of these sections starts. We always create a
|
||||
|
@ -56,6 +82,7 @@ public:
|
|||
void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
||||
void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
||||
void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
||||
void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -212,6 +239,80 @@ void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned getDFormOp(unsigned SecondaryOp) {
|
||||
switch (SecondaryOp) {
|
||||
case LBZX:
|
||||
return LBZ;
|
||||
case LHZX:
|
||||
return LHZ;
|
||||
case LWZX:
|
||||
return LWZ;
|
||||
case LDX:
|
||||
return LD;
|
||||
case STBX:
|
||||
return STB;
|
||||
case STHX:
|
||||
return STH;
|
||||
case STWX:
|
||||
return STW;
|
||||
case STDX:
|
||||
return STD;
|
||||
case ADD:
|
||||
return ADDI;
|
||||
default:
|
||||
error("unrecognized instruction for IE to LE R_PPC64_TLS");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
|
||||
// The initial exec code sequence for a global `x` will look like:
|
||||
// Instruction Relocation Symbol
|
||||
// addis r9, r2, x@got@tprel@ha R_PPC64_GOT_TPREL16_HA x
|
||||
// ld r9, x@got@tprel@l(r9) R_PPC64_GOT_TPREL16_LO_DS x
|
||||
// add r9, r9, x@tls R_PPC64_TLS x
|
||||
|
||||
// Relaxing to local exec entails converting:
|
||||
// addis r9, r2, x@got@tprel@ha into nop
|
||||
// ld r9, x@got@tprel@l(r9) into addis r9, r13, x@tprel@ha
|
||||
// add r9, r9, x@tls into addi r9, r9, x@tprel@l
|
||||
|
||||
// x@tls R_PPC64_TLS is a relocation which does not compute anything,
|
||||
// it is replaced with r13 (thread pointer).
|
||||
|
||||
// The add instruction in the initial exec sequence has multiple variations
|
||||
// that need to be handled. If we are building an address it will use an add
|
||||
// instruction, if we are accessing memory it will use any of the X-form
|
||||
// indexed load or store instructions.
|
||||
|
||||
unsigned Offset = (Config->EKind == ELF64BEKind) ? 2 : 0;
|
||||
switch (Type) {
|
||||
case R_PPC64_GOT_TPREL16_HA:
|
||||
write32(Loc - Offset, 0x60000000); // nop
|
||||
break;
|
||||
case R_PPC64_GOT_TPREL16_LO_DS:
|
||||
case R_PPC64_GOT_TPREL16_DS: {
|
||||
uint32_t RegNo = read32(Loc - Offset) & 0x03E00000; // bits 6-10
|
||||
write32(Loc - Offset, 0x3C0D0000 | RegNo); // addis RegNo, r13
|
||||
relocateOne(Loc, R_PPC64_TPREL16_HA, Val);
|
||||
break;
|
||||
}
|
||||
case R_PPC64_TLS: {
|
||||
uint32_t PrimaryOp = (read32(Loc) & 0xFC000000) >> 26; // bits 0-5
|
||||
if (PrimaryOp != 31)
|
||||
error("unrecognized instruction for IE to LE R_PPC64_TLS");
|
||||
uint32_t SecondaryOp = (read32(Loc) & 0x000007FE) >> 1; // bits 21-30
|
||||
uint32_t DFormOp = getDFormOp(SecondaryOp);
|
||||
write32(Loc, ((DFormOp << 26) | (read32(Loc) & 0x03FFFFFF)));
|
||||
relocateOne(Loc + Offset, R_PPC64_TPREL16_LO, Val);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("unknown relocation for IE to LE");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
|
||||
const uint8_t *Loc) const {
|
||||
switch (Type) {
|
||||
|
@ -279,7 +380,7 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
|
|||
case R_PPC64_TLSLD:
|
||||
return R_TLSLD_HINT;
|
||||
case R_PPC64_TLS:
|
||||
return R_HINT;
|
||||
return R_TLSIE_HINT;
|
||||
default:
|
||||
return R_ABS;
|
||||
}
|
||||
|
|
|
@ -270,12 +270,15 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
|
|||
|
||||
// Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
|
||||
// defined.
|
||||
if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_GOT_PAGE_PC>(Expr) &&
|
||||
if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_GOT_PAGE_PC, R_GOT_OFF,
|
||||
R_TLSIE_HINT>(Expr) &&
|
||||
!Config->Shared && !Sym.IsPreemptible) {
|
||||
C.Relocations.push_back({R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Sym});
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Expr == R_TLSIE_HINT)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -358,7 +361,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
|
|||
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,
|
||||
R_TLSLD_HINT>(E))
|
||||
R_TLSLD_HINT, R_TLSIE_HINT>(E))
|
||||
return true;
|
||||
|
||||
// These never do, except if the entire file is position dependent or if
|
||||
|
|
|
@ -83,6 +83,7 @@ enum RelExpr {
|
|||
R_TLSGD_GOT,
|
||||
R_TLSGD_GOT_FROM_END,
|
||||
R_TLSGD_PC,
|
||||
R_TLSIE_HINT,
|
||||
R_TLSLD_GOT,
|
||||
R_TLSLD_GOT_FROM_END,
|
||||
R_TLSLD_GOT_OFF,
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
.text
|
||||
.abiversion 2
|
||||
.type c,@object # @c
|
||||
.section .tdata,"awT",@progbits
|
||||
.globl c
|
||||
c:
|
||||
.byte 97 # 0x61
|
||||
.size c, 1
|
||||
|
||||
.type s,@object # @s
|
||||
.globl s
|
||||
.p2align 1
|
||||
s:
|
||||
.short 55 # 0x37
|
||||
.size s, 2
|
||||
|
||||
.type i,@object # @i
|
||||
.globl i
|
||||
.p2align 2
|
||||
i:
|
||||
.long 55 # 0x37
|
||||
.size i, 4
|
||||
|
||||
.type l,@object # @l
|
||||
.globl l
|
||||
.p2align 3
|
||||
l:
|
||||
.quad 55 # 0x37
|
||||
.size l, 8
|
|
@ -0,0 +1,140 @@
|
|||
// REQUIRES: ppc
|
||||
|
||||
// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls-ie-le.s -o %t2.o
|
||||
// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o -o %t
|
||||
// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
|
||||
// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
|
||||
// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
|
||||
|
||||
// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls-ie-le.s -o %t2.o
|
||||
// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o -o %t
|
||||
// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
|
||||
// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s
|
||||
// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
|
||||
|
||||
.text
|
||||
.abiversion 2
|
||||
test1: # @test1
|
||||
addis 3, 2, c@got@tprel@ha
|
||||
ld 3, c@got@tprel@l(3)
|
||||
lbzx 3, 3, c@tls
|
||||
blr
|
||||
test2: # @test2
|
||||
addis 3, 2, s@got@tprel@ha
|
||||
ld 3, s@got@tprel@l(3)
|
||||
lhzx 3, 3, s@tls
|
||||
blr
|
||||
test3: # @test3
|
||||
addis 3, 2, i@got@tprel@ha
|
||||
ld 3, i@got@tprel@l(3)
|
||||
lwzx 3, 3, i@tls
|
||||
blr
|
||||
test4: # @test4
|
||||
addis 3, 2, l@got@tprel@ha
|
||||
ld 3, l@got@tprel@l(3)
|
||||
ldx 3, 3, l@tls
|
||||
blr
|
||||
test5: # @test5
|
||||
addis 4, 2, c@got@tprel@ha
|
||||
ld 4, c@got@tprel@l(4)
|
||||
stbx 3, 4, c@tls
|
||||
blr
|
||||
test6: # @test6
|
||||
addis 4, 2, s@got@tprel@ha
|
||||
ld 4, s@got@tprel@l(4)
|
||||
sthx 3, 4, s@tls
|
||||
blr
|
||||
test7: # @test7
|
||||
addis 4, 2, i@got@tprel@ha
|
||||
ld 4, i@got@tprel@l(4)
|
||||
stwx 3, 4, i@tls
|
||||
blr
|
||||
test8: # @test8
|
||||
addis 4, 2, l@got@tprel@ha
|
||||
ld 4, l@got@tprel@l(4)
|
||||
stdx 3, 4, l@tls
|
||||
blr
|
||||
test9: # @test9
|
||||
addis 3, 2, i@got@tprel@ha
|
||||
ld 3, i@got@tprel@l(3)
|
||||
add 3, 3, i@tls
|
||||
blr
|
||||
test_ds: # @test_ds
|
||||
ld 4, l@got@tprel(2)
|
||||
stdx 3, 4, l@tls
|
||||
blr
|
||||
|
||||
|
||||
// Verify that the input has initial-exec tls relocation types.
|
||||
// InputRelocs: Relocation section '.rela.text'
|
||||
// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} c + 0
|
||||
// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} c + 0
|
||||
// InputRelocs: R_PPC64_TLS {{0+}} c + 0
|
||||
// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} s + 0
|
||||
// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} s + 0
|
||||
// InputRelocs: R_PPC64_TLS {{0+}} s + 0
|
||||
// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} i + 0
|
||||
// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} i + 0
|
||||
// InputRelocs: R_PPC64_TLS {{0+}} i + 0
|
||||
// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} l + 0
|
||||
// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} l + 0
|
||||
// InputRelocs: R_PPC64_TLS {{0+}} l + 0
|
||||
// InputRelocs: R_PPC64_GOT_TPREL16_DS {{0+}} l + 0
|
||||
// InputRelocs: R_PPC64_TLS {{0+}} l + 0
|
||||
|
||||
// Verify that no initial-exec relocations exist for the dynamic linker.
|
||||
// OutputRelocs-NOT: R_PPC64_TPREL64 {{0+}} c + 0
|
||||
// OutputRelocs-NPT: R_PPC64_TPREL64 {{0+}} s + 0
|
||||
// OutputRelocs-NOT: R_PPC64_TPREL64 {{0+}} i + 0
|
||||
// OutputRelocs-NOT: R_PPC64_TPREL64 {{0+}} l + 0
|
||||
|
||||
// Dis: test1:
|
||||
// Dis: nop
|
||||
// Dis: addis 3, 13, 0
|
||||
// Dis: lbz 3, -28672(3)
|
||||
|
||||
// Dis: test2:
|
||||
// Dis: nop
|
||||
// Dis: addis 3, 13, 0
|
||||
// Dis: lhz 3, -28670(3)
|
||||
|
||||
// Dis: test3:
|
||||
// Dis: nop
|
||||
// Dis: addis 3, 13, 0
|
||||
// Dis: lwz 3, -28668(3)
|
||||
|
||||
// Dis: test4:
|
||||
// Dis: nop
|
||||
// Dis: addis 3, 13, 0
|
||||
// Dis: ld 3, -28664(3)
|
||||
|
||||
// Dis: test5:
|
||||
// Dis: nop
|
||||
// Dis: addis 4, 13, 0
|
||||
// Dis: stb 3, -28672(4)
|
||||
|
||||
// Dis: test6:
|
||||
// Dis: nop
|
||||
// Dis: addis 4, 13, 0
|
||||
// Dis: sth 3, -28670(4)
|
||||
|
||||
// Dis: test7:
|
||||
// Dis: nop
|
||||
// Dis: addis 4, 13, 0
|
||||
// Dis: stw 3, -28668(4)
|
||||
|
||||
// Dis: test8:
|
||||
// Dis: nop
|
||||
// Dis: addis 4, 13, 0
|
||||
// Dis: std 3, -28664(4)
|
||||
|
||||
// Dis: test9:
|
||||
// Dis: nop
|
||||
// Dis: addis 3, 13, 0
|
||||
// Dis: addi 3, 3, -28668
|
||||
|
||||
// Dis: test_ds:
|
||||
// Dis: addis 4, 13, 0
|
||||
// Dis: std 3, -28664(4)
|
Loading…
Reference in New Issue