summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp69
-rw-r--r--llvm/test/MC/AArch64/fixup-out-of-range.s64
-rw-r--r--llvm/test/MC/AArch64/ldr-pseudo-obj-errors.s2
3 files changed, 110 insertions, 25 deletions
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
index 3ad48bc133f..d88ec99f7d9 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
@@ -12,6 +12,7 @@
#include "MCTargetDesc/AArch64FixupKinds.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDirectives.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCFixupKindInfo.h"
@@ -134,14 +135,16 @@ static unsigned AdrImmBits(unsigned Value) {
return (hi19 << 5) | (lo2 << 29);
}
-static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
+static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
+ MCContext *Ctx) {
+ unsigned Kind = Fixup.getKind();
int64_t SignedValue = static_cast<int64_t>(Value);
switch (Kind) {
default:
llvm_unreachable("Unknown fixup kind!");
case AArch64::fixup_aarch64_pcrel_adr_imm21:
- if (SignedValue > 2097151 || SignedValue < -2097152)
- report_fatal_error("fixup value out of range");
+ if (Ctx && (SignedValue > 2097151 || SignedValue < -2097152))
+ Ctx->reportError(Fixup.getLoc(), "fixup value out of range");
return AdrImmBits(Value & 0x1fffffULL);
case AArch64::fixup_aarch64_pcrel_adrp_imm21:
return AdrImmBits((Value & 0x1fffff000ULL) >> 12);
@@ -149,54 +152,66 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
case AArch64::fixup_aarch64_pcrel_branch19:
// Signed 21-bit immediate
if (SignedValue > 2097151 || SignedValue < -2097152)
- report_fatal_error("fixup value out of range");
+ if (Ctx) Ctx->reportError(Fixup.getLoc(), "fixup value out of range");
+ if (Ctx && (Value & 0x3))
+ Ctx->reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
// Low two bits are not encoded.
return (Value >> 2) & 0x7ffff;
case AArch64::fixup_aarch64_add_imm12:
case AArch64::fixup_aarch64_ldst_imm12_scale1:
// Unsigned 12-bit immediate
- if (Value >= 0x1000)
- report_fatal_error("invalid imm12 fixup value");
+ if (Ctx && Value >= 0x1000)
+ Ctx->reportError(Fixup.getLoc(), "fixup value out of range");
return Value;
case AArch64::fixup_aarch64_ldst_imm12_scale2:
// Unsigned 12-bit immediate which gets multiplied by 2
- if (Value & 1 || Value >= 0x2000)
- report_fatal_error("invalid imm12 fixup value");
+ if (Ctx && (Value >= 0x2000))
+ Ctx->reportError(Fixup.getLoc(), "fixup value out of range");
+ if (Ctx && (Value & 0x1))
+ Ctx->reportError(Fixup.getLoc(), "fixup must be 2-byte aligned");
return Value >> 1;
case AArch64::fixup_aarch64_ldst_imm12_scale4:
// Unsigned 12-bit immediate which gets multiplied by 4
- if (Value & 3 || Value >= 0x4000)
- report_fatal_error("invalid imm12 fixup value");
+ if (Ctx && (Value >= 0x4000))
+ Ctx->reportError(Fixup.getLoc(), "fixup value out of range");
+ if (Ctx && (Value & 0x3))
+ Ctx->reportError(Fixup.getLoc(), "fixup must be 4-byte aligned");
return Value >> 2;
case AArch64::fixup_aarch64_ldst_imm12_scale8:
// Unsigned 12-bit immediate which gets multiplied by 8
- if (Value & 7 || Value >= 0x8000)
- report_fatal_error("invalid imm12 fixup value");
+ if (Ctx && (Value >= 0x8000))
+ Ctx->reportError(Fixup.getLoc(), "fixup value out of range");
+ if (Ctx && (Value & 0x7))
+ Ctx->reportError(Fixup.getLoc(), "fixup must be 8-byte aligned");
return Value >> 3;
case AArch64::fixup_aarch64_ldst_imm12_scale16:
// Unsigned 12-bit immediate which gets multiplied by 16
- if (Value & 15 || Value >= 0x10000)
- report_fatal_error("invalid imm12 fixup value");
+ if (Ctx && (Value >= 0x10000))
+ Ctx->reportError(Fixup.getLoc(), "fixup value out of range");
+ if (Ctx && (Value & 0xf))
+ Ctx->reportError(Fixup.getLoc(), "fixup must be 16-byte aligned");
return Value >> 4;
case AArch64::fixup_aarch64_movw:
- report_fatal_error("no resolvable MOVZ/MOVK fixups supported yet");
+ if (Ctx)
+ Ctx->reportError(Fixup.getLoc(),
+ "no resolvable MOVZ/MOVK fixups supported yet");
return Value;
case AArch64::fixup_aarch64_pcrel_branch14:
// Signed 16-bit immediate
- if (SignedValue > 32767 || SignedValue < -32768)
- report_fatal_error("fixup value out of range");
+ if (Ctx && (SignedValue > 32767 || SignedValue < -32768))
+ Ctx->reportError(Fixup.getLoc(), "fixup value out of range");
// Low two bits are not encoded (4-byte alignment assumed).
- if (Value & 0x3)
- report_fatal_error("fixup not sufficiently aligned");
+ if (Ctx && (Value & 0x3))
+ Ctx->reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
return (Value >> 2) & 0x3fff;
case AArch64::fixup_aarch64_pcrel_branch26:
case AArch64::fixup_aarch64_pcrel_call26:
// Signed 28-bit immediate
- if (SignedValue > 134217727 || SignedValue < -134217728)
- report_fatal_error("fixup value out of range");
+ if (Ctx && (SignedValue > 134217727 || SignedValue < -134217728))
+ Ctx->reportError(Fixup.getLoc(), "fixup value out of range");
// Low two bits are not encoded (4-byte alignment assumed).
- if (Value & 0x3)
- report_fatal_error("fixup not sufficiently aligned");
+ if (Ctx && (Value & 0x3))
+ Ctx->reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
return (Value >> 2) & 0x3ffffff;
case FK_Data_1:
case FK_Data_2:
@@ -253,7 +268,7 @@ void AArch64AsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
return; // Doesn't change encoding.
MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
// Apply any target-specific value adjustments.
- Value = adjustFixupValue(Fixup.getKind(), Value);
+ Value = adjustFixupValue(Fixup, Value, nullptr);
// Shift the value into position.
Value <<= Info.TargetOffset;
@@ -544,6 +559,12 @@ void ELFAArch64AsmBackend::processFixupValue(
// to the linker -- a relocation!
if ((uint32_t)Fixup.getKind() == AArch64::fixup_aarch64_pcrel_adrp_imm21)
IsResolved = false;
+
+ // Try to get the encoded value for the fixup as-if we're mapping it into
+ // the instruction. This allows adjustFixupValue() to issue a diagnostic
+ // if the value is invalid.
+ if (IsResolved)
+ (void)adjustFixupValue(Fixup, Value, &Asm.getContext());
}
}
diff --git a/llvm/test/MC/AArch64/fixup-out-of-range.s b/llvm/test/MC/AArch64/fixup-out-of-range.s
new file mode 100644
index 00000000000..0d0d2ffb0bf
--- /dev/null
+++ b/llvm/test/MC/AArch64/fixup-out-of-range.s
@@ -0,0 +1,64 @@
+// RUN: not llvm-mc -triple aarch64--none-eabi -filetype obj < %s -o /dev/null 2>&1 | FileCheck %s
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
+ adr x0, distant
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
+ ldr x0, distant
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup not sufficiently aligned
+ ldr x0, unaligned
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
+ b.eq distant
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup not sufficiently aligned
+ b.eq unaligned
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
+ ldr x0, [x1, distant-.]
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup must be 8-byte aligned
+ ldr x0, [x1, unaligned-.]
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
+ ldr w0, [x1, distant-.]
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup must be 4-byte aligned
+ ldr w0, [x1, unaligned-.]
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
+ ldrh w0, [x1, distant-.]
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup must be 2-byte aligned
+ ldrh w0, [x1, unaligned-.]
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
+ ldrb w0, [x1, distant-.]
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
+ ldr q0, [x1, distant-.]
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup must be 16-byte aligned
+ ldr q0, [x1, unaligned-.]
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
+ tbz x0, #1, distant
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup not sufficiently aligned
+ tbz x0, #1, unaligned
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
+ b distant
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup not sufficiently aligned
+ b unaligned
+
+ .byte 0
+unaligned:
+ .byte 0
+
+ .space 1<<27
+ .balign 8
+distant:
+ .word 0
diff --git a/llvm/test/MC/AArch64/ldr-pseudo-obj-errors.s b/llvm/test/MC/AArch64/ldr-pseudo-obj-errors.s
index 7f1b64262c4..d851917b714 100644
--- a/llvm/test/MC/AArch64/ldr-pseudo-obj-errors.s
+++ b/llvm/test/MC/AArch64/ldr-pseudo-obj-errors.s
@@ -8,6 +8,6 @@
.text
foo:
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: fixup value out of range
ldr x0, =0x10111
.space 0xdeadb0
-// CHECK: LVM ERROR: fixup value out of range
OpenPOWER on IntegriCloud