summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Fertile <sfertile@ca.ibm.com>2018-08-28 15:16:01 +0000
committerSean Fertile <sfertile@ca.ibm.com>2018-08-28 15:16:01 +0000
commit4d354e1199183887dc43b6b44ed0a5b294f04ce5 (patch)
tree81c34ad40569f0b62fe4127176c5b54ddaec94ab
parent1f334d006254331ab4e1244c35fcdf2ed53266af (diff)
downloadbcm5719-llvm-4d354e1199183887dc43b6b44ed0a5b294f04ce5.tar.gz
bcm5719-llvm-4d354e1199183887dc43b6b44ed0a5b294f04ce5.zip
[PPC64] Fix DQ-form instruction handling and emit error for misalignment.
Relanding r340564, original commit message: Fixes the handling of *_DS relocations used on DQ-form instructions where we were overwriting some of the extended opcode bits. Also adds an alignment check so that the user will receive a diagnostic error if the value we are writing is not properly aligned. Differential Revision: https://reviews.llvm.org/D51124 llvm-svn: 340832
-rw-r--r--lld/ELF/Arch/PPC64.cpp42
-rw-r--r--lld/test/ELF/ppc64-dq.s32
-rw-r--r--lld/test/ELF/ppc64-error-missaligned-dq.s26
-rw-r--r--lld/test/ELF/ppc64-error-missaligned-ds.s26
4 files changed, 119 insertions, 7 deletions
diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index cf116828dbf..803b392eb8b 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -98,6 +98,24 @@ static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; }
static uint16_t highest(uint64_t V) { return V >> 48; }
static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; }
+// Extracts the 'PO' field of an instruction encoding.
+static uint8_t getPrimaryOpCode(uint32_t Encoding) { return (Encoding >> 26); }
+
+static bool isDQFormInstruction(uint32_t Encoding) {
+ switch (getPrimaryOpCode(Encoding)) {
+ default:
+ return false;
+ case 56:
+ // The only instruction with a primary opcode of 56 is `lq`.
+ return true;
+ case 61:
+ // There are both DS and DQ instruction forms with this primary opcode.
+ // Namely `lxv` and `stxv` are the DQ-forms that use it.
+ // The DS 'XO' bits being set to 01 is restricted to DQ form.
+ return (Encoding & 3) == 0x1;
+ }
+}
+
PPC64::PPC64() {
GotRel = R_PPC64_GLOB_DAT;
PltRel = R_PPC64_JMP_SLOT;
@@ -298,7 +316,7 @@ void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
break;
}
case R_PPC64_TLS: {
- uint32_t PrimaryOp = (read32(Loc) & 0xFC000000) >> 26; // bits 0-5
+ 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
@@ -506,10 +524,15 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write16(Loc, Val);
break;
case R_PPC64_ADDR16_DS:
- case R_PPC64_TPREL16_DS:
+ case R_PPC64_TPREL16_DS: {
checkInt(Loc, Val, 16, Type);
- write16(Loc, (read16(Loc) & 3) | (Val & ~3));
- break;
+ // DQ-form instructions use bits 28-31 as part of the instruction encoding
+ // DS-form instructions only use bits 30-31.
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
+ uint16_t Mask = isDQFormInstruction(read32(Loc - EndianOffset)) ? 0xF : 0x3;
+ checkAlignment(Loc, lo(Val), Mask + 1, Type);
+ write16(Loc, (read16(Loc) & Mask) | lo(Val));
+ } break;
case R_PPC64_ADDR16_HA:
case R_PPC64_REL16_HA:
case R_PPC64_TPREL16_HA:
@@ -542,9 +565,14 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write16(Loc, lo(Val));
break;
case R_PPC64_ADDR16_LO_DS:
- case R_PPC64_TPREL16_LO_DS:
- write16(Loc, (read16(Loc) & 3) | (lo(Val) & ~3));
- break;
+ case R_PPC64_TPREL16_LO_DS: {
+ // DQ-form instructions use bits 28-31 as part of the instruction encoding
+ // DS-form instructions only use bits 30-31.
+ uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
+ uint16_t Mask = isDQFormInstruction(read32(Loc - EndianOffset)) ? 0xF : 0x3;
+ checkAlignment(Loc, lo(Val), Mask + 1, Type);
+ write16(Loc, (read16(Loc) & Mask) | lo(Val));
+ } break;
case R_PPC64_ADDR32:
case R_PPC64_REL32:
checkInt(Loc, Val, 32, Type);
diff --git a/lld/test/ELF/ppc64-dq.s b/lld/test/ELF/ppc64-dq.s
new file mode 100644
index 00000000000..0fb8441a2d0
--- /dev/null
+++ b/lld/test/ELF/ppc64-dq.s
@@ -0,0 +1,32 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump -D %t | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump -D %t | FileCheck %s
+
+ .global test
+ .p2align 4
+ .type test,@function
+test:
+.Lgep:
+ addis 2, 12, .TOC.-.Lgep@ha
+ addi 2, 2, .TOC.-.Lgep@l
+.Llep:
+ .localentry test, .Llep-.Lgep
+ addis 3, 2, qword@toc@ha
+ lxv 3, qword@toc@l(3)
+ addis 3, 2, qword@toc@ha
+ stxv 3, qword@toc@l(3)
+ blr
+
+ .comm qword, 16, 16
+
+# Verify that we don't overwrite any of the extended opcode bits on a DQ form
+# instruction.
+# CHECK-LABEL: test
+# CHECK: lxv 3, -32768(3)
+# CHECK: stxv 3, -32768(3)
diff --git a/lld/test/ELF/ppc64-error-missaligned-dq.s b/lld/test/ELF/ppc64-error-missaligned-dq.s
new file mode 100644
index 00000000000..ea30ab88fb8
--- /dev/null
+++ b/lld/test/ELF/ppc64-error-missaligned-dq.s
@@ -0,0 +1,26 @@
+# REQUIRES: ppc
+#
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+# CHECK: improper alignment for relocation R_PPC64_ADDR16_LO_DS: 0x8001 is not aligned to 16 bytes
+
+ .global test
+ .p2align 4
+ .type test,@function
+test:
+.Lgep:
+ addis 2, 12, .TOC.-.Lgep@ha
+ addi 2, 2, .TOC.-.Lgep@l
+.Llep:
+ .localentry test, .Llep-.Lgep
+ addis 3, 2, qword@toc@ha
+ lxv 3, qword@toc@l(3)
+ blr
+
+ .comm pad, 1, 1
+ .comm qword, 16, 1
+
diff --git a/lld/test/ELF/ppc64-error-missaligned-ds.s b/lld/test/ELF/ppc64-error-missaligned-ds.s
new file mode 100644
index 00000000000..99a2c08bc99
--- /dev/null
+++ b/lld/test/ELF/ppc64-error-missaligned-ds.s
@@ -0,0 +1,26 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+# CHECK: improper alignment for relocation R_PPC64_ADDR16_LO_DS: 0x8001 is not aligned to 4 bytes
+
+ .global test
+ .p2align 4
+ .type test,@function
+test:
+.Lgep:
+ addis 2, 12, .TOC.-.Lgep@ha
+ addi 2, 2, .TOC.-.Lgep@l
+.Llep:
+ .localentry test, .Llep-.Lgep
+ addis 3, 2, word@toc@ha
+ lwa 3, word@toc@l(3)
+ blr
+
+ .comm pad, 1, 1
+ .comm word, 4, 1
+
OpenPOWER on IntegriCloud