Skip to content

Commit 4d354e1

Browse files
author
Sean Fertile
committedAug 28, 2018
[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
1 parent 1f334d0 commit 4d354e1

File tree

4 files changed

+119
-7
lines changed

4 files changed

+119
-7
lines changed
 

‎lld/ELF/Arch/PPC64.cpp

+35-7
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,24 @@ static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; }
9898
static uint16_t highest(uint64_t V) { return V >> 48; }
9999
static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; }
100100

101+
// Extracts the 'PO' field of an instruction encoding.
102+
static uint8_t getPrimaryOpCode(uint32_t Encoding) { return (Encoding >> 26); }
103+
104+
static bool isDQFormInstruction(uint32_t Encoding) {
105+
switch (getPrimaryOpCode(Encoding)) {
106+
default:
107+
return false;
108+
case 56:
109+
// The only instruction with a primary opcode of 56 is `lq`.
110+
return true;
111+
case 61:
112+
// There are both DS and DQ instruction forms with this primary opcode.
113+
// Namely `lxv` and `stxv` are the DQ-forms that use it.
114+
// The DS 'XO' bits being set to 01 is restricted to DQ form.
115+
return (Encoding & 3) == 0x1;
116+
}
117+
}
118+
101119
PPC64::PPC64() {
102120
GotRel = R_PPC64_GLOB_DAT;
103121
PltRel = R_PPC64_JMP_SLOT;
@@ -298,7 +316,7 @@ void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
298316
break;
299317
}
300318
case R_PPC64_TLS: {
301-
uint32_t PrimaryOp = (read32(Loc) & 0xFC000000) >> 26; // bits 0-5
319+
uint32_t PrimaryOp = getPrimaryOpCode(read32(Loc));
302320
if (PrimaryOp != 31)
303321
error("unrecognized instruction for IE to LE R_PPC64_TLS");
304322
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 {
506524
write16(Loc, Val);
507525
break;
508526
case R_PPC64_ADDR16_DS:
509-
case R_PPC64_TPREL16_DS:
527+
case R_PPC64_TPREL16_DS: {
510528
checkInt(Loc, Val, 16, Type);
511-
write16(Loc, (read16(Loc) & 3) | (Val & ~3));
512-
break;
529+
// DQ-form instructions use bits 28-31 as part of the instruction encoding
530+
// DS-form instructions only use bits 30-31.
531+
uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
532+
uint16_t Mask = isDQFormInstruction(read32(Loc - EndianOffset)) ? 0xF : 0x3;
533+
checkAlignment(Loc, lo(Val), Mask + 1, Type);
534+
write16(Loc, (read16(Loc) & Mask) | lo(Val));
535+
} break;
513536
case R_PPC64_ADDR16_HA:
514537
case R_PPC64_REL16_HA:
515538
case R_PPC64_TPREL16_HA:
@@ -542,9 +565,14 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
542565
write16(Loc, lo(Val));
543566
break;
544567
case R_PPC64_ADDR16_LO_DS:
545-
case R_PPC64_TPREL16_LO_DS:
546-
write16(Loc, (read16(Loc) & 3) | (lo(Val) & ~3));
547-
break;
568+
case R_PPC64_TPREL16_LO_DS: {
569+
// DQ-form instructions use bits 28-31 as part of the instruction encoding
570+
// DS-form instructions only use bits 30-31.
571+
uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U;
572+
uint16_t Mask = isDQFormInstruction(read32(Loc - EndianOffset)) ? 0xF : 0x3;
573+
checkAlignment(Loc, lo(Val), Mask + 1, Type);
574+
write16(Loc, (read16(Loc) & Mask) | lo(Val));
575+
} break;
548576
case R_PPC64_ADDR32:
549577
case R_PPC64_REL32:
550578
checkInt(Loc, Val, 32, Type);

‎lld/test/ELF/ppc64-dq.s

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# REQUIRES: ppc
2+
3+
# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
4+
# RUN: ld.lld %t.o -o %t
5+
# RUN: llvm-objdump -D %t | FileCheck %s
6+
7+
# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
8+
# RUN: ld.lld %t.o -o %t
9+
# RUN: llvm-objdump -D %t | FileCheck %s
10+
11+
.global test
12+
.p2align 4
13+
.type test,@function
14+
test:
15+
.Lgep:
16+
addis 2, 12, .TOC.-.Lgep@ha
17+
addi 2, 2, .TOC.-.Lgep@l
18+
.Llep:
19+
.localentry test, .Llep-.Lgep
20+
addis 3, 2, qword@toc@ha
21+
lxv 3, qword@toc@l(3)
22+
addis 3, 2, qword@toc@ha
23+
stxv 3, qword@toc@l(3)
24+
blr
25+
26+
.comm qword, 16, 16
27+
28+
# Verify that we don't overwrite any of the extended opcode bits on a DQ form
29+
# instruction.
30+
# CHECK-LABEL: test
31+
# CHECK: lxv 3, -32768(3)
32+
# CHECK: stxv 3, -32768(3)
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# REQUIRES: ppc
2+
#
3+
# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
4+
# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
5+
6+
# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
7+
# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
8+
9+
# CHECK: improper alignment for relocation R_PPC64_ADDR16_LO_DS: 0x8001 is not aligned to 16 bytes
10+
11+
.global test
12+
.p2align 4
13+
.type test,@function
14+
test:
15+
.Lgep:
16+
addis 2, 12, .TOC.-.Lgep@ha
17+
addi 2, 2, .TOC.-.Lgep@l
18+
.Llep:
19+
.localentry test, .Llep-.Lgep
20+
addis 3, 2, qword@toc@ha
21+
lxv 3, qword@toc@l(3)
22+
blr
23+
24+
.comm pad, 1, 1
25+
.comm qword, 16, 1
26+
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# REQUIRES: ppc
2+
3+
# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
4+
# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
5+
6+
# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
7+
# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
8+
9+
# CHECK: improper alignment for relocation R_PPC64_ADDR16_LO_DS: 0x8001 is not aligned to 4 bytes
10+
11+
.global test
12+
.p2align 4
13+
.type test,@function
14+
test:
15+
.Lgep:
16+
addis 2, 12, .TOC.-.Lgep@ha
17+
addi 2, 2, .TOC.-.Lgep@l
18+
.Llep:
19+
.localentry test, .Llep-.Lgep
20+
addis 3, 2, word@toc@ha
21+
lwa 3, word@toc@l(3)
22+
blr
23+
24+
.comm pad, 1, 1
25+
.comm word, 4, 1
26+

0 commit comments

Comments
 (0)
Please sign in to comment.