aboutsummaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
Diffstat (limited to 'lld')
-rw-r--r--lld/ELF/Arch/PPC64.cpp53
-rw-r--r--lld/test/ELF/ppc64-tls-pcrel-ie.s126
2 files changed, 170 insertions, 9 deletions
diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index 5225463..e367535 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -840,16 +840,49 @@ void PPC64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
relocateNoSym(loc, R_PPC64_TPREL16_HA, val);
break;
}
+ case R_PPC64_GOT_TPREL_PCREL34: {
+ const uint64_t pldRT = readPrefixedInstruction(loc) & 0x0000000003e00000;
+ // paddi RT(from pld), r13, symbol@tprel, 0
+ writePrefixedInstruction(loc, 0x06000000380d0000 | pldRT);
+ relocateNoSym(loc, R_PPC64_TPREL34, val);
+ break;
+ }
case R_PPC64_TLS: {
- uint32_t primaryOp = getPrimaryOpCode(read32(loc));
- 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 = getPPCDFormOp(secondaryOp);
- if (dFormOp == 0)
- error("unrecognized instruction for IE to LE R_PPC64_TLS");
- write32(loc, ((dFormOp << 26) | (read32(loc) & 0x03FFFFFF)));
- relocateNoSym(loc + offset, R_PPC64_TPREL16_LO, val);
+ const uintptr_t locAsInt = reinterpret_cast<uintptr_t>(loc);
+ if (locAsInt % 4 == 0) {
+ uint32_t primaryOp = getPrimaryOpCode(read32(loc));
+ 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 = getPPCDFormOp(secondaryOp);
+ if (dFormOp == 0)
+ error("unrecognized instruction for IE to LE R_PPC64_TLS");
+ write32(loc, ((dFormOp << 26) | (read32(loc) & 0x03FFFFFF)));
+ relocateNoSym(loc + offset, R_PPC64_TPREL16_LO, val);
+ } else if (locAsInt % 4 == 1) {
+ // If the offset is not 4 byte aligned then we have a PCRel type reloc.
+ // This version of the relocation is offset by one byte from the
+ // instruction it references.
+ uint32_t tlsInstr = read32(loc - 1);
+ uint32_t primaryOp = getPrimaryOpCode(tlsInstr);
+ if (primaryOp != 31)
+ errorOrWarn("unrecognized instruction for IE to LE R_PPC64_TLS");
+ uint32_t secondaryOp = (tlsInstr & 0x000007FE) >> 1; // bits 21-30
+ // The add is a special case and should be turned into a nop. The paddi
+ // that comes before it will already have computed the address of the
+ // symbol.
+ if (secondaryOp == 266) {
+ write32(loc - 1, NOP);
+ } else {
+ uint32_t dFormOp = getPPCDFormOp(secondaryOp);
+ if (dFormOp == 0)
+ errorOrWarn("unrecognized instruction for IE to LE R_PPC64_TLS");
+ write32(loc - 1, ((dFormOp << 26) | (tlsInstr & 0x03FF0000)));
+ }
+ } else {
+ errorOrWarn("R_PPC64_TLS must be either 4 byte aligned or one byte "
+ "offset from 4 byte aligned");
+ }
break;
}
default:
@@ -889,6 +922,7 @@ RelExpr PPC64::getRelExpr(RelType type, const Symbol &s,
case R_PPC64_TOC16_LO:
return R_GOTREL;
case R_PPC64_GOT_PCREL34:
+ case R_PPC64_GOT_TPREL_PCREL34:
case R_PPC64_PCREL_OPT:
return R_GOT_PC;
case R_PPC64_TOC16_HA:
@@ -1237,6 +1271,7 @@ void PPC64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
break;
}
case R_PPC64_GOT_PCREL34:
+ case R_PPC64_GOT_TPREL_PCREL34:
case R_PPC64_TPREL34: {
const uint64_t si0Mask = 0x00000003ffff0000;
const uint64_t si1Mask = 0x000000000000ffff;
diff --git a/lld/test/ELF/ppc64-tls-pcrel-ie.s b/lld/test/ELF/ppc64-tls-pcrel-ie.s
new file mode 100644
index 0000000..93a286a
--- /dev/null
+++ b/lld/test/ELF/ppc64-tls-pcrel-ie.s
@@ -0,0 +1,126 @@
+# REQUIRES: ppc
+
+# RUN: split-file %s %t
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/asm -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le %t/defs -o %t-defs.o
+# RUN: ld.lld --shared %t-defs.o --soname=t-defs -o %t-defs.so
+# RUN: ld.lld -T %t/lds %t.o %t-defs.so -o %t-ie
+# RUN: ld.lld -T %t/lds %t.o %t-defs.o -o %t-le
+
+# RUN: llvm-readelf -r %t-ie | FileCheck %s --check-prefix=IE-RELOC
+# RUN: llvm-readelf -s %t-ie | FileCheck %s --check-prefix=IE-SYM
+# RUN: llvm-readelf -x .got %t-ie | FileCheck %s --check-prefix=IE-GOT
+# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-ie | FileCheck %s --check-prefix=IE
+
+# RUN: llvm-readelf -r %t-le | FileCheck %s --check-prefix=LE-RELOC
+# RUN: llvm-readelf -s %t-le | FileCheck %s --check-prefix=LE-SYM
+# RUN: llvm-readelf -x .got %t-le 2>&1 | FileCheck %s --check-prefix=LE-GOT
+# RUN: llvm-objdump -d --no-show-raw-insn --mcpu=pwr10 %t-le | FileCheck %s --check-prefix=LE
+
+## This test checks the Initial Exec PC Relative TLS implementation.
+## The IE version checks that the relocations are generated correctly.
+## The LE version checks that the Initial Exec to Local Exec relaxation is
+## done correctly.
+
+#--- lds
+SECTIONS {
+ .text_addr 0x1001000 : { *(.text_addr) }
+ .text_val 0x1002000 : { *(.text_val) }
+ .text_twoval 0x1003000 : { *(.text_twoval) }
+ .text_incrval 0x1004000 : { *(.text_incrval) }
+}
+
+#--- defs
+.section .tbss,"awT",@nobits
+.globl x
+x:
+ .long 0
+.globl y
+y:
+ .long 0
+
+#--- asm
+# IE-RELOC: Relocation section '.rela.dyn' at offset 0x10090 contains 2 entries:
+# IE-RELOC: 00000000010040d8 0000000100000049 R_PPC64_TPREL64 0000000000000000 x + 0
+# IE-RELOC: 00000000010040e0 0000000200000049 R_PPC64_TPREL64 0000000000000000 y + 0
+
+# IE-SYM: Symbol table '.dynsym' contains 3 entries:
+# IE-SYM: 1: 0000000000000000 0 TLS GLOBAL DEFAULT UND x
+# IE-SYM: 2: 0000000000000000 0 TLS GLOBAL DEFAULT UND y
+
+# IE-GOT: Hex dump of section '.got':
+# IE-GOT-NEXT: 0x010040d8 d8c00001 00000000 00000000 00000000
+
+# LE-RELOC: There are no relocations in this file.
+
+# LE-SYM: Symbol table '.symtab' contains 7 entries:
+# LE-SYM: 5: 0000000000000000 0 TLS GLOBAL DEFAULT 6 x
+# LE-SYM: 6: 0000000000000004 0 TLS GLOBAL DEFAULT 6 y
+
+# LE-GOT: could not find section '.got'
+
+# IE-LABEL: <IEAddr>:
+# IE-NEXT: pld 3, 12504(0), 1
+# IE-NEXT: add 3, 3, 13
+# IE-NEXT: blr
+# LE-LABEL: <IEAddr>:
+# LE-NEXT: paddi 3, 13, -28672, 0
+# LE-NEXT: nop
+# LE-NEXT: blr
+.section .text_addr, "ax", %progbits
+IEAddr:
+ pld 3, x@got@tprel@pcrel(0), 1
+ add 3, 3, x@tls@pcrel
+ blr
+
+# IE-LABEL: <IEVal>:
+# IE-NEXT: pld 3, 8408(0), 1
+# IE-NEXT: lwzx 3, 3, 13
+# IE-NEXT: blr
+# LE-LABEL: <IEVal>:
+# LE-NEXT: paddi 3, 13, -28672, 0
+# LE-NEXT: lwz 3, 0(3)
+# LE-NEXT: blr
+.section .text_val, "ax", %progbits
+IEVal:
+ pld 3, x@got@tprel@pcrel(0), 1
+ lwzx 3, 3, x@tls@pcrel
+ blr
+
+# IE-LABEL: <IETwoVal>:
+# IE-NEXT: pld 3, 4312(0), 1
+# IE-NEXT: pld 4, 4312(0), 1
+# IE-NEXT: lwzx 3, 3, 13
+# IE-NEXT: lwzx 4, 4, 13
+# IE-NEXT: blr
+# LE-LABEL: <IETwoVal>:
+# LE-NEXT: paddi 3, 13, -28672, 0
+# LE-NEXT: paddi 4, 13, -28668, 0
+# LE-NEXT: lwz 3, 0(3)
+# LE-NEXT: lwz 4, 0(4)
+# LE-NEXT: blr
+.section .text_twoval, "ax", %progbits
+IETwoVal:
+ pld 3, x@got@tprel@pcrel(0), 1
+ pld 4, y@got@tprel@pcrel(0), 1
+ lwzx 3, 3, x@tls@pcrel
+ lwzx 4, 4, y@tls@pcrel
+ blr
+
+# IE-LABEL: <IEIncrementVal>:
+# IE-NEXT: pld 4, 224(0), 1
+# IE-NEXT: lwzx 3, 4, 13
+# IE-NEXT: stwx 3, 4, 13
+# IE-NEXT: blr
+# LE-LABEL: <IEIncrementVal>:
+# LE-NEXT: paddi 4, 13, -28668, 0
+# LE-NEXT: lwz 3, 0(4)
+# LE-NEXT: stw 3, 0(4)
+# LE-NEXT: blr
+.section .text_incrval, "ax", %progbits
+IEIncrementVal:
+ pld 4, y@got@tprel@pcrel(0), 1
+ lwzx 3, 4, y@tls@pcrel
+ stwx 3, 4, y@tls@pcrel
+ blr