A complete implementation of `applyFixup` for D132323.
Makes `LoongArchAsmBackend::shouldForceRelocation` to determine
if the relocation types must be forced.
This patch also adds range and alignment checks for `b*` instructions'
operands, at which point the offset to a label is known.
Differential Revision: https://reviews.llvm.org/D132818
//===----------------------------------------------------------------------===//
#include "LoongArchAsmBackend.h"
+#include "LoongArchFixupKinds.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCValue.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/EndianStream.h"
return Infos[Kind - FirstTargetFixupKind];
}
+static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
+ MCContext &Ctx) {
+ switch (Fixup.getTargetKind()) {
+ default:
+ llvm_unreachable("Unknown fixup kind");
+ case FK_Data_1:
+ case FK_Data_2:
+ case FK_Data_4:
+ case FK_Data_8:
+ return Value;
+ case LoongArch::fixup_loongarch_b16: {
+ if (!isInt<18>(Value))
+ Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
+ if (Value % 4)
+ Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned");
+ return (Value >> 2) & 0xffff;
+ }
+ case LoongArch::fixup_loongarch_b21: {
+ if (!isInt<23>(Value))
+ Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
+ if (Value % 4)
+ Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned");
+ return ((Value & 0x3fffc) << 8) | ((Value >> 18) & 0x1f);
+ }
+ case LoongArch::fixup_loongarch_b26: {
+ if (!isInt<28>(Value))
+ Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
+ if (Value % 4)
+ Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned");
+ return ((Value & 0x3fffc) << 8) | ((Value >> 18) & 0x3ff);
+ }
+ case LoongArch::fixup_loongarch_abs_hi20:
+ case LoongArch::fixup_loongarch_tls_le_hi20:
+ return (Value >> 12) & 0xfffff;
+ case LoongArch::fixup_loongarch_abs_lo12:
+ case LoongArch::fixup_loongarch_tls_le_lo12:
+ return Value & 0xfff;
+ case LoongArch::fixup_loongarch_abs64_lo20:
+ case LoongArch::fixup_loongarch_tls_le64_lo20:
+ return (Value >> 32) & 0xfffff;
+ case LoongArch::fixup_loongarch_abs64_hi12:
+ case LoongArch::fixup_loongarch_tls_le64_hi12:
+ return (Value >> 52) & 0xfff;
+ }
+}
+
void LoongArchAsmBackend::applyFixup(const MCAssembler &Asm,
const MCFixup &Fixup,
const MCValue &Target,
if (Kind >= FirstLiteralRelocationKind)
return;
MCFixupKindInfo Info = getFixupKindInfo(Kind);
- // TODO: Apply any target-specific value adjustments.
+ MCContext &Ctx = Asm.getContext();
+
+ // Apply any target-specific value adjustments.
+ Value = adjustFixupValue(Fixup, Value, Ctx);
// Shift the value into position.
Value <<= Info.TargetOffset;
const MCValue &Target) {
if (Fixup.getKind() >= FirstLiteralRelocationKind)
return true;
- // TODO: Determine which relocation require special processing at linking
- // time.
- return false;
+ switch (Fixup.getTargetKind()) {
+ default:
+ return false;
+ case FK_Data_1:
+ case FK_Data_2:
+ case FK_Data_4:
+ case FK_Data_8:
+ return !Target.isAbsolute();
+ }
}
bool LoongArchAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
case LoongArch::BCNEZ:
FixupKind = LoongArch::fixup_loongarch_b21;
break;
+ case LoongArch::B:
+ FixupKind = LoongArch::fixup_loongarch_b26;
+ break;
}
}
--- /dev/null
+# RUN: not llvm-mc --triple=loongarch64 --filetype=obj %s -o /dev/null 2>&1 | FileCheck %s
+
+ beq $a0, $a1, far_distant # CHECK: :[[#@LINE]]:3: error: fixup value out of range
+ bne $a0, $a1, unaligned # CHECK: :[[#@LINE]]:3: error: fixup value must be 4-byte aligned
+
+ bnez $a0, unaligned # CHECK: :[[#@LINE]]:3: error: fixup value must be 4-byte aligned
+ beqz $a0, far_distant_bz # CHECK: :[[#@LINE]]:3: error: fixup value out of range
+
+ b unaligned # CHECK: :[[#@LINE]]:3: error: fixup value must be 4-byte aligned
+
+ .byte 0
+unaligned:
+ .byte 0
+ .byte 0
+ .byte 0
+
+ .space 1<<16
+distant:
+ .space 1<<18
+far_distant:
+
+ .byte 0
+unaligned_bz:
+ .byte 0
+ .byte 0
+ .byte 0
+distant_bz:
+ .space 1<<23
+far_distant_bz:
--- /dev/null
+# RUN: not llvm-mc --filetype=obj %s --triple=loongarch32 -o /dev/null 2>&1 \
+# RUN: | FileCheck %s
+# RUN: not llvm-mc --filetype=obj %s --triple=loongarch64 -o /dev/null 2>&1 \
+# RUN: | FileCheck %s
+
+.byte foo # CHECK: [[#@LINE]]:7: error: 1-byte data relocations not supported
+.2byte foo # CHECK: [[#@LINE]]:8: error: 2-byte data relocations not supported
--- /dev/null
+# RUN: llvm-mc --triple=loongarch64 %s --show-encoding \
+# RUN: | FileCheck --check-prefix=CHECK-FIXUP %s
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 %s \
+# RUN: | llvm-objdump -d - | FileCheck --check-prefix=CHECK-INSTR %s
+# RUN: llvm-mc --filetype=obj --triple=loongarch64 %s \
+# RUN: | llvm-readobj -r - | FileCheck --check-prefix=CHECK-REL %s
+
+## Checks that fixups that can be resolved within the same object file are
+## applied correctly.
+
+.LBB0:
+lu12i.w $t1, %abs_hi20(val)
+# CHECK-FIXUP: fixup A - offset: 0, value: %abs_hi20(val), kind: fixup_loongarch_abs_hi20
+# CHECK-INSTR: lu12i.w $t1, 74565
+
+ori $t1, $t1, %abs_lo12(val)
+# CHECK-FIXUP: fixup A - offset: 0, value: %abs_lo12(val), kind: fixup_loongarch_abs_lo12
+# CHECK-INSTR: ori $t1, $t1, 1656
+
+b .LBB0
+# CHECK-FIXUP: fixup A - offset: 0, value: .LBB0, kind: fixup_loongarch_b26
+# CHECK-INSTR: b -8
+b .LBB2
+# CHECK-FIXUP: fixup A - offset: 0, value: .LBB2, kind: fixup_loongarch_b26
+# CHECK-INSTR: b 331004
+beq $a0, $a1, .LBB0
+# CHECK-FIXUP: fixup A - offset: 0, value: .LBB0, kind: fixup_loongarch_b16
+# CHECK-INSTR: beq $a0, $a1, -16
+blt $a0, $a1, .LBB1
+# CHECK-FIXUP: fixup A - offset: 0, value: .LBB1, kind: fixup_loongarch_b16
+# CHECK-INSTR: blt $a0, $a1, 1116
+beqz $a0, .LBB0
+# CHECK-FIXUP: fixup A - offset: 0, value: .LBB0, kind: fixup_loongarch_b21
+# CHECK-INSTR: beqz $a0, -24
+bnez $a0, .LBB1
+# CHECK-FIXUP: fixup A - offset: 0, value: .LBB1, kind: fixup_loongarch_b21
+# CHECK-INSTR: bnez $a0, 1108
+
+.fill 1104
+
+.LBB1:
+
+.fill 329876
+nop
+.LBB2:
+
+.set val, 0x12345678
+
+# CHECK-REL-NOT: R_LARCH
+
+## Testing the function call offset could resolved by assembler
+## when the function and the callsite within the same compile unit.
+func:
+.fill 100
+bl func
+# CHECK-FIXUP: fixup A - offset: 0, value: func, kind: fixup_loongarch_b26
+# CHECK-INSTR: bl -100
+
+.fill 10000
+bl func
+# CHECK-FIXUP: fixup A - offset: 0, value: func, kind: fixup_loongarch_b26
+# CHECK-INSTR: bl -10104
+
+.fill 20888
+bl func
+# CHECK-FIXUP: fixup A - offset: 0, value: func, kind: fixup_loongarch_b26
+# CHECK-INSTR: bl -30996