Index: lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ 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 @@ 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(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 @@ 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 @@ 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 @@ // 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()); } } Index: test/MC/AArch64/fixup-out-of-range.s =================================================================== --- /dev/null +++ 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 Index: test/MC/AArch64/ldr-pseudo-obj-errors.s =================================================================== --- test/MC/AArch64/ldr-pseudo-obj-errors.s +++ 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