diff options
author | Zaara Syeda <syzaara@ca.ibm.com> | 2018-06-08 17:04:09 +0000 |
---|---|---|
committer | Zaara Syeda <syzaara@ca.ibm.com> | 2018-06-08 17:04:09 +0000 |
commit | 4455b3766671a8b467eccf5cb388d45d3ff0b70a (patch) | |
tree | 66ac09297e57fe279aa23dd94d8db316ff8826b9 /lld | |
parent | 89deac669441f847fb389dacab0bcdf7e7f85de2 (diff) | |
download | bcm5719-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.cpp | 23 | ||||
-rw-r--r-- | lld/ELF/InputSection.cpp | 17 | ||||
-rw-r--r-- | lld/ELF/Target.h | 8 | ||||
-rw-r--r-- | lld/test/ELF/ppc64-local-exec-tls.s | 163 |
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 |