summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Smith <peter.smith@linaro.org>2017-09-06 14:23:06 +0000
committerPeter Smith <peter.smith@linaro.org>2017-09-06 14:23:06 +0000
commit1d5a070386bab364ea34b0230707edfced7df5e9 (patch)
treeed15cfab17feab76816a662a0e9a25e3e757ac8a
parent3ef89b0fc7af7436f8f952e24cd50dfdfb87d08d (diff)
downloadbcm5719-llvm-1d5a070386bab364ea34b0230707edfced7df5e9.tar.gz
bcm5719-llvm-1d5a070386bab364ea34b0230707edfced7df5e9.zip
[ELF][AArch64] Add alignment checks for the LDST<N>_ABS_LO12_NC relocations
The R_AARCH64_LDST<N>_ABS LO12_NC relocations where N is 8, 16, 32, 64 or 128 have a scaled immediate. For example R_AARCH64_LDST32_ABS_LO12_NC shifts the calculated value right by 4. If the target symbol + relocation addend is not aligned properly then bits of the answer will be lost. This change adds an alignment check to the relocations to make sure the target of the relocation is aligned properly. This matches the behavior of GNU ld. The motivation is to catch ODR violations such as a declaration of extern int foo, but a definition of bool foo as the compiler may use R_AARCH64_LDST32_ABS_LO12_NC for the former, but not align the destination. Differential Revision: https://reviews.llvm.org/D37444 llvm-svn: 312637
-rw-r--r--lld/ELF/Arch/AArch64.cpp4
-rw-r--r--lld/test/ELF/aarch64-lo12-alignment.s45
2 files changed, 49 insertions, 0 deletions
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 9a258597d4c..9561dfc5750 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -251,15 +251,19 @@ void AArch64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
or32AArch64Imm(Loc, getBits(Val, 0, 11));
break;
case R_AARCH64_LDST16_ABS_LO12_NC:
+ checkAlignment<2>(Loc, Val, Type);
or32AArch64Imm(Loc, getBits(Val, 1, 11));
break;
case R_AARCH64_LDST32_ABS_LO12_NC:
+ checkAlignment<4>(Loc, Val, Type);
or32AArch64Imm(Loc, getBits(Val, 2, 11));
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
+ checkAlignment<8>(Loc, Val, Type);
or32AArch64Imm(Loc, getBits(Val, 3, 11));
break;
case R_AARCH64_LDST128_ABS_LO12_NC:
+ checkAlignment<16>(Loc, Val, Type);
or32AArch64Imm(Loc, getBits(Val, 4, 11));
break;
case R_AARCH64_MOVW_UABS_G0_NC:
diff --git a/lld/test/ELF/aarch64-lo12-alignment.s b/lld/test/ELF/aarch64-lo12-alignment.s
new file mode 100644
index 00000000000..137832dc3d2
--- /dev/null
+++ b/lld/test/ELF/aarch64-lo12-alignment.s
@@ -0,0 +1,45 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t
+// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+
+// Test derived from a typical ODR violation where a global is declared
+// extern int but defined as a half or byte sized type.
+ .section .text
+ .globl _start
+ .type _start, %function
+// Access foo2 as if it were an aligned 32-bit int, expect an error as
+// foo is not aligned
+
+_start:
+ ldrb w2, [x0, #:lo12:foo1] // Ok as no shift involved
+ ldrh w2, [x0, #:lo12:foo1] // Error foo1 is not 2-byte aligned
+ ldrh w2, [x0, #:lo12:foo2] // Ok as foo2 is 2-byte aligned
+ ldr w2, [x0, #:lo12:foo2] // Error foo2 is not 4-byte aligned
+ ldr w2, [x0, #:lo12:foo4] // Ok as foo4 is 4-byte aligned
+ ldr x3, [x0, #:lo12:foo4] // Error foo4 is not 8-byte aligned
+ ldr x3, [x0, #:lo12:foo8] // Ok as foo8 is 8-byte aligned
+ ldr q0, [x0, #:lo12:foo8] // Error foo8 is not 16-byte aligned
+ ldr q0, [x0, #:lo12:foo16] // Ok as foo16 is 16-byte aligned
+
+ .section .data.bool, "a", @nobits
+ .balign 16
+ .globl foo16
+ .globl foo1
+ .globl foo2
+ .globl foo4
+ .globl foo8
+foo16:
+ .space 1
+foo1:
+ .space 1
+foo2:
+ .space 2
+foo4:
+ .space 4
+foo8:
+ .space 8
+
+// CHECK: improper alignment for relocation R_AARCH64_LDST16_ABS_LO12_NC
+// CHECK-NEXT: improper alignment for relocation R_AARCH64_LDST32_ABS_LO12_NC
+// CHECK-NEXT: improper alignment for relocation R_AARCH64_LDST64_ABS_LO12_NC
+// CHECK-NEXT: improper alignment for relocation R_AARCH64_LDST128_ABS_LO12_NC
OpenPOWER on IntegriCloud