summaryrefslogtreecommitdiffstats
path: root/lld
diff options
context:
space:
mode:
authorZaara Syeda <syzaara@ca.ibm.com>2018-06-08 17:04:09 +0000
committerZaara Syeda <syzaara@ca.ibm.com>2018-06-08 17:04:09 +0000
commit4455b3766671a8b467eccf5cb388d45d3ff0b70a (patch)
tree66ac09297e57fe279aa23dd94d8db316ff8826b9 /lld
parent89deac669441f847fb389dacab0bcdf7e7f85de2 (diff)
downloadbcm5719-llvm-4455b3766671a8b467eccf5cb388d45d3ff0b70a.tar.gz
bcm5719-llvm-4455b3766671a8b467eccf5cb388d45d3ff0b70a.zip
[PPC64] Add support for local-exec TLS model
This patch adds the relocations needed support the local-exec TLS model: R_PPC64_TPREL16 R_PPC64_TPREL16_HA R_PPC64_TPREL16_LO R_PPC64_TPREL16_HI R_PPC64_TPREL16_DS R_PPC64_TPREL16_LO_DS R_PPC64_TPREL16_HIGHER R_PPC64_TPREL16_HIGHERA R_PPC64_TPREL16_HIGHEST R_PPC64_TPREL16_HIGHESTA Differential Revision: https://reviews.llvm.org/D47598 llvm-svn: 334304
Diffstat (limited to 'lld')
-rw-r--r--lld/ELF/Arch/PPC64.cpp23
-rw-r--r--lld/ELF/InputSection.cpp17
-rw-r--r--lld/ELF/Target.h8
-rw-r--r--lld/test/ELF/ppc64-local-exec-tls.s163
4 files changed, 209 insertions, 2 deletions
diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index 1d5d9393f9c..a80aca2e366 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -79,6 +79,8 @@ PPC64::PPC64() {
GotPltHeaderEntriesNum = 2;
PltHeaderSize = 60;
NeedsThunks = true;
+ TcbSize = 8;
+ TlsTpOffset = 0x7000;
TlsModuleIndexRel = R_PPC64_DTPMOD64;
TlsOffsetRel = R_PPC64_DTPREL64;
@@ -187,6 +189,17 @@ 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_TPREL16:
+ case R_PPC64_TPREL16_HA:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_TPREL16_DS:
+ case R_PPC64_TPREL16_LO_DS:
+ case R_PPC64_TPREL16_HIGHER:
+ case R_PPC64_TPREL16_HIGHERA:
+ case R_PPC64_TPREL16_HIGHEST:
+ case R_PPC64_TPREL16_HIGHESTA:
+ return R_TLS;
case R_PPC64_TLSGD:
case R_PPC64_TLSLD:
case R_PPC64_TLS:
@@ -277,38 +290,48 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
break;
}
case R_PPC64_ADDR16:
+ case R_PPC64_TPREL16:
checkInt(Loc, Val, 16, Type);
write16(Loc, Val);
break;
case R_PPC64_ADDR16_DS:
+ case R_PPC64_TPREL16_DS:
checkInt(Loc, Val, 16, Type);
write16(Loc, (read16(Loc) & 3) | (Val & ~3));
break;
case R_PPC64_ADDR16_HA:
case R_PPC64_REL16_HA:
+ case R_PPC64_TPREL16_HA:
write16(Loc, applyPPCHa(Val));
break;
case R_PPC64_ADDR16_HI:
case R_PPC64_REL16_HI:
+ case R_PPC64_TPREL16_HI:
write16(Loc, applyPPCHi(Val));
break;
case R_PPC64_ADDR16_HIGHER:
+ case R_PPC64_TPREL16_HIGHER:
write16(Loc, applyPPCHigher(Val));
break;
case R_PPC64_ADDR16_HIGHERA:
+ case R_PPC64_TPREL16_HIGHERA:
write16(Loc, applyPPCHighera(Val));
break;
case R_PPC64_ADDR16_HIGHEST:
+ case R_PPC64_TPREL16_HIGHEST:
write16(Loc, applyPPCHighest(Val));
break;
case R_PPC64_ADDR16_HIGHESTA:
+ case R_PPC64_TPREL16_HIGHESTA:
write16(Loc, applyPPCHighesta(Val));
break;
case R_PPC64_ADDR16_LO:
case R_PPC64_REL16_LO:
+ case R_PPC64_TPREL16_LO:
write16(Loc, applyPPCLo(Val));
break;
case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_TPREL16_LO_DS:
write16(Loc, (read16(Loc) & 3) | (applyPPCLo(Val) & ~3));
break;
case R_PPC64_ADDR32:
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 09bc39eaed1..32f1f4846f7 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -618,8 +618,23 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
// statically to zero.
if (Sym.isTls() && Sym.isUndefWeak())
return 0;
- if (Target->TcbSize)
+
+ // For TLS variant 1 the TCB is a fixed size, whereas for TLS variant 2 the
+ // TCB is on unspecified size and content. Targets that implement variant 1
+ // should set TcbSize.
+ if (Target->TcbSize) {
+ // PPC64 V2 ABI has the thread pointer offset into the middle of the TLS
+ // storage area by TlsTpOffset for efficient addressing TCB and up to
+ // 4KB – 8 B of other thread library information (placed before the TCB).
+ // Subtracting this offset will get the address of the first TLS block.
+ if (Target->TlsTpOffset)
+ return Sym.getVA(A) - Target->TlsTpOffset;
+
+ // If thread pointer is not offset into the middle, the first thing in the
+ // TLS storage area is the TCB. Add the TcbSize to get the address of the
+ // first TLS block.
return Sym.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align);
+ }
return Sym.getVA(A) - Out::TlsPhdr->p_memsz;
case R_RELAX_TLS_GD_TO_LE_NEG:
case R_NEG_TLS:
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index c7d390658d0..b04e6c44bf3 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -105,9 +105,15 @@ public:
// On PPC ELF V2 abi, the first entry in the .got is the .TOC.
unsigned GotHeaderEntriesNum = 0;
- // Set to 0 for variant 2
+ // For TLS variant 1, the TCB is a fixed size specified by the Target.
+ // For variant 2, the TCB is an unspecified size.
+ // Set to 0 for variant 2.
unsigned TcbSize = 0;
+ // Set to the offset (in bytes) that the thread pointer is initialized to
+ // point to, relative to the start of the thread local storage.
+ unsigned TlsTpOffset = 0;
+
bool NeedsThunks = false;
// A 4-byte field corresponding to one or more trap instructions, used to pad
diff --git a/lld/test/ELF/ppc64-local-exec-tls.s b/lld/test/ELF/ppc64-local-exec-tls.s
new file mode 100644
index 00000000000..ff8c2b90102
--- /dev/null
+++ b/lld/test/ELF/ppc64-local-exec-tls.s
@@ -0,0 +1,163 @@
+// REQUIRES: ppc
+// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+
+ .text
+ .abiversion 2
+ .globl test_local_exec # -- Begin function test_local_exec
+ .p2align 4
+ .type test_local_exec,@function
+test_local_exec: # @test_local_exec
+.Lfunc_begin0:
+# %bb.0: # %entry
+ li 3, 0
+ stw 3, -12(1)
+ addis 3, 13, a@tprel@ha
+ addi 3, 3, a@tprel@l
+ ld 3, 0(3)
+ mr 4, 3
+ extsw 3, 4
+ blr
+ .long 0
+ .quad 0
+.Lfunc_end0:
+ .size test_local_exec, .Lfunc_end0-.Lfunc_begin0
+ # -- End function
+test_tprel:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1@ha
+ addi 2, 2, .TOC.-.Lfunc_gep1@l
+.Lfunc_lep1:
+ .localentry test_tprel, .Lfunc_lep1-.Lfunc_gep1
+ addi 3, 13, b@tprel
+ blr
+
+
+test_hi:
+.Lfunc_gep2:
+ addis 2, 12, .TOC.-.Lfunc_gep2@ha
+ addi 2, 2, .TOC.-.Lfunc_gep2@l
+.Lfunc_lep2:
+ .localentry test_hi, .Lfunc_lep2-.Lfunc_gep2
+ addis 3, 13, b@tprel@h
+ blr
+
+test_ds:
+.Lfunc_gep3:
+ addis 2, 12, .TOC.-.Lfunc_gep3@ha
+ addi 2, 2, .TOC.-.Lfunc_gep3@l
+.Lfunc_lep3:
+ .localentry test_ds, .Lfunc_lep3-.Lfunc_gep3
+ ld 3, b@tprel, 13
+ blr
+
+test_lo_ds:
+.Lfunc_gep4:
+ addis 2, 12, .TOC.-.Lfunc_gep4@ha
+ addi 2, 2, .TOC.-.Lfunc_gep4@l
+.Lfunc_lep4:
+ .localentry test_lo_ds, .Lfunc_lep4-.Lfunc_gep4
+ ld 3, b@tprel@l, 13
+ blr
+
+test_highest_a:
+.Lfunc_gep5:
+ addis 2, 12, .TOC.-.Lfunc_gep5@ha
+ addi 2, 2, .TOC.-.Lfunc_gep5@l
+.Lfunc_lep5:
+ .localentry test_highest_a, .Lfunc_lep5-.Lfunc_gep5
+ lis 4, b@tprel@highesta
+ ori 4, 4, b@tprel@highera
+ lis 5, b@tprel@ha
+ addi 5, 5, b@tprel@l
+ sldi 4, 4, 32
+ or 4, 4, 5
+ add 3, 13, 4
+ blr
+
+test_highest:
+.Lfunc_gep6:
+ addis 2, 12, .TOC.-.Lfunc_gep6@ha
+ addi 2, 2, .TOC.-.Lfunc_gep6@l
+.Lfunc_lep6:
+ .localentry test_highest, .Lfunc_lep6-.Lfunc_gep6
+ lis 4, b@tprel@highest
+ ori 4, 4, b@tprel@higher
+ sldi 4, 4, 32
+ oris 4, 4, b@tprel@h
+ ori 4, 4, b@tprel@l
+ add 3, 13, 4
+ blr
+
+ .type a,@object # @a
+ .type b,@object # @b
+ .section .tdata,"awT",@progbits
+ .p2align 3
+a:
+ .quad 55 # 0x37
+ .size a, 8
+
+b:
+ .quad 55 # 0x37
+ .size b, 8
+
+// Verify that the input has every initial-exec tls relocation type.
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_TPREL16_HA {{0+}} a + 0
+// InputRelocs: R_PPC64_TPREL16_LO {{0+}} a + 0
+// InputRelocs: R_PPC64_TPREL16 {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_HI {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_DS {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_LO_DS {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_HIGHESTA {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_HIGHERA {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_HIGHEST {{0+8}} b + 0
+// InputRelocs: R_PPC64_TPREL16_HIGHER {{0+8}} b + 0
+
+// The start of the TLS storage area is 0x7000 bytes before the thread pointer (r13).
+// We are building the address of the first TLS variable, relative to the thread pointer.
+// #ha(a@tprel) --> (0 - 0x7000 + 0x8000) >> 16 = 0
+// #lo(a@tprel)) --> (0 - 0x7000) & 0xFFFF = -0x7000 = -28672
+// Dis: test_local_exec:
+// Dis: addis 3, 13, 0
+// Dis: addi 3, 3, -28672
+
+// We are building the offset for the second TLS variable
+// Offset within tls storage - 0x7000
+// b@tprel = 8 - 0x7000 = 28664
+// Dis: test_tprel:
+// Dis: addi 3, 13, -28664
+
+// #hi(b@tprel) --> (8 - 0x7000) >> 16 = -1
+// Dis: test_hi:
+// Dis: addis 3, 13, -1
+
+// b@tprel = 8 - 0x7000 = -28664
+// Dis: test_ds:
+// Dis: ld 3, -28664(13)
+
+// #lo(b@tprel) --> (8 - 0x7000) & 0xFFFF = -28664
+// Dis: test_lo_ds:
+// Dis: ld 3, -28664(13)
+
+// #highesta(b@tprel) --> ((0x8 - 0x7000 + 0x8000) >> 48) & 0xFFFF = 0
+// #highera(b@tprel) --> ((0x8 - 0x7000 + 0x8000) >> 32) & 0xFFFF = 0
+// #ha(k@dtprel) --> ((0x8 - 0x7000 + 0x8000) >> 16) & 0xFFFF = 0
+// #lo(k@dtprel) --> ((0x8 - 0x7000) & 0xFFFF = -28664
+// Dis: test_highest_a:
+// Dis: lis 4, 0
+// Dis: ori 4, 4, 0
+// Dis: lis 5, 0
+// Dis: addi 5, 5, -28664
+
+// #highest(b@tprel) --> ((0x8 - 0x7000) >> 48) & 0xFFFF = 0xFFFF = -1
+// #higher(b@tprel) --> ((0x8 - 0x7000) >> 32) & 0xFFFF = 0xFFFF = 65535
+// #hi(k@dtprel) --> ((0x8 - 0x7000) >> 16) & 0xFFFF = 0xFFFF = 65535
+// #lo(k@dtprel) --> ((0x8 - 0x7000) & 0xFFFF = 33796
+// Dis: test_highest:
+// Dis: lis 4, -1
+// Dis: ori 4, 4, 65535
+// Dis: oris 4, 4, 65535
+// Dis: ori 4, 4, 36872
OpenPOWER on IntegriCloud