Index: lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -727,9 +727,13 @@ || ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12; } - // Otherwise it should be a real immediate in range: - const MCConstantExpr *CE = cast(Expr); - return CE->getValue() >= 0 && CE->getValue() <= 0xfff; + // If it's a constant, it should be a real immediate in range: + if (auto *CE = dyn_cast(Expr)) + return CE->getValue() >= 0 && CE->getValue() <= 0xfff; + + // If it's an expression, we hope for the best and let the fixup/relocation + // code deal with it. + return true; } bool isAddSubImmNeg() const { if (!isShiftedImm() && !isImm()) @@ -3572,31 +3576,34 @@ AArch64MCExpr::VariantKind ELFRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind; int64_t Addend; - if (!classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { - return Error(Loc[2], "invalid immediate expression"); - } + if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { - // Only allow these with ADDXri. - if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF || - DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) && - Inst.getOpcode() == AArch64::ADDXri) - return false; + // Only allow these with ADDXri. + if ((DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF || + DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) && + Inst.getOpcode() == AArch64::ADDXri) + return false; - // Only allow these with ADDXri/ADDWri - if ((ELFRefKind == AArch64MCExpr::VK_LO12 || - ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 || - ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 || - ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC || - ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 || - ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 || - ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC || - ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12) && - (Inst.getOpcode() == AArch64::ADDXri || - Inst.getOpcode() == AArch64::ADDWri)) - return false; + // Only allow these with ADDXri/ADDWri + if ((ELFRefKind == AArch64MCExpr::VK_LO12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC || + ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 || + ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC || + ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12) && + (Inst.getOpcode() == AArch64::ADDXri || + Inst.getOpcode() == AArch64::ADDWri)) + return false; - // Don't allow expressions in the immediate field otherwise - return Error(Loc[2], "invalid immediate expression"); + // Don't allow symbol refs in the immediate field otherwise + // Note: Loc.back() may be Loc[1] or Loc[2] depending on the number of + // operands of the original instruction (i.e. 'add w0, w1, borked' vs + // 'cmp w0, 'borked') + return Error(Loc.back(), "invalid immediate expression"); + } + // We don't validate more complex expressions here } return false; } Index: lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -520,6 +520,17 @@ return CompactUnwindEncoding; } + + void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFixup &Fixup, const MCFragment *DF, + const MCValue &Target, uint64_t &Value, + bool &IsResolved) override { + // 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()); + } }; } // end anonymous namespace Index: lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64MachObjectWriter.cpp @@ -75,7 +75,7 @@ Log2Size = llvm::Log2_32(4); switch (Sym->getKind()) { default: - llvm_unreachable("Unexpected symbol reference variant kind!"); + return false; case MCSymbolRefExpr::VK_PAGEOFF: RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12); return true; Index: test/MC/AArch64/basic-a64-diagnostics.s =================================================================== --- test/MC/AArch64/basic-a64-diagnostics.s +++ test/MC/AArch64/basic-a64-diagnostics.s @@ -172,9 +172,14 @@ // A relocation should be provided for symbols add x3, x9, #variable + add x3, x9, #variable-16 // CHECK-ERROR: error: expected compatible register, symbol or integer in range [0, 4095] // CHECK-ERROR-NEXT: add x3, x9, #variable // CHECK-ERROR-NEXT: ^ +// CHECK-ERROR-NEXT: error: expected compatible register, symbol or integer in range [0, 4095] +// CHECK-ERROR-NEXT: add x3, x9, #variable-16 +// CHECK-ERROR-NEXT: ^ + //------------------------------------------------------------------------------ Index: test/MC/AArch64/label-arithmetic-darwin.s =================================================================== --- /dev/null +++ test/MC/AArch64/label-arithmetic-darwin.s @@ -0,0 +1,56 @@ +// RUN: llvm-mc -triple aarch64-darwin -filetype=obj %s -o - | llvm-objdump -r -d - | FileCheck %s +// RUN: llvm-mc -triple aarch64-ios -filetype=obj %s -o - | llvm-objdump -r -d - | FileCheck %s + +visible: + .space 8 +Lstart: + .space 8 +Lend: + adds w0, w1, #(Lend - Lstart) + adds x0, x1, #(Lend - Lstart) + add w0, w1, #(Lend - Lstart) + add x0, x1, #(Lend - Lstart) + cmp w0, #(Lend - Lstart) + cmp x0, #(Lend - Lstart) + sub w0, w1, #(Lend - Lstart) + sub x0, x1, #(Lend - Lstart) + // CHECK: adds w0, w1, #8 + // CHECK: adds x0, x1, #8 + // CHECK: add w0, w1, #8 + // CHECK: add x0, x1, #8 + // CHECK: cmp w0, #8 + // CHECK: cmp x0, #8 + // CHECK: sub w0, w1, #8 + // CHECK: sub x0, x1, #8 + + add w0, w1, #((Lend - Lstart) >> 2) + cmp w0, #((Lend - Lstart) >> 2) + // CHECK: add w0, w1, #2 + // CHECK: cmp w0, #2 + + add w0, w1, #(Lend - Lstart + 12) + cmp w0, #(Lend - Lstart + 12) + // CHECK: add w0, w1, #20 + // CHECK: cmp w0, #20 + + add w0, w1, #(Lforward - Lend) + cmp w0, #(Lforward - Lend) + // CHECK: add w0, w1, #320 + // CHECK: cmp w0, #320 + + add w0, w1, #(Lstart - visible) + cmp w0, #(Lstart - visible) + // CHECK: add w0, w1, #8 + // CHECK: cmp w0, #8 + +// Add some filler so we don't have to modify #(Lforward - Lend) if we add more +// instructions above +Lfiller: + .space 320 - (Lfiller - Lend) + +Lforward: + .space 4 + add w0, w1, #(. - Lforward) + cmp w0, #(. - Lforward) + // CHECK: add w0, w1, #4 + // CHECK: cmp w0, #8 Index: test/MC/AArch64/label-arithmetic-diags-darwin.s =================================================================== --- /dev/null +++ test/MC/AArch64/label-arithmetic-diags-darwin.s @@ -0,0 +1,68 @@ +// RUN: not llvm-mc -triple aarch64-darwin -filetype=obj %s -o /dev/null 2>&1 | FileCheck %s +// RUN: not llvm-mc -triple aarch64-ios -filetype=obj %s -o /dev/null 2>&1 | FileCheck %s + +Lstart: + .space 8 +Lend: + add w0, w1, #(Lend - external) + cmp w0, #(Lend - external) + // CHECK: error: unknown AArch64 fixup kind! + // CHECK-NEXT: add w0, w1, #(Lend - external) + // CHECK-NEXT: ^ + // CHECK: error: unknown AArch64 fixup kind! + // CHECK-NEXT: cmp w0, #(Lend - external) + // CHECK-NEXT: ^ + + add w0, w1, #(Lend - var@TLVPPAGEOFF) + cmp w0, #(Lend - var@TLVPPAGEOFF) + // CHECK: error: unknown AArch64 fixup kind! + // CHECK-NEXT: add w0, w1, #(Lend - var@TLVPPAGEOFF) + // CHECK-NEXT: ^ + // CHECK: error: unknown AArch64 fixup kind! + // CHECK-NEXT: cmp w0, #(Lend - var@TLVPPAGEOFF) + // CHECK-NEXT: ^ + + add w0, w1, #(Lstart - Lend) + cmp w0, #(Lstart - Lend) + // CHECK: error: fixup value out of range + // CHECK-NEXT: add w0, w1, #(Lstart - Lend) + // CHECK-NEXT: ^ + // CHECK: error: fixup value out of range + // CHECK-NEXT: cmp w0, #(Lstart - Lend) + // CHECK-NEXT: ^ + + .space 5000 +Lfar: + add w0, w1, #(Lfar - Lend) + cmp w0, #(Lfar - Lend) + // CHECK: error: fixup value out of range + // CHECK-NEXT: add w0, w1, #(Lfar - Lend) + // CHECK-NEXT: ^ + // CHECK: error: fixup value out of range + // CHECK-NEXT: cmp w0, #(Lfar - Lend) + // CHECK-NEXT: ^ + +Lprivate1: + .space 8 +notprivate: + .space 8 +Lprivate2: + add w0, w1, #(Lprivate2 - Lprivate1) + cmp w0, #(Lprivate2 - Lprivate1) + // CHECK: error: unknown AArch64 fixup kind! + // CHECK-NEXT: add w0, w1, #(Lprivate2 - Lprivate1) + // CHECK-NEXT: ^ + // CHECK: error: unknown AArch64 fixup kind! + // CHECK-NEXT: cmp w0, #(Lprivate2 - Lprivate1) + // CHECK-NEXT: ^ + + .section __TEXT, sec_y, regular, pure_instructions +Lend_across_sec: + add w0, w1, #(Lend_across_sec - Lprivate2) + cmp w0, #(Lend_across_sec - Lprivate2) + // CHECK: error: unknown AArch64 fixup kind! + // CHECK-NEXT: add w0, w1, #(Lend_across_sec - Lprivate2) + // CHECK-NEXT: ^ + // CHECK: error: unknown AArch64 fixup kind! + // CHECK-NEXT: cmp w0, #(Lend_across_sec - Lprivate2) + // CHECK-NEXT: ^ Index: test/MC/AArch64/label-arithmetic-diags-elf.s =================================================================== --- /dev/null +++ test/MC/AArch64/label-arithmetic-diags-elf.s @@ -0,0 +1,71 @@ +// RUN: not llvm-mc -triple aarch64-elf -filetype=obj %s -o /dev/null 2>&1 | FileCheck %s + + .section sec_x +start: + .space 5000 +end: + add w0, w1, #(end - start) + cmp w0, #(end - start) + // CHECK: error: fixup value out of range + // CHECK-NEXT: add w0, w1, #(end - start) + // CHECK-NEXT: ^ + // CHECK: error: fixup value out of range + // CHECK-NEXT: cmp w0, #(end - start) + // CHECK-NEXT: ^ + +negative: + add w0, w1, #(end - negative) + cmp w0, #(end - negative) + // CHECK: error: fixup value out of range + // CHECK-NEXT: add w0, w1, #(end - negative) + // CHECK-NEXT: ^ + // CHECK: error: fixup value out of range + // CHECK-NEXT: cmp w0, #(end - negative) + // CHECK-NEXT: ^ + + add w0, w1, #(end - external) + cmp w0, #(end - external) + // CHECK: error: symbol 'external' can not be undefined in a subtraction expression + // CHECK-NEXT: add w0, w1, #(end - external) + // CHECK-NEXT: ^ + // CHECK: error: symbol 'external' can not be undefined in a subtraction expression + // CHECK-NEXT: cmp w0, #(end - external) + // CHECK-NEXT: ^ + + add w0, w1, #:lo12:external - end + cmp w0, #:lo12:external - end + // CHECK: error: Unsupported pc-relative fixup kind + // CHECK-NEXT: add w0, w1, #:lo12:external - end + // CHECK-NEXT: ^ + // CHECK: error: Unsupported pc-relative fixup kind + // CHECK-NEXT: cmp w0, #:lo12:external - end + // CHECK-NEXT: ^ + + add w0, w1, #:got_lo12:external - end + cmp w0, #:got_lo12:external - end + // CHECK: error: Unsupported pc-relative fixup kind + // CHECK-NEXT: add w0, w1, #:got_lo12:external - end + // CHECK-NEXT: ^ + // CHECK: error: Unsupported pc-relative fixup kind + // CHECK-NEXT: cmp w0, #:got_lo12:external - end + // CHECK-NEXT: ^ + + .section sec_y +end_across_sec: + add w0, w1, #(end_across_sec - start) + cmp w0, #(end_across_sec - start) + // CHECK: error: Cannot represent a difference across sections + // CHECK-NEXT: add w0, w1, #(end_across_sec - start) + // CHECK-NEXT: ^ + // CHECK: error: Cannot represent a difference across sections + // CHECK-NEXT: cmp w0, #(end_across_sec - start) + // CHECK-NEXT: ^ + + add w0, w1, #(sec_y - sec_x) + cmp w0, #(sec_y - sec_x) + // CHECK: error: symbol 'sec_x' can not be undefined in a subtraction expression + // CHECK-NEXT: add w0, w1, #(sec_y - sec_x) + // CHECK-NEXT: ^ + // CHECK: error: symbol 'sec_x' can not be undefined in a subtraction expression + // CHECK-NEXT: cmp w0, #(sec_y - sec_x) + // CHECK-NEXT: ^ Index: test/MC/AArch64/label-arithmetic-elf.s =================================================================== --- /dev/null +++ test/MC/AArch64/label-arithmetic-elf.s @@ -0,0 +1,91 @@ +// RUN: llvm-mc -triple aarch64-elf -filetype=obj %s -o - | llvm-objdump -d - | FileCheck %s + +start: + .space 8 +end: + // CHECK-LABEL: end: + + adds w0, w1, #(end - start) + adds x0, x1, #(end - start) + add w0, w1, #(end - start) + add x0, x1, #(end - start) + cmp w0, #(end - start) + cmp x0, #(end - start) + sub w0, w1, #(end - start) + sub x0, x1, #(end - start) + // CHECK: adds w0, w1, #8 + // CHECK: adds x0, x1, #8 + // CHECK: add w0, w1, #8 + // CHECK: add x0, x1, #8 + // CHECK: cmp w0, #8 + // CHECK: cmp x0, #8 + // CHECK: sub w0, w1, #8 + // CHECK: sub x0, x1, #8 + + add w0, w1, #((end - start) >> 2) + cmp w0, #((end - start) >> 2) + // CHECK: add w0, w1, #2 + // CHECK: cmp w0, #2 + + add w0, w1, #(end - start + 12) + cmp w0, #(end - start + 12) + // CHECK: add w0, w1, #20 + // CHECK: cmp w0, #20 + + add w0, w1, #(forward - end) + cmp w0, #(forward - end) + // CHECK: add w0, w1, #320 + // CHECK: cmp w0, #320 + +// Add some filler so we don't have to modify #(forward - end) if we add more +// instructions above +.Lfiller: + .space 320 - (.Lfiller - end) + +forward: + .space 8 + +.Lstart: + .space 8 +.Lend: + add w0, w1, #(.Lend - .Lstart) + cmp w0, #(.Lend - .Lstart) + // CHECK: add w0, w1, #8 + // CHECK: cmp w0, #8 + +.Lprivate1: + .space 8 +notprivate: + .space 8 +.Lprivate2: + add w0, w1, #(.Lprivate2 - .Lprivate1) + cmp w0, #(.Lprivate2 - .Lprivate1) + // CHECK: add w0, w1, #16 + // CHECK: cmp w0, #16 + + .type foo, @function +foo: + // CHECK-LABEL: foo: + + add w0, w1, #(foo - .Lprivate2) + cmp w0, #(foo - .Lprivate2) + // CHECK: add w0, w1, #8 + // CHECK: cmp w0, #8 + + ret + + .type goo, @function +goo: + // CHECK-LABEL: goo: + + add w0, w1, #(goo - foo) + cmp w0, #(goo - foo) + // CHECK: add w0, w1, #12 + // CHECK: cmp w0, #12 + + add w0, w1, #(. - goo) + cmp w0, #(. - goo) + // CHECK: add w0, w1, #8 + // CHECK: cmp w0, #12 + + ret