//
//===----------------------------------------------------------------------===//
-#include "MCTargetDesc/ARMMCTargetDesc.h"
-#include "MCTargetDesc/ARMAddressingModes.h"
#include "MCTargetDesc/ARMAsmBackend.h"
+#include "MCTargetDesc/ARMAddressingModes.h"
#include "MCTargetDesc/ARMAsmBackendDarwin.h"
#include "MCTargetDesc/ARMAsmBackendELF.h"
#include "MCTargetDesc/ARMAsmBackendWinCOFF.h"
#include "MCTargetDesc/ARMBaseInfo.h"
#include "MCTargetDesc/ARMFixupKinds.h"
+#include "MCTargetDesc/ARMMCTargetDesc.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAssembler.h"
{"fixup_t2_movt_hi16", 0, 20, 0},
{"fixup_t2_movw_lo16", 0, 20, 0},
{"fixup_arm_mod_imm", 0, 12, 0},
+ {"fixup_t2_so_imm", 0, 26, 0},
};
const static MCFixupKindInfo InfosBE[ARM::NumTargetFixupKinds] = {
// This table *must* be in the order that the fixup_* kinds are defined in
{"fixup_t2_movt_hi16", 12, 20, 0},
{"fixup_t2_movw_lo16", 12, 20, 0},
{"fixup_arm_mod_imm", 20, 12, 0},
+ {"fixup_t2_so_imm", 26, 6, 0},
};
if (Kind < FirstTargetFixupKind)
}
unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
- bool IsPCRel, MCContext *Ctx,
+ bool IsPCRel, MCContext &Ctx,
bool IsLittleEndian,
bool IsResolved) const {
unsigned Kind = Fixup.getKind();
switch (Kind) {
default:
- if (Ctx) Ctx->reportError(Fixup.getLoc(), "bad relocation fixup type");
+ Ctx.reportError(Fixup.getLoc(), "bad relocation fixup type");
return 0;
case FK_Data_1:
case FK_Data_2:
Value = -Value;
isAdd = false;
}
- if (Ctx && Value >= 4096) {
- Ctx->reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
+ if (Value >= 4096) {
+ Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
return 0;
}
Value |= isAdd << 23;
Value = -Value;
opc = 2; // 0b0010
}
- if (Ctx && ARM_AM::getSOImmVal(Value) == -1) {
- Ctx->reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
+ if (ARM_AM::getSOImmVal(Value) == -1) {
+ Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
return 0;
}
// Encode the immediate and shift the opcode into place.
//
// Note that the halfwords are stored high first, low second; so we need
// to transpose the fixup value here to map properly.
- if (Ctx && Value % 4 != 0) {
- Ctx->reportError(Fixup.getLoc(), "misaligned ARM call destination");
+ if (Value % 4 != 0) {
+ Ctx.reportError(Fixup.getLoc(), "misaligned ARM call destination");
return 0;
}
case ARM::fixup_arm_thumb_cp:
// On CPUs supporting Thumb2, this will be relaxed to an ldr.w, otherwise we
// could have an error on our hands.
- if (Ctx && !STI->getFeatureBits()[ARM::FeatureThumb2] && IsResolved) {
+ if (!STI->getFeatureBits()[ARM::FeatureThumb2] && IsResolved) {
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
if (FixupDiagnostic) {
- Ctx->reportError(Fixup.getLoc(), FixupDiagnostic);
+ Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
return 0;
}
}
// CB instructions can only branch to offsets in [4, 126] in multiples of 2
// so ensure that the raw value LSB is zero and it lies in [2, 130].
// An offset of 2 will be relaxed to a NOP.
- if (Ctx && ((int64_t)Value < 2 || Value > 0x82 || Value & 1)) {
- Ctx->reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
+ if ((int64_t)Value < 2 || Value > 0x82 || Value & 1) {
+ Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
return 0;
}
// Offset by 4 and don't encode the lower bit, which is always 0.
}
case ARM::fixup_arm_thumb_br:
// Offset by 4 and don't encode the lower bit, which is always 0.
- if (Ctx && !STI->getFeatureBits()[ARM::FeatureThumb2] &&
- !STI->getFeatureBits()[ARM::HasV8MBaselineOps]) {
+ if (!STI->getFeatureBits()[ARM::FeatureThumb2] &&
+ !STI->getFeatureBits()[ARM::HasV8MBaselineOps]) {
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
if (FixupDiagnostic) {
- Ctx->reportError(Fixup.getLoc(), FixupDiagnostic);
+ Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
return 0;
}
}
return ((Value - 4) >> 1) & 0x7ff;
case ARM::fixup_arm_thumb_bcc:
// Offset by 4 and don't encode the lower bit, which is always 0.
- if (Ctx && !STI->getFeatureBits()[ARM::FeatureThumb2]) {
+ if (!STI->getFeatureBits()[ARM::FeatureThumb2]) {
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
if (FixupDiagnostic) {
- Ctx->reportError(Fixup.getLoc(), FixupDiagnostic);
+ Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
return 0;
}
}
isAdd = false;
}
// The value has the low 4 bits encoded in [3:0] and the high 4 in [11:8].
- if (Ctx && Value >= 256) {
- Ctx->reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
+ if (Value >= 256) {
+ Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
return 0;
}
Value = (Value & 0xf) | ((Value & 0xf0) << 4);
}
// These values don't encode the low two bits since they're always zero.
Value >>= 2;
- if (Ctx && Value >= 256) {
- Ctx->reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
+ if (Value >= 256) {
+ Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
return 0;
}
Value |= isAdd << 23;
isAdd = false;
}
// These values don't encode the low bit since it's always zero.
- if (Ctx && (Value & 1)) {
- Ctx->reportError(Fixup.getLoc(), "invalid value for this fixup");
+ if (Value & 1) {
+ Ctx.reportError(Fixup.getLoc(), "invalid value for this fixup");
return 0;
}
Value >>= 1;
- if (Ctx && Value >= 256) {
- Ctx->reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
+ if (Value >= 256) {
+ Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
return 0;
}
Value |= isAdd << 23;
}
case ARM::fixup_arm_mod_imm:
Value = ARM_AM::getSOImmVal(Value);
- if (Ctx && Value >> 12) {
- Ctx->reportError(Fixup.getLoc(), "out of range immediate fixup value");
+ if (Value >> 12) {
+ Ctx.reportError(Fixup.getLoc(), "out of range immediate fixup value");
return 0;
}
return Value;
+ case ARM::fixup_t2_so_imm: {
+ Value = ARM_AM::getT2SOImmVal(Value);
+ if ((int64_t)Value < 0) {
+ Ctx.reportError(Fixup.getLoc(), "out of range immediate fixup value");
+ return 0;
+ }
+ // Value will contain a 12-bit value broken up into a 4-bit shift in bits
+ // 11:8 and the 8-bit immediate in 0:7. The instruction has the immediate
+ // in 0:7. The 4-bit shift is split up into i:imm3 where i is placed at bit
+ // 10 of the upper half-word and imm3 is placed at 14:12 of the lower
+ // half-word.
+ uint64_t EncValue = 0;
+ EncValue |= (Value & 0x800) << 15;
+ EncValue |= (Value & 0x700) << 4;
+ EncValue |= (Value & 0xff);
+ return swapHalfWords(EncValue, IsLittleEndian);
+ }
}
}
// linker can handle it. GNU AS produces an error in this case.
if (Sym->isExternal() || Value >= 0x400004)
IsResolved = false;
+ // When an ARM function is called from a Thumb function, produce a
+ // relocation so the linker will use the correct branch instruction for ELF
+ // binaries.
+ if (Sym->isELF()) {
+ unsigned Type = dyn_cast<MCSymbolELF>(Sym)->getType();
+ if ((Type == ELF::STT_FUNC || Type == ELF::STT_GNU_IFUNC) &&
+ !Asm.isThumbFunc(Sym))
+ IsResolved = false;
+ }
}
// We must always generate a relocation for BL/BLX instructions if we have
// a symbol to reference, as the linker relies on knowing the destination
(unsigned)Fixup.getKind() == ARM::fixup_arm_uncondbl ||
(unsigned)Fixup.getKind() == ARM::fixup_arm_condbl))
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 aren't invalid.
- (void)adjustFixupValue(Fixup, Value, false, &Asm.getContext(),
- IsLittleEndian, IsResolved);
}
/// getFixupKindNumBytes - The number of bytes the fixup may change.
case ARM::fixup_arm_movw_lo16:
case ARM::fixup_t2_movt_hi16:
case ARM::fixup_t2_movw_lo16:
+ case ARM::fixup_t2_so_imm:
return 4;
case FK_SecRel_2:
case ARM::fixup_t2_movt_hi16:
case ARM::fixup_t2_movw_lo16:
case ARM::fixup_arm_mod_imm:
+ case ARM::fixup_t2_so_imm:
// Instruction size is 4 bytes.
return 4;
}
}
void ARMAsmBackend::applyFixup(const MCFixup &Fixup, char *Data,
- unsigned DataSize, uint64_t Value,
- bool IsPCRel) const {
+ unsigned DataSize, uint64_t Value, bool IsPCRel,
+ MCContext &Ctx) const {
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
- Value =
- adjustFixupValue(Fixup, Value, IsPCRel, nullptr, IsLittleEndian, true);
+ Value = adjustFixupValue(Fixup, Value, IsPCRel, Ctx, IsLittleEndian, true);
if (!Value)
return; // Doesn't change encoding.