10b57cec5SDimitry Andric //===-- ARMAsmBackend.cpp - ARM Assembler Backend -------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "MCTargetDesc/ARMAsmBackend.h"
100b57cec5SDimitry Andric #include "MCTargetDesc/ARMAddressingModes.h"
110b57cec5SDimitry Andric #include "MCTargetDesc/ARMAsmBackendDarwin.h"
120b57cec5SDimitry Andric #include "MCTargetDesc/ARMAsmBackendELF.h"
130b57cec5SDimitry Andric #include "MCTargetDesc/ARMAsmBackendWinCOFF.h"
140b57cec5SDimitry Andric #include "MCTargetDesc/ARMFixupKinds.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/ARMMCTargetDesc.h"
160b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
170b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
180b57cec5SDimitry Andric #include "llvm/BinaryFormat/MachO.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCDirectives.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h"
260b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h"
270b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
280b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h"
290b57cec5SDimitry Andric #include "llvm/MC/MCSectionMachO.h"
300b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
310fca6ea1SDimitry Andric #include "llvm/MC/MCTargetOptions.h"
320b57cec5SDimitry Andric #include "llvm/MC/MCValue.h"
330b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
340b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h"
350b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
360b57cec5SDimitry Andric #include "llvm/Support/Format.h"
370b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
380b57cec5SDimitry Andric using namespace llvm;
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric namespace {
410b57cec5SDimitry Andric class ARMELFObjectWriter : public MCELFObjectTargetWriter {
420b57cec5SDimitry Andric public:
ARMELFObjectWriter(uint8_t OSABI)430b57cec5SDimitry Andric ARMELFObjectWriter(uint8_t OSABI)
440b57cec5SDimitry Andric : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI, ELF::EM_ARM,
450b57cec5SDimitry Andric /*HasRelocationAddend*/ false) {}
460b57cec5SDimitry Andric };
470b57cec5SDimitry Andric } // end anonymous namespace
480b57cec5SDimitry Andric
getFixupKind(StringRef Name) const49bdd1243dSDimitry Andric std::optional<MCFixupKind> ARMAsmBackend::getFixupKind(StringRef Name) const {
50bdd1243dSDimitry Andric return std::nullopt;
51349cc55cSDimitry Andric }
520b57cec5SDimitry Andric
53bdd1243dSDimitry Andric std::optional<MCFixupKind>
getFixupKind(StringRef Name) const54bdd1243dSDimitry Andric ARMAsmBackendELF::getFixupKind(StringRef Name) const {
555ffd83dbSDimitry Andric unsigned Type = llvm::StringSwitch<unsigned>(Name)
565ffd83dbSDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y)
575ffd83dbSDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/ARM.def"
585ffd83dbSDimitry Andric #undef ELF_RELOC
59fe6060f1SDimitry Andric .Case("BFD_RELOC_NONE", ELF::R_ARM_NONE)
60fe6060f1SDimitry Andric .Case("BFD_RELOC_8", ELF::R_ARM_ABS8)
61fe6060f1SDimitry Andric .Case("BFD_RELOC_16", ELF::R_ARM_ABS16)
62fe6060f1SDimitry Andric .Case("BFD_RELOC_32", ELF::R_ARM_ABS32)
635ffd83dbSDimitry Andric .Default(-1u);
645ffd83dbSDimitry Andric if (Type == -1u)
65bdd1243dSDimitry Andric return std::nullopt;
665ffd83dbSDimitry Andric return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
getFixupKindInfo(MCFixupKind Kind) const690b57cec5SDimitry Andric const MCFixupKindInfo &ARMAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
700b57cec5SDimitry Andric const static MCFixupKindInfo InfosLE[ARM::NumTargetFixupKinds] = {
710b57cec5SDimitry Andric // This table *must* be in the order that the fixup_* kinds are defined in
720b57cec5SDimitry Andric // ARMFixupKinds.h.
730b57cec5SDimitry Andric //
740b57cec5SDimitry Andric // Name Offset (bits) Size (bits) Flags
755f757f3fSDimitry Andric {"fixup_arm_ldst_pcrel_12", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
760b57cec5SDimitry Andric {"fixup_t2_ldst_pcrel_12", 0, 32,
775f757f3fSDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
785f757f3fSDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
795f757f3fSDimitry Andric {"fixup_arm_pcrel_10_unscaled", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
807a6dacacSDimitry Andric {"fixup_arm_pcrel_10", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
810b57cec5SDimitry Andric {"fixup_t2_pcrel_10", 0, 32,
820b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
830b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
840b57cec5SDimitry Andric {"fixup_arm_pcrel_9", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
850b57cec5SDimitry Andric {"fixup_t2_pcrel_9", 0, 32,
867a6dacacSDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
877a6dacacSDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
88fe6060f1SDimitry Andric {"fixup_arm_ldst_abs_12", 0, 32, 0},
890b57cec5SDimitry Andric {"fixup_thumb_adr_pcrel_10", 0, 8,
905f757f3fSDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
915f757f3fSDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
925f757f3fSDimitry Andric {"fixup_arm_adr_pcrel_12", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
930b57cec5SDimitry Andric {"fixup_t2_adr_pcrel_12", 0, 32,
945f757f3fSDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
955f757f3fSDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
960b57cec5SDimitry Andric {"fixup_arm_condbranch", 0, 24, MCFixupKindInfo::FKF_IsPCRel},
970b57cec5SDimitry Andric {"fixup_arm_uncondbranch", 0, 24, MCFixupKindInfo::FKF_IsPCRel},
980b57cec5SDimitry Andric {"fixup_t2_condbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
990b57cec5SDimitry Andric {"fixup_t2_uncondbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1000b57cec5SDimitry Andric {"fixup_arm_thumb_br", 0, 16, MCFixupKindInfo::FKF_IsPCRel},
1010b57cec5SDimitry Andric {"fixup_arm_uncondbl", 0, 24, MCFixupKindInfo::FKF_IsPCRel},
1020b57cec5SDimitry Andric {"fixup_arm_condbl", 0, 24, MCFixupKindInfo::FKF_IsPCRel},
1030b57cec5SDimitry Andric {"fixup_arm_blx", 0, 24, MCFixupKindInfo::FKF_IsPCRel},
1040b57cec5SDimitry Andric {"fixup_arm_thumb_bl", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1050b57cec5SDimitry Andric {"fixup_arm_thumb_blx", 0, 32,
1060b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
1070b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
1080b57cec5SDimitry Andric {"fixup_arm_thumb_cb", 0, 16, MCFixupKindInfo::FKF_IsPCRel},
1090b57cec5SDimitry Andric {"fixup_arm_thumb_cp", 0, 8,
1100b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
1110b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
1120b57cec5SDimitry Andric {"fixup_arm_thumb_bcc", 0, 8, MCFixupKindInfo::FKF_IsPCRel},
1130b57cec5SDimitry Andric // movw / movt: 16-bits immediate but scattered into two chunks 0 - 12, 16
1140b57cec5SDimitry Andric // - 19.
1150b57cec5SDimitry Andric {"fixup_arm_movt_hi16", 0, 20, 0},
1160b57cec5SDimitry Andric {"fixup_arm_movw_lo16", 0, 20, 0},
1170b57cec5SDimitry Andric {"fixup_t2_movt_hi16", 0, 20, 0},
1180b57cec5SDimitry Andric {"fixup_t2_movw_lo16", 0, 20, 0},
11906c3fb27SDimitry Andric {"fixup_arm_thumb_upper_8_15", 0, 8, 0},
12006c3fb27SDimitry Andric {"fixup_arm_thumb_upper_0_7", 0, 8, 0},
12106c3fb27SDimitry Andric {"fixup_arm_thumb_lower_8_15", 0, 8, 0},
12206c3fb27SDimitry Andric {"fixup_arm_thumb_lower_0_7", 0, 8, 0},
1230b57cec5SDimitry Andric {"fixup_arm_mod_imm", 0, 12, 0},
1240b57cec5SDimitry Andric {"fixup_t2_so_imm", 0, 26, 0},
1250b57cec5SDimitry Andric {"fixup_bf_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1260b57cec5SDimitry Andric {"fixup_bf_target", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1270b57cec5SDimitry Andric {"fixup_bfl_target", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1280b57cec5SDimitry Andric {"fixup_bfc_target", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1290b57cec5SDimitry Andric {"fixup_bfcsel_else_target", 0, 32, 0},
1300b57cec5SDimitry Andric {"fixup_wls", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
131fe6060f1SDimitry Andric {"fixup_le", 0, 32, MCFixupKindInfo::FKF_IsPCRel}};
1320b57cec5SDimitry Andric const static MCFixupKindInfo InfosBE[ARM::NumTargetFixupKinds] = {
1330b57cec5SDimitry Andric // This table *must* be in the order that the fixup_* kinds are defined in
1340b57cec5SDimitry Andric // ARMFixupKinds.h.
1350b57cec5SDimitry Andric //
1360b57cec5SDimitry Andric // Name Offset (bits) Size (bits) Flags
1375f757f3fSDimitry Andric {"fixup_arm_ldst_pcrel_12", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1380b57cec5SDimitry Andric {"fixup_t2_ldst_pcrel_12", 0, 32,
1395f757f3fSDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
1405f757f3fSDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
1415f757f3fSDimitry Andric {"fixup_arm_pcrel_10_unscaled", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1427a6dacacSDimitry Andric {"fixup_arm_pcrel_10", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1430b57cec5SDimitry Andric {"fixup_t2_pcrel_10", 0, 32,
1440b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
1450b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
1460b57cec5SDimitry Andric {"fixup_arm_pcrel_9", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1470b57cec5SDimitry Andric {"fixup_t2_pcrel_9", 0, 32,
1487a6dacacSDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
1497a6dacacSDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
150fe6060f1SDimitry Andric {"fixup_arm_ldst_abs_12", 0, 32, 0},
1510b57cec5SDimitry Andric {"fixup_thumb_adr_pcrel_10", 8, 8,
1527a6dacacSDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
1537a6dacacSDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
1547a6dacacSDimitry Andric {"fixup_arm_adr_pcrel_12", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1550b57cec5SDimitry Andric {"fixup_t2_adr_pcrel_12", 0, 32,
1567a6dacacSDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
1577a6dacacSDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
1580b57cec5SDimitry Andric {"fixup_arm_condbranch", 8, 24, MCFixupKindInfo::FKF_IsPCRel},
1590b57cec5SDimitry Andric {"fixup_arm_uncondbranch", 8, 24, MCFixupKindInfo::FKF_IsPCRel},
1600b57cec5SDimitry Andric {"fixup_t2_condbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1610b57cec5SDimitry Andric {"fixup_t2_uncondbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1620b57cec5SDimitry Andric {"fixup_arm_thumb_br", 0, 16, MCFixupKindInfo::FKF_IsPCRel},
1630b57cec5SDimitry Andric {"fixup_arm_uncondbl", 8, 24, MCFixupKindInfo::FKF_IsPCRel},
1640b57cec5SDimitry Andric {"fixup_arm_condbl", 8, 24, MCFixupKindInfo::FKF_IsPCRel},
1650b57cec5SDimitry Andric {"fixup_arm_blx", 8, 24, MCFixupKindInfo::FKF_IsPCRel},
1660b57cec5SDimitry Andric {"fixup_arm_thumb_bl", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1670b57cec5SDimitry Andric {"fixup_arm_thumb_blx", 0, 32,
1680b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
1690b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
1700b57cec5SDimitry Andric {"fixup_arm_thumb_cb", 0, 16, MCFixupKindInfo::FKF_IsPCRel},
1710b57cec5SDimitry Andric {"fixup_arm_thumb_cp", 8, 8,
1720b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsPCRel |
1730b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
1740b57cec5SDimitry Andric {"fixup_arm_thumb_bcc", 8, 8, MCFixupKindInfo::FKF_IsPCRel},
1750b57cec5SDimitry Andric // movw / movt: 16-bits immediate but scattered into two chunks 0 - 12, 16
1760b57cec5SDimitry Andric // - 19.
1770b57cec5SDimitry Andric {"fixup_arm_movt_hi16", 12, 20, 0},
1780b57cec5SDimitry Andric {"fixup_arm_movw_lo16", 12, 20, 0},
1790b57cec5SDimitry Andric {"fixup_t2_movt_hi16", 12, 20, 0},
1800b57cec5SDimitry Andric {"fixup_t2_movw_lo16", 12, 20, 0},
18106c3fb27SDimitry Andric {"fixup_arm_thumb_upper_8_15", 24, 8, 0},
18206c3fb27SDimitry Andric {"fixup_arm_thumb_upper_0_7", 24, 8, 0},
18306c3fb27SDimitry Andric {"fixup_arm_thumb_lower_8_15", 24, 8, 0},
18406c3fb27SDimitry Andric {"fixup_arm_thumb_lower_0_7", 24, 8, 0},
1850b57cec5SDimitry Andric {"fixup_arm_mod_imm", 20, 12, 0},
1860b57cec5SDimitry Andric {"fixup_t2_so_imm", 26, 6, 0},
1870b57cec5SDimitry Andric {"fixup_bf_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1880b57cec5SDimitry Andric {"fixup_bf_target", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1890b57cec5SDimitry Andric {"fixup_bfl_target", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1900b57cec5SDimitry Andric {"fixup_bfc_target", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
1910b57cec5SDimitry Andric {"fixup_bfcsel_else_target", 0, 32, 0},
1920b57cec5SDimitry Andric {"fixup_wls", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
193fe6060f1SDimitry Andric {"fixup_le", 0, 32, MCFixupKindInfo::FKF_IsPCRel}};
1940b57cec5SDimitry Andric
1955ffd83dbSDimitry Andric // Fixup kinds from .reloc directive are like R_ARM_NONE. They do not require
1965ffd83dbSDimitry Andric // any extra processing.
1975ffd83dbSDimitry Andric if (Kind >= FirstLiteralRelocationKind)
1985ffd83dbSDimitry Andric return MCAsmBackend::getFixupKindInfo(FK_NONE);
1995ffd83dbSDimitry Andric
2000b57cec5SDimitry Andric if (Kind < FirstTargetFixupKind)
2010b57cec5SDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind);
2020b57cec5SDimitry Andric
2030b57cec5SDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
2040b57cec5SDimitry Andric "Invalid kind!");
2055f757f3fSDimitry Andric return (Endian == llvm::endianness::little
2065f757f3fSDimitry Andric ? InfosLE
2070b57cec5SDimitry Andric : InfosBE)[Kind - FirstTargetFixupKind];
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric
handleAssemblerFlag(MCAssemblerFlag Flag)2100b57cec5SDimitry Andric void ARMAsmBackend::handleAssemblerFlag(MCAssemblerFlag Flag) {
2110b57cec5SDimitry Andric switch (Flag) {
2120b57cec5SDimitry Andric default:
2130b57cec5SDimitry Andric break;
2140b57cec5SDimitry Andric case MCAF_Code16:
2150b57cec5SDimitry Andric setIsThumb(true);
2160b57cec5SDimitry Andric break;
2170b57cec5SDimitry Andric case MCAF_Code32:
2180b57cec5SDimitry Andric setIsThumb(false);
2190b57cec5SDimitry Andric break;
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric
getRelaxedOpcode(unsigned Op,const MCSubtargetInfo & STI) const2230b57cec5SDimitry Andric unsigned ARMAsmBackend::getRelaxedOpcode(unsigned Op,
2240b57cec5SDimitry Andric const MCSubtargetInfo &STI) const {
22506c3fb27SDimitry Andric bool HasThumb2 = STI.hasFeature(ARM::FeatureThumb2);
22606c3fb27SDimitry Andric bool HasV8MBaselineOps = STI.hasFeature(ARM::HasV8MBaselineOps);
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric switch (Op) {
2290b57cec5SDimitry Andric default:
2300b57cec5SDimitry Andric return Op;
2310b57cec5SDimitry Andric case ARM::tBcc:
2320b57cec5SDimitry Andric return HasThumb2 ? (unsigned)ARM::t2Bcc : Op;
2330b57cec5SDimitry Andric case ARM::tLDRpci:
2340b57cec5SDimitry Andric return HasThumb2 ? (unsigned)ARM::t2LDRpci : Op;
2350b57cec5SDimitry Andric case ARM::tADR:
2360b57cec5SDimitry Andric return HasThumb2 ? (unsigned)ARM::t2ADR : Op;
2370b57cec5SDimitry Andric case ARM::tB:
2380b57cec5SDimitry Andric return HasV8MBaselineOps ? (unsigned)ARM::t2B : Op;
2390b57cec5SDimitry Andric case ARM::tCBZ:
2400b57cec5SDimitry Andric return ARM::tHINT;
2410b57cec5SDimitry Andric case ARM::tCBNZ:
2420b57cec5SDimitry Andric return ARM::tHINT;
2430b57cec5SDimitry Andric }
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric
mayNeedRelaxation(const MCInst & Inst,const MCSubtargetInfo & STI) const2460b57cec5SDimitry Andric bool ARMAsmBackend::mayNeedRelaxation(const MCInst &Inst,
2470b57cec5SDimitry Andric const MCSubtargetInfo &STI) const {
2480b57cec5SDimitry Andric if (getRelaxedOpcode(Inst.getOpcode(), STI) != Inst.getOpcode())
2490b57cec5SDimitry Andric return true;
2500b57cec5SDimitry Andric return false;
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric
checkPCRelOffset(uint64_t Value,int64_t Min,int64_t Max)2530b57cec5SDimitry Andric static const char *checkPCRelOffset(uint64_t Value, int64_t Min, int64_t Max) {
2540b57cec5SDimitry Andric int64_t Offset = int64_t(Value) - 4;
2550b57cec5SDimitry Andric if (Offset < Min || Offset > Max)
2560b57cec5SDimitry Andric return "out of range pc-relative fixup value";
2570b57cec5SDimitry Andric return nullptr;
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric
reasonForFixupRelaxation(const MCFixup & Fixup,uint64_t Value) const2600b57cec5SDimitry Andric const char *ARMAsmBackend::reasonForFixupRelaxation(const MCFixup &Fixup,
2610b57cec5SDimitry Andric uint64_t Value) const {
2628bcb0991SDimitry Andric switch (Fixup.getTargetKind()) {
2630b57cec5SDimitry Andric case ARM::fixup_arm_thumb_br: {
2640b57cec5SDimitry Andric // Relaxing tB to t2B. tB has a signed 12-bit displacement with the
2650b57cec5SDimitry Andric // low bit being an implied zero. There's an implied +4 offset for the
2660b57cec5SDimitry Andric // branch, so we adjust the other way here to determine what's
2670b57cec5SDimitry Andric // encodable.
2680b57cec5SDimitry Andric //
2690b57cec5SDimitry Andric // Relax if the value is too big for a (signed) i8.
2700b57cec5SDimitry Andric int64_t Offset = int64_t(Value) - 4;
2710b57cec5SDimitry Andric if (Offset > 2046 || Offset < -2048)
2720b57cec5SDimitry Andric return "out of range pc-relative fixup value";
2730b57cec5SDimitry Andric break;
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric case ARM::fixup_arm_thumb_bcc: {
2760b57cec5SDimitry Andric // Relaxing tBcc to t2Bcc. tBcc has a signed 9-bit displacement with the
2770b57cec5SDimitry Andric // low bit being an implied zero. There's an implied +4 offset for the
2780b57cec5SDimitry Andric // branch, so we adjust the other way here to determine what's
2790b57cec5SDimitry Andric // encodable.
2800b57cec5SDimitry Andric //
2810b57cec5SDimitry Andric // Relax if the value is too big for a (signed) i8.
2820b57cec5SDimitry Andric int64_t Offset = int64_t(Value) - 4;
2830b57cec5SDimitry Andric if (Offset > 254 || Offset < -256)
2840b57cec5SDimitry Andric return "out of range pc-relative fixup value";
2850b57cec5SDimitry Andric break;
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric case ARM::fixup_thumb_adr_pcrel_10:
2880b57cec5SDimitry Andric case ARM::fixup_arm_thumb_cp: {
2890b57cec5SDimitry Andric // If the immediate is negative, greater than 1020, or not a multiple
2900b57cec5SDimitry Andric // of four, the wide version of the instruction must be used.
2910b57cec5SDimitry Andric int64_t Offset = int64_t(Value) - 4;
2920b57cec5SDimitry Andric if (Offset & 3)
2930b57cec5SDimitry Andric return "misaligned pc-relative fixup value";
2940b57cec5SDimitry Andric else if (Offset > 1020 || Offset < 0)
2950b57cec5SDimitry Andric return "out of range pc-relative fixup value";
2960b57cec5SDimitry Andric break;
2970b57cec5SDimitry Andric }
2980b57cec5SDimitry Andric case ARM::fixup_arm_thumb_cb: {
2990b57cec5SDimitry Andric // If we have a Thumb CBZ or CBNZ instruction and its target is the next
3000b57cec5SDimitry Andric // instruction it is actually out of range for the instruction.
3010b57cec5SDimitry Andric // It will be changed to a NOP.
3020b57cec5SDimitry Andric int64_t Offset = (Value & ~1);
3030b57cec5SDimitry Andric if (Offset == 2)
3040b57cec5SDimitry Andric return "will be converted to nop";
3050b57cec5SDimitry Andric break;
3060b57cec5SDimitry Andric }
3070b57cec5SDimitry Andric case ARM::fixup_bf_branch:
3080b57cec5SDimitry Andric return checkPCRelOffset(Value, 0, 30);
3090b57cec5SDimitry Andric case ARM::fixup_bf_target:
3100b57cec5SDimitry Andric return checkPCRelOffset(Value, -0x10000, +0xfffe);
3110b57cec5SDimitry Andric case ARM::fixup_bfl_target:
3120b57cec5SDimitry Andric return checkPCRelOffset(Value, -0x40000, +0x3fffe);
3130b57cec5SDimitry Andric case ARM::fixup_bfc_target:
3140b57cec5SDimitry Andric return checkPCRelOffset(Value, -0x1000, +0xffe);
3150b57cec5SDimitry Andric case ARM::fixup_wls:
3160b57cec5SDimitry Andric return checkPCRelOffset(Value, 0, +0xffe);
3170b57cec5SDimitry Andric case ARM::fixup_le:
3180b57cec5SDimitry Andric // The offset field in the LE and LETP instructions is an 11-bit
3190b57cec5SDimitry Andric // value shifted left by 2 (i.e. 0,2,4,...,4094), and it is
3200b57cec5SDimitry Andric // interpreted as a negative offset from the value read from pc,
3210b57cec5SDimitry Andric // i.e. from instruction_address+4.
3220b57cec5SDimitry Andric //
3230b57cec5SDimitry Andric // So an LE instruction can in principle address the instruction
3240b57cec5SDimitry Andric // immediately after itself, or (not very usefully) the address
3250b57cec5SDimitry Andric // half way through the 4-byte LE.
3260b57cec5SDimitry Andric return checkPCRelOffset(Value, -0xffe, 0);
3270b57cec5SDimitry Andric case ARM::fixup_bfcsel_else_target: {
3280b57cec5SDimitry Andric if (Value != 2 && Value != 4)
3290b57cec5SDimitry Andric return "out of range label-relative fixup value";
3300b57cec5SDimitry Andric break;
3310b57cec5SDimitry Andric }
3320b57cec5SDimitry Andric
3330b57cec5SDimitry Andric default:
3340b57cec5SDimitry Andric llvm_unreachable("Unexpected fixup kind in reasonForFixupRelaxation()!");
3350b57cec5SDimitry Andric }
3360b57cec5SDimitry Andric return nullptr;
3370b57cec5SDimitry Andric }
3380b57cec5SDimitry Andric
fixupNeedsRelaxation(const MCFixup & Fixup,uint64_t Value) const3390fca6ea1SDimitry Andric bool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
3400fca6ea1SDimitry Andric uint64_t Value) const {
3410b57cec5SDimitry Andric return reasonForFixupRelaxation(Fixup, Value);
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const3445ffd83dbSDimitry Andric void ARMAsmBackend::relaxInstruction(MCInst &Inst,
3455ffd83dbSDimitry Andric const MCSubtargetInfo &STI) const {
3460b57cec5SDimitry Andric unsigned RelaxedOp = getRelaxedOpcode(Inst.getOpcode(), STI);
3470b57cec5SDimitry Andric
348349cc55cSDimitry Andric // Return a diagnostic if we get here w/ a bogus instruction.
3490b57cec5SDimitry Andric if (RelaxedOp == Inst.getOpcode()) {
3500b57cec5SDimitry Andric SmallString<256> Tmp;
3510b57cec5SDimitry Andric raw_svector_ostream OS(Tmp);
3520b57cec5SDimitry Andric Inst.dump_pretty(OS);
3530b57cec5SDimitry Andric OS << "\n";
3540b57cec5SDimitry Andric report_fatal_error("unexpected instruction to relax: " + OS.str());
3550b57cec5SDimitry Andric }
3560b57cec5SDimitry Andric
3570b57cec5SDimitry Andric // If we are changing Thumb CBZ or CBNZ instruction to a NOP, aka tHINT, we
3580b57cec5SDimitry Andric // have to change the operands too.
3590b57cec5SDimitry Andric if ((Inst.getOpcode() == ARM::tCBZ || Inst.getOpcode() == ARM::tCBNZ) &&
3600b57cec5SDimitry Andric RelaxedOp == ARM::tHINT) {
3615ffd83dbSDimitry Andric MCInst Res;
3620b57cec5SDimitry Andric Res.setOpcode(RelaxedOp);
3630b57cec5SDimitry Andric Res.addOperand(MCOperand::createImm(0));
3640b57cec5SDimitry Andric Res.addOperand(MCOperand::createImm(14));
3650b57cec5SDimitry Andric Res.addOperand(MCOperand::createReg(0));
3665ffd83dbSDimitry Andric Inst = std::move(Res);
3670b57cec5SDimitry Andric return;
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric
3700b57cec5SDimitry Andric // The rest of instructions we're relaxing have the same operands.
3710b57cec5SDimitry Andric // We just need to update to the proper opcode.
3725ffd83dbSDimitry Andric Inst.setOpcode(RelaxedOp);
3730b57cec5SDimitry Andric }
3740b57cec5SDimitry Andric
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const375349cc55cSDimitry Andric bool ARMAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
376349cc55cSDimitry Andric const MCSubtargetInfo *STI) const {
3770b57cec5SDimitry Andric const uint16_t Thumb1_16bitNopEncoding = 0x46c0; // using MOV r8,r8
3780b57cec5SDimitry Andric const uint16_t Thumb2_16bitNopEncoding = 0xbf00; // NOP
3790b57cec5SDimitry Andric const uint32_t ARMv4_NopEncoding = 0xe1a00000; // using MOV r0,r0
3800b57cec5SDimitry Andric const uint32_t ARMv6T2_NopEncoding = 0xe320f000; // NOP
3810b57cec5SDimitry Andric if (isThumb()) {
3820b57cec5SDimitry Andric const uint16_t nopEncoding =
383349cc55cSDimitry Andric hasNOP(STI) ? Thumb2_16bitNopEncoding : Thumb1_16bitNopEncoding;
3840b57cec5SDimitry Andric uint64_t NumNops = Count / 2;
3850b57cec5SDimitry Andric for (uint64_t i = 0; i != NumNops; ++i)
3860b57cec5SDimitry Andric support::endian::write(OS, nopEncoding, Endian);
3870b57cec5SDimitry Andric if (Count & 1)
3880b57cec5SDimitry Andric OS << '\0';
3890b57cec5SDimitry Andric return true;
3900b57cec5SDimitry Andric }
3910b57cec5SDimitry Andric // ARM mode
3920b57cec5SDimitry Andric const uint32_t nopEncoding =
393349cc55cSDimitry Andric hasNOP(STI) ? ARMv6T2_NopEncoding : ARMv4_NopEncoding;
3940b57cec5SDimitry Andric uint64_t NumNops = Count / 4;
3950b57cec5SDimitry Andric for (uint64_t i = 0; i != NumNops; ++i)
3960b57cec5SDimitry Andric support::endian::write(OS, nopEncoding, Endian);
3970b57cec5SDimitry Andric // FIXME: should this function return false when unable to write exactly
3980b57cec5SDimitry Andric // 'Count' bytes with NOP encodings?
3990b57cec5SDimitry Andric switch (Count % 4) {
4000b57cec5SDimitry Andric default:
4010b57cec5SDimitry Andric break; // No leftover bytes to write
4020b57cec5SDimitry Andric case 1:
4030b57cec5SDimitry Andric OS << '\0';
4040b57cec5SDimitry Andric break;
4050b57cec5SDimitry Andric case 2:
4060b57cec5SDimitry Andric OS.write("\0\0", 2);
4070b57cec5SDimitry Andric break;
4080b57cec5SDimitry Andric case 3:
4090b57cec5SDimitry Andric OS.write("\0\0\xa0", 3);
4100b57cec5SDimitry Andric break;
4110b57cec5SDimitry Andric }
4120b57cec5SDimitry Andric
4130b57cec5SDimitry Andric return true;
4140b57cec5SDimitry Andric }
4150b57cec5SDimitry Andric
swapHalfWords(uint32_t Value,bool IsLittleEndian)4160b57cec5SDimitry Andric static uint32_t swapHalfWords(uint32_t Value, bool IsLittleEndian) {
4170b57cec5SDimitry Andric if (IsLittleEndian) {
4180b57cec5SDimitry Andric // Note that the halfwords are stored high first and low second in thumb;
4190b57cec5SDimitry Andric // so we need to swap the fixup value here to map properly.
4200b57cec5SDimitry Andric uint32_t Swapped = (Value & 0xFFFF0000) >> 16;
4210b57cec5SDimitry Andric Swapped |= (Value & 0x0000FFFF) << 16;
4220b57cec5SDimitry Andric return Swapped;
4230b57cec5SDimitry Andric } else
4240b57cec5SDimitry Andric return Value;
4250b57cec5SDimitry Andric }
4260b57cec5SDimitry Andric
joinHalfWords(uint32_t FirstHalf,uint32_t SecondHalf,bool IsLittleEndian)4270b57cec5SDimitry Andric static uint32_t joinHalfWords(uint32_t FirstHalf, uint32_t SecondHalf,
4280b57cec5SDimitry Andric bool IsLittleEndian) {
4290b57cec5SDimitry Andric uint32_t Value;
4300b57cec5SDimitry Andric
4310b57cec5SDimitry Andric if (IsLittleEndian) {
4320b57cec5SDimitry Andric Value = (SecondHalf & 0xFFFF) << 16;
4330b57cec5SDimitry Andric Value |= (FirstHalf & 0xFFFF);
4340b57cec5SDimitry Andric } else {
4350b57cec5SDimitry Andric Value = (SecondHalf & 0xFFFF);
4360b57cec5SDimitry Andric Value |= (FirstHalf & 0xFFFF) << 16;
4370b57cec5SDimitry Andric }
4380b57cec5SDimitry Andric
4390b57cec5SDimitry Andric return Value;
4400b57cec5SDimitry Andric }
4410b57cec5SDimitry Andric
adjustFixupValue(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,uint64_t Value,bool IsResolved,MCContext & Ctx,const MCSubtargetInfo * STI) const4420b57cec5SDimitry Andric unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
4430b57cec5SDimitry Andric const MCFixup &Fixup,
4440b57cec5SDimitry Andric const MCValue &Target, uint64_t Value,
4450b57cec5SDimitry Andric bool IsResolved, MCContext &Ctx,
4460b57cec5SDimitry Andric const MCSubtargetInfo* STI) const {
4470b57cec5SDimitry Andric unsigned Kind = Fixup.getKind();
4480b57cec5SDimitry Andric
4490b57cec5SDimitry Andric // MachO tries to make .o files that look vaguely pre-linked, so for MOVW/MOVT
4500b57cec5SDimitry Andric // and .word relocations they put the Thumb bit into the addend if possible.
4510b57cec5SDimitry Andric // Other relocation types don't want this bit though (branches couldn't encode
4520b57cec5SDimitry Andric // it if it *was* present, and no other relocations exist) and it can
4530b57cec5SDimitry Andric // interfere with checking valid expressions.
4540b57cec5SDimitry Andric if (const MCSymbolRefExpr *A = Target.getSymA()) {
4550b57cec5SDimitry Andric if (A->hasSubsectionsViaSymbols() && Asm.isThumbFunc(&A->getSymbol()) &&
4560b57cec5SDimitry Andric A->getSymbol().isExternal() &&
4570b57cec5SDimitry Andric (Kind == FK_Data_4 || Kind == ARM::fixup_arm_movw_lo16 ||
4580b57cec5SDimitry Andric Kind == ARM::fixup_arm_movt_hi16 || Kind == ARM::fixup_t2_movw_lo16 ||
4590b57cec5SDimitry Andric Kind == ARM::fixup_t2_movt_hi16))
4600b57cec5SDimitry Andric Value |= 1;
4610b57cec5SDimitry Andric }
4620b57cec5SDimitry Andric
4630b57cec5SDimitry Andric switch (Kind) {
4640b57cec5SDimitry Andric default:
4650b57cec5SDimitry Andric return 0;
4660b57cec5SDimitry Andric case FK_Data_1:
4670b57cec5SDimitry Andric case FK_Data_2:
4680b57cec5SDimitry Andric case FK_Data_4:
4690b57cec5SDimitry Andric return Value;
4700b57cec5SDimitry Andric case FK_SecRel_2:
4710b57cec5SDimitry Andric return Value;
4720b57cec5SDimitry Andric case FK_SecRel_4:
4730b57cec5SDimitry Andric return Value;
4740b57cec5SDimitry Andric case ARM::fixup_arm_movt_hi16:
4750b57cec5SDimitry Andric assert(STI != nullptr);
4760b57cec5SDimitry Andric if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
4770b57cec5SDimitry Andric Value >>= 16;
478bdd1243dSDimitry Andric [[fallthrough]];
4790b57cec5SDimitry Andric case ARM::fixup_arm_movw_lo16: {
4800b57cec5SDimitry Andric unsigned Hi4 = (Value & 0xF000) >> 12;
4810b57cec5SDimitry Andric unsigned Lo12 = Value & 0x0FFF;
4820b57cec5SDimitry Andric // inst{19-16} = Hi4;
4830b57cec5SDimitry Andric // inst{11-0} = Lo12;
4840b57cec5SDimitry Andric Value = (Hi4 << 16) | (Lo12);
4850b57cec5SDimitry Andric return Value;
4860b57cec5SDimitry Andric }
4870b57cec5SDimitry Andric case ARM::fixup_t2_movt_hi16:
4880b57cec5SDimitry Andric assert(STI != nullptr);
4890b57cec5SDimitry Andric if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
4900b57cec5SDimitry Andric Value >>= 16;
491bdd1243dSDimitry Andric [[fallthrough]];
4920b57cec5SDimitry Andric case ARM::fixup_t2_movw_lo16: {
4930b57cec5SDimitry Andric unsigned Hi4 = (Value & 0xF000) >> 12;
4940b57cec5SDimitry Andric unsigned i = (Value & 0x800) >> 11;
4950b57cec5SDimitry Andric unsigned Mid3 = (Value & 0x700) >> 8;
4960b57cec5SDimitry Andric unsigned Lo8 = Value & 0x0FF;
4970b57cec5SDimitry Andric // inst{19-16} = Hi4;
4980b57cec5SDimitry Andric // inst{26} = i;
4990b57cec5SDimitry Andric // inst{14-12} = Mid3;
5000b57cec5SDimitry Andric // inst{7-0} = Lo8;
5010b57cec5SDimitry Andric Value = (Hi4 << 16) | (i << 26) | (Mid3 << 12) | (Lo8);
5025f757f3fSDimitry Andric return swapHalfWords(Value, Endian == llvm::endianness::little);
5030b57cec5SDimitry Andric }
50406c3fb27SDimitry Andric case ARM::fixup_arm_thumb_upper_8_15:
50506c3fb27SDimitry Andric if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
50606c3fb27SDimitry Andric return (Value & 0xff000000) >> 24;
50706c3fb27SDimitry Andric return Value & 0xff;
50806c3fb27SDimitry Andric case ARM::fixup_arm_thumb_upper_0_7:
50906c3fb27SDimitry Andric if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
51006c3fb27SDimitry Andric return (Value & 0x00ff0000) >> 16;
51106c3fb27SDimitry Andric return Value & 0xff;
51206c3fb27SDimitry Andric case ARM::fixup_arm_thumb_lower_8_15:
51306c3fb27SDimitry Andric if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
51406c3fb27SDimitry Andric return (Value & 0x0000ff00) >> 8;
51506c3fb27SDimitry Andric return Value & 0xff;
51606c3fb27SDimitry Andric case ARM::fixup_arm_thumb_lower_0_7:
51706c3fb27SDimitry Andric return Value & 0x000000ff;
5180b57cec5SDimitry Andric case ARM::fixup_arm_ldst_pcrel_12:
5190b57cec5SDimitry Andric // ARM PC-relative values are offset by 8.
5200b57cec5SDimitry Andric Value -= 4;
521bdd1243dSDimitry Andric [[fallthrough]];
522fe6060f1SDimitry Andric case ARM::fixup_t2_ldst_pcrel_12:
5230b57cec5SDimitry Andric // Offset by 4, adjusted by two due to the half-word ordering of thumb.
5240b57cec5SDimitry Andric Value -= 4;
525bdd1243dSDimitry Andric [[fallthrough]];
526fe6060f1SDimitry Andric case ARM::fixup_arm_ldst_abs_12: {
5270b57cec5SDimitry Andric bool isAdd = true;
5280b57cec5SDimitry Andric if ((int64_t)Value < 0) {
5290b57cec5SDimitry Andric Value = -Value;
5300b57cec5SDimitry Andric isAdd = false;
5310b57cec5SDimitry Andric }
5320b57cec5SDimitry Andric if (Value >= 4096) {
5330b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
5340b57cec5SDimitry Andric return 0;
5350b57cec5SDimitry Andric }
5360b57cec5SDimitry Andric Value |= isAdd << 23;
5370b57cec5SDimitry Andric
5380b57cec5SDimitry Andric // Same addressing mode as fixup_arm_pcrel_10,
5390b57cec5SDimitry Andric // but with 16-bit halfwords swapped.
5400b57cec5SDimitry Andric if (Kind == ARM::fixup_t2_ldst_pcrel_12)
5415f757f3fSDimitry Andric return swapHalfWords(Value, Endian == llvm::endianness::little);
5420b57cec5SDimitry Andric
5430b57cec5SDimitry Andric return Value;
5440b57cec5SDimitry Andric }
5450b57cec5SDimitry Andric case ARM::fixup_arm_adr_pcrel_12: {
5460b57cec5SDimitry Andric // ARM PC-relative values are offset by 8.
5470b57cec5SDimitry Andric Value -= 8;
5480b57cec5SDimitry Andric unsigned opc = 4; // bits {24-21}. Default to add: 0b0100
5490b57cec5SDimitry Andric if ((int64_t)Value < 0) {
5500b57cec5SDimitry Andric Value = -Value;
5510b57cec5SDimitry Andric opc = 2; // 0b0010
5520b57cec5SDimitry Andric }
5530b57cec5SDimitry Andric if (ARM_AM::getSOImmVal(Value) == -1) {
5540b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
5550b57cec5SDimitry Andric return 0;
5560b57cec5SDimitry Andric }
5570b57cec5SDimitry Andric // Encode the immediate and shift the opcode into place.
5580b57cec5SDimitry Andric return ARM_AM::getSOImmVal(Value) | (opc << 21);
5590b57cec5SDimitry Andric }
5600b57cec5SDimitry Andric
5610b57cec5SDimitry Andric case ARM::fixup_t2_adr_pcrel_12: {
5620b57cec5SDimitry Andric Value -= 4;
5630b57cec5SDimitry Andric unsigned opc = 0;
5640b57cec5SDimitry Andric if ((int64_t)Value < 0) {
5650b57cec5SDimitry Andric Value = -Value;
5660b57cec5SDimitry Andric opc = 5;
5670b57cec5SDimitry Andric }
5680b57cec5SDimitry Andric
5690b57cec5SDimitry Andric uint32_t out = (opc << 21);
5700b57cec5SDimitry Andric out |= (Value & 0x800) << 15;
5710b57cec5SDimitry Andric out |= (Value & 0x700) << 4;
5720b57cec5SDimitry Andric out |= (Value & 0x0FF);
5730b57cec5SDimitry Andric
5745f757f3fSDimitry Andric return swapHalfWords(out, Endian == llvm::endianness::little);
5750b57cec5SDimitry Andric }
5760b57cec5SDimitry Andric
5770b57cec5SDimitry Andric case ARM::fixup_arm_condbranch:
5780b57cec5SDimitry Andric case ARM::fixup_arm_uncondbranch:
5790b57cec5SDimitry Andric case ARM::fixup_arm_uncondbl:
5800b57cec5SDimitry Andric case ARM::fixup_arm_condbl:
5810b57cec5SDimitry Andric case ARM::fixup_arm_blx:
5820b57cec5SDimitry Andric // These values don't encode the low two bits since they're always zero.
5830b57cec5SDimitry Andric // Offset by 8 just as above.
5840b57cec5SDimitry Andric if (const MCSymbolRefExpr *SRE =
5850b57cec5SDimitry Andric dyn_cast<MCSymbolRefExpr>(Fixup.getValue()))
5860b57cec5SDimitry Andric if (SRE->getKind() == MCSymbolRefExpr::VK_TLSCALL)
5870b57cec5SDimitry Andric return 0;
5880b57cec5SDimitry Andric return 0xffffff & ((Value - 8) >> 2);
5890b57cec5SDimitry Andric case ARM::fixup_t2_uncondbranch: {
5900b57cec5SDimitry Andric Value = Value - 4;
5910b57cec5SDimitry Andric if (!isInt<25>(Value)) {
5920b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "Relocation out of range");
5930b57cec5SDimitry Andric return 0;
5940b57cec5SDimitry Andric }
5950b57cec5SDimitry Andric
5960b57cec5SDimitry Andric Value >>= 1; // Low bit is not encoded.
5970b57cec5SDimitry Andric
5980b57cec5SDimitry Andric uint32_t out = 0;
5990b57cec5SDimitry Andric bool I = Value & 0x800000;
6000b57cec5SDimitry Andric bool J1 = Value & 0x400000;
6010b57cec5SDimitry Andric bool J2 = Value & 0x200000;
6020b57cec5SDimitry Andric J1 ^= I;
6030b57cec5SDimitry Andric J2 ^= I;
6040b57cec5SDimitry Andric
6050b57cec5SDimitry Andric out |= I << 26; // S bit
6060b57cec5SDimitry Andric out |= !J1 << 13; // J1 bit
6070b57cec5SDimitry Andric out |= !J2 << 11; // J2 bit
6080b57cec5SDimitry Andric out |= (Value & 0x1FF800) << 5; // imm6 field
6090b57cec5SDimitry Andric out |= (Value & 0x0007FF); // imm11 field
6100b57cec5SDimitry Andric
6115f757f3fSDimitry Andric return swapHalfWords(out, Endian == llvm::endianness::little);
6120b57cec5SDimitry Andric }
6130b57cec5SDimitry Andric case ARM::fixup_t2_condbranch: {
6140b57cec5SDimitry Andric Value = Value - 4;
6150b57cec5SDimitry Andric if (!isInt<21>(Value)) {
6160b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "Relocation out of range");
6170b57cec5SDimitry Andric return 0;
6180b57cec5SDimitry Andric }
6190b57cec5SDimitry Andric
6200b57cec5SDimitry Andric Value >>= 1; // Low bit is not encoded.
6210b57cec5SDimitry Andric
6220b57cec5SDimitry Andric uint64_t out = 0;
6230b57cec5SDimitry Andric out |= (Value & 0x80000) << 7; // S bit
6240b57cec5SDimitry Andric out |= (Value & 0x40000) >> 7; // J2 bit
6250b57cec5SDimitry Andric out |= (Value & 0x20000) >> 4; // J1 bit
6260b57cec5SDimitry Andric out |= (Value & 0x1F800) << 5; // imm6 field
6270b57cec5SDimitry Andric out |= (Value & 0x007FF); // imm11 field
6280b57cec5SDimitry Andric
6295f757f3fSDimitry Andric return swapHalfWords(out, Endian == llvm::endianness::little);
6300b57cec5SDimitry Andric }
6310b57cec5SDimitry Andric case ARM::fixup_arm_thumb_bl: {
6320b57cec5SDimitry Andric if (!isInt<25>(Value - 4) ||
63306c3fb27SDimitry Andric (!STI->hasFeature(ARM::FeatureThumb2) &&
63406c3fb27SDimitry Andric !STI->hasFeature(ARM::HasV8MBaselineOps) &&
63506c3fb27SDimitry Andric !STI->hasFeature(ARM::HasV6MOps) &&
6360b57cec5SDimitry Andric !isInt<23>(Value - 4))) {
6370b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "Relocation out of range");
6380b57cec5SDimitry Andric return 0;
6390b57cec5SDimitry Andric }
6400b57cec5SDimitry Andric
6410b57cec5SDimitry Andric // The value doesn't encode the low bit (always zero) and is offset by
6420b57cec5SDimitry Andric // four. The 32-bit immediate value is encoded as
6430b57cec5SDimitry Andric // imm32 = SignExtend(S:I1:I2:imm10:imm11:0)
6440b57cec5SDimitry Andric // where I1 = NOT(J1 ^ S) and I2 = NOT(J2 ^ S).
6450b57cec5SDimitry Andric // The value is encoded into disjoint bit positions in the destination
6460b57cec5SDimitry Andric // opcode. x = unchanged, I = immediate value bit, S = sign extension bit,
6470b57cec5SDimitry Andric // J = either J1 or J2 bit
6480b57cec5SDimitry Andric //
6490b57cec5SDimitry Andric // BL: xxxxxSIIIIIIIIII xxJxJIIIIIIIIIII
6500b57cec5SDimitry Andric //
6510b57cec5SDimitry Andric // Note that the halfwords are stored high first, low second; so we need
6520b57cec5SDimitry Andric // to transpose the fixup value here to map properly.
6530b57cec5SDimitry Andric uint32_t offset = (Value - 4) >> 1;
6540b57cec5SDimitry Andric uint32_t signBit = (offset & 0x800000) >> 23;
6550b57cec5SDimitry Andric uint32_t I1Bit = (offset & 0x400000) >> 22;
6560b57cec5SDimitry Andric uint32_t J1Bit = (I1Bit ^ 0x1) ^ signBit;
6570b57cec5SDimitry Andric uint32_t I2Bit = (offset & 0x200000) >> 21;
6580b57cec5SDimitry Andric uint32_t J2Bit = (I2Bit ^ 0x1) ^ signBit;
6590b57cec5SDimitry Andric uint32_t imm10Bits = (offset & 0x1FF800) >> 11;
6600b57cec5SDimitry Andric uint32_t imm11Bits = (offset & 0x000007FF);
6610b57cec5SDimitry Andric
6620b57cec5SDimitry Andric uint32_t FirstHalf = (((uint16_t)signBit << 10) | (uint16_t)imm10Bits);
6630b57cec5SDimitry Andric uint32_t SecondHalf = (((uint16_t)J1Bit << 13) | ((uint16_t)J2Bit << 11) |
6640b57cec5SDimitry Andric (uint16_t)imm11Bits);
6655f757f3fSDimitry Andric return joinHalfWords(FirstHalf, SecondHalf,
6665f757f3fSDimitry Andric Endian == llvm::endianness::little);
6670b57cec5SDimitry Andric }
6680b57cec5SDimitry Andric case ARM::fixup_arm_thumb_blx: {
6690b57cec5SDimitry Andric // The value doesn't encode the low two bits (always zero) and is offset by
6700b57cec5SDimitry Andric // four (see fixup_arm_thumb_cp). The 32-bit immediate value is encoded as
6710b57cec5SDimitry Andric // imm32 = SignExtend(S:I1:I2:imm10H:imm10L:00)
6720b57cec5SDimitry Andric // where I1 = NOT(J1 ^ S) and I2 = NOT(J2 ^ S).
6730b57cec5SDimitry Andric // The value is encoded into disjoint bit positions in the destination
6740b57cec5SDimitry Andric // opcode. x = unchanged, I = immediate value bit, S = sign extension bit,
6750b57cec5SDimitry Andric // J = either J1 or J2 bit, 0 = zero.
6760b57cec5SDimitry Andric //
6770b57cec5SDimitry Andric // BLX: xxxxxSIIIIIIIIII xxJxJIIIIIIIIII0
6780b57cec5SDimitry Andric //
6790b57cec5SDimitry Andric // Note that the halfwords are stored high first, low second; so we need
6800b57cec5SDimitry Andric // to transpose the fixup value here to map properly.
6810b57cec5SDimitry Andric if (Value % 4 != 0) {
6820b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "misaligned ARM call destination");
6830b57cec5SDimitry Andric return 0;
6840b57cec5SDimitry Andric }
6850b57cec5SDimitry Andric
6860b57cec5SDimitry Andric uint32_t offset = (Value - 4) >> 2;
6870b57cec5SDimitry Andric if (const MCSymbolRefExpr *SRE =
6880b57cec5SDimitry Andric dyn_cast<MCSymbolRefExpr>(Fixup.getValue()))
6890b57cec5SDimitry Andric if (SRE->getKind() == MCSymbolRefExpr::VK_TLSCALL)
6900b57cec5SDimitry Andric offset = 0;
6910b57cec5SDimitry Andric uint32_t signBit = (offset & 0x400000) >> 22;
6920b57cec5SDimitry Andric uint32_t I1Bit = (offset & 0x200000) >> 21;
6930b57cec5SDimitry Andric uint32_t J1Bit = (I1Bit ^ 0x1) ^ signBit;
6940b57cec5SDimitry Andric uint32_t I2Bit = (offset & 0x100000) >> 20;
6950b57cec5SDimitry Andric uint32_t J2Bit = (I2Bit ^ 0x1) ^ signBit;
6960b57cec5SDimitry Andric uint32_t imm10HBits = (offset & 0xFFC00) >> 10;
6970b57cec5SDimitry Andric uint32_t imm10LBits = (offset & 0x3FF);
6980b57cec5SDimitry Andric
6990b57cec5SDimitry Andric uint32_t FirstHalf = (((uint16_t)signBit << 10) | (uint16_t)imm10HBits);
7000b57cec5SDimitry Andric uint32_t SecondHalf = (((uint16_t)J1Bit << 13) | ((uint16_t)J2Bit << 11) |
7010b57cec5SDimitry Andric ((uint16_t)imm10LBits) << 1);
7025f757f3fSDimitry Andric return joinHalfWords(FirstHalf, SecondHalf,
7035f757f3fSDimitry Andric Endian == llvm::endianness::little);
7040b57cec5SDimitry Andric }
7050b57cec5SDimitry Andric case ARM::fixup_thumb_adr_pcrel_10:
7060b57cec5SDimitry Andric case ARM::fixup_arm_thumb_cp:
7070b57cec5SDimitry Andric // On CPUs supporting Thumb2, this will be relaxed to an ldr.w, otherwise we
7080b57cec5SDimitry Andric // could have an error on our hands.
7090b57cec5SDimitry Andric assert(STI != nullptr);
71006c3fb27SDimitry Andric if (!STI->hasFeature(ARM::FeatureThumb2) && IsResolved) {
7110b57cec5SDimitry Andric const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
7120b57cec5SDimitry Andric if (FixupDiagnostic) {
7130b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
7140b57cec5SDimitry Andric return 0;
7150b57cec5SDimitry Andric }
7160b57cec5SDimitry Andric }
7170b57cec5SDimitry Andric // Offset by 4, and don't encode the low two bits.
7180b57cec5SDimitry Andric return ((Value - 4) >> 2) & 0xff;
7190b57cec5SDimitry Andric case ARM::fixup_arm_thumb_cb: {
7200b57cec5SDimitry Andric // CB instructions can only branch to offsets in [4, 126] in multiples of 2
7210b57cec5SDimitry Andric // so ensure that the raw value LSB is zero and it lies in [2, 130].
7220b57cec5SDimitry Andric // An offset of 2 will be relaxed to a NOP.
7230b57cec5SDimitry Andric if ((int64_t)Value < 2 || Value > 0x82 || Value & 1) {
7240b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
7250b57cec5SDimitry Andric return 0;
7260b57cec5SDimitry Andric }
7270b57cec5SDimitry Andric // Offset by 4 and don't encode the lower bit, which is always 0.
7280b57cec5SDimitry Andric // FIXME: diagnose if no Thumb2
7290b57cec5SDimitry Andric uint32_t Binary = (Value - 4) >> 1;
7300b57cec5SDimitry Andric return ((Binary & 0x20) << 4) | ((Binary & 0x1f) << 3);
7310b57cec5SDimitry Andric }
7320b57cec5SDimitry Andric case ARM::fixup_arm_thumb_br:
7330b57cec5SDimitry Andric // Offset by 4 and don't encode the lower bit, which is always 0.
7340b57cec5SDimitry Andric assert(STI != nullptr);
73506c3fb27SDimitry Andric if (!STI->hasFeature(ARM::FeatureThumb2) &&
73606c3fb27SDimitry Andric !STI->hasFeature(ARM::HasV8MBaselineOps)) {
7370b57cec5SDimitry Andric const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
7380b57cec5SDimitry Andric if (FixupDiagnostic) {
7390b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
7400b57cec5SDimitry Andric return 0;
7410b57cec5SDimitry Andric }
7420b57cec5SDimitry Andric }
7430b57cec5SDimitry Andric return ((Value - 4) >> 1) & 0x7ff;
7440b57cec5SDimitry Andric case ARM::fixup_arm_thumb_bcc:
7450b57cec5SDimitry Andric // Offset by 4 and don't encode the lower bit, which is always 0.
7460b57cec5SDimitry Andric assert(STI != nullptr);
74706c3fb27SDimitry Andric if (!STI->hasFeature(ARM::FeatureThumb2)) {
7480b57cec5SDimitry Andric const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
7490b57cec5SDimitry Andric if (FixupDiagnostic) {
7500b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
7510b57cec5SDimitry Andric return 0;
7520b57cec5SDimitry Andric }
7530b57cec5SDimitry Andric }
7540b57cec5SDimitry Andric return ((Value - 4) >> 1) & 0xff;
7550b57cec5SDimitry Andric case ARM::fixup_arm_pcrel_10_unscaled: {
7560b57cec5SDimitry Andric Value = Value - 8; // ARM fixups offset by an additional word and don't
7570b57cec5SDimitry Andric // need to adjust for the half-word ordering.
7580b57cec5SDimitry Andric bool isAdd = true;
7590b57cec5SDimitry Andric if ((int64_t)Value < 0) {
7600b57cec5SDimitry Andric Value = -Value;
7610b57cec5SDimitry Andric isAdd = false;
7620b57cec5SDimitry Andric }
7630b57cec5SDimitry Andric // The value has the low 4 bits encoded in [3:0] and the high 4 in [11:8].
7640b57cec5SDimitry Andric if (Value >= 256) {
7650b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
7660b57cec5SDimitry Andric return 0;
7670b57cec5SDimitry Andric }
7680b57cec5SDimitry Andric Value = (Value & 0xf) | ((Value & 0xf0) << 4);
7690b57cec5SDimitry Andric return Value | (isAdd << 23);
7700b57cec5SDimitry Andric }
7710b57cec5SDimitry Andric case ARM::fixup_arm_pcrel_10:
7720b57cec5SDimitry Andric Value = Value - 4; // ARM fixups offset by an additional word and don't
7730b57cec5SDimitry Andric // need to adjust for the half-word ordering.
774bdd1243dSDimitry Andric [[fallthrough]];
7750b57cec5SDimitry Andric case ARM::fixup_t2_pcrel_10: {
7760b57cec5SDimitry Andric // Offset by 4, adjusted by two due to the half-word ordering of thumb.
7770b57cec5SDimitry Andric Value = Value - 4;
7780b57cec5SDimitry Andric bool isAdd = true;
7790b57cec5SDimitry Andric if ((int64_t)Value < 0) {
7800b57cec5SDimitry Andric Value = -Value;
7810b57cec5SDimitry Andric isAdd = false;
7820b57cec5SDimitry Andric }
7830b57cec5SDimitry Andric // These values don't encode the low two bits since they're always zero.
7840b57cec5SDimitry Andric Value >>= 2;
7850b57cec5SDimitry Andric if (Value >= 256) {
7860b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
7870b57cec5SDimitry Andric return 0;
7880b57cec5SDimitry Andric }
7890b57cec5SDimitry Andric Value |= isAdd << 23;
7900b57cec5SDimitry Andric
7910b57cec5SDimitry Andric // Same addressing mode as fixup_arm_pcrel_10, but with 16-bit halfwords
7920b57cec5SDimitry Andric // swapped.
7930b57cec5SDimitry Andric if (Kind == ARM::fixup_t2_pcrel_10)
7945f757f3fSDimitry Andric return swapHalfWords(Value, Endian == llvm::endianness::little);
7950b57cec5SDimitry Andric
7960b57cec5SDimitry Andric return Value;
7970b57cec5SDimitry Andric }
7980b57cec5SDimitry Andric case ARM::fixup_arm_pcrel_9:
7990b57cec5SDimitry Andric Value = Value - 4; // ARM fixups offset by an additional word and don't
8000b57cec5SDimitry Andric // need to adjust for the half-word ordering.
801bdd1243dSDimitry Andric [[fallthrough]];
8020b57cec5SDimitry Andric case ARM::fixup_t2_pcrel_9: {
8030b57cec5SDimitry Andric // Offset by 4, adjusted by two due to the half-word ordering of thumb.
8040b57cec5SDimitry Andric Value = Value - 4;
8050b57cec5SDimitry Andric bool isAdd = true;
8060b57cec5SDimitry Andric if ((int64_t)Value < 0) {
8070b57cec5SDimitry Andric Value = -Value;
8080b57cec5SDimitry Andric isAdd = false;
8090b57cec5SDimitry Andric }
8100b57cec5SDimitry Andric // These values don't encode the low bit since it's always zero.
8110b57cec5SDimitry Andric if (Value & 1) {
8120b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "invalid value for this fixup");
8130b57cec5SDimitry Andric return 0;
8140b57cec5SDimitry Andric }
8150b57cec5SDimitry Andric Value >>= 1;
8160b57cec5SDimitry Andric if (Value >= 256) {
8170b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value");
8180b57cec5SDimitry Andric return 0;
8190b57cec5SDimitry Andric }
8200b57cec5SDimitry Andric Value |= isAdd << 23;
8210b57cec5SDimitry Andric
8220b57cec5SDimitry Andric // Same addressing mode as fixup_arm_pcrel_9, but with 16-bit halfwords
8230b57cec5SDimitry Andric // swapped.
8240b57cec5SDimitry Andric if (Kind == ARM::fixup_t2_pcrel_9)
8255f757f3fSDimitry Andric return swapHalfWords(Value, Endian == llvm::endianness::little);
8260b57cec5SDimitry Andric
8270b57cec5SDimitry Andric return Value;
8280b57cec5SDimitry Andric }
8290b57cec5SDimitry Andric case ARM::fixup_arm_mod_imm:
8300b57cec5SDimitry Andric Value = ARM_AM::getSOImmVal(Value);
8310b57cec5SDimitry Andric if (Value >> 12) {
8320b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "out of range immediate fixup value");
8330b57cec5SDimitry Andric return 0;
8340b57cec5SDimitry Andric }
8350b57cec5SDimitry Andric return Value;
8360b57cec5SDimitry Andric case ARM::fixup_t2_so_imm: {
8370b57cec5SDimitry Andric Value = ARM_AM::getT2SOImmVal(Value);
8380b57cec5SDimitry Andric if ((int64_t)Value < 0) {
8390b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "out of range immediate fixup value");
8400b57cec5SDimitry Andric return 0;
8410b57cec5SDimitry Andric }
8420b57cec5SDimitry Andric // Value will contain a 12-bit value broken up into a 4-bit shift in bits
8430b57cec5SDimitry Andric // 11:8 and the 8-bit immediate in 0:7. The instruction has the immediate
8440b57cec5SDimitry Andric // in 0:7. The 4-bit shift is split up into i:imm3 where i is placed at bit
8450b57cec5SDimitry Andric // 10 of the upper half-word and imm3 is placed at 14:12 of the lower
8460b57cec5SDimitry Andric // half-word.
8470b57cec5SDimitry Andric uint64_t EncValue = 0;
8480b57cec5SDimitry Andric EncValue |= (Value & 0x800) << 15;
8490b57cec5SDimitry Andric EncValue |= (Value & 0x700) << 4;
8500b57cec5SDimitry Andric EncValue |= (Value & 0xff);
8515f757f3fSDimitry Andric return swapHalfWords(EncValue, Endian == llvm::endianness::little);
8520b57cec5SDimitry Andric }
8530b57cec5SDimitry Andric case ARM::fixup_bf_branch: {
8540b57cec5SDimitry Andric const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
8550b57cec5SDimitry Andric if (FixupDiagnostic) {
8560b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
8570b57cec5SDimitry Andric return 0;
8580b57cec5SDimitry Andric }
8590b57cec5SDimitry Andric uint32_t out = (((Value - 4) >> 1) & 0xf) << 23;
8605f757f3fSDimitry Andric return swapHalfWords(out, Endian == llvm::endianness::little);
8610b57cec5SDimitry Andric }
8620b57cec5SDimitry Andric case ARM::fixup_bf_target:
8630b57cec5SDimitry Andric case ARM::fixup_bfl_target:
8640b57cec5SDimitry Andric case ARM::fixup_bfc_target: {
8650b57cec5SDimitry Andric const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
8660b57cec5SDimitry Andric if (FixupDiagnostic) {
8670b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
8680b57cec5SDimitry Andric return 0;
8690b57cec5SDimitry Andric }
8700b57cec5SDimitry Andric uint32_t out = 0;
8710b57cec5SDimitry Andric uint32_t HighBitMask = (Kind == ARM::fixup_bf_target ? 0xf800 :
8720b57cec5SDimitry Andric Kind == ARM::fixup_bfl_target ? 0x3f800 : 0x800);
8730b57cec5SDimitry Andric out |= (((Value - 4) >> 1) & 0x1) << 11;
8740b57cec5SDimitry Andric out |= (((Value - 4) >> 1) & 0x7fe);
8750b57cec5SDimitry Andric out |= (((Value - 4) >> 1) & HighBitMask) << 5;
8765f757f3fSDimitry Andric return swapHalfWords(out, Endian == llvm::endianness::little);
8770b57cec5SDimitry Andric }
8780b57cec5SDimitry Andric case ARM::fixup_bfcsel_else_target: {
8790b57cec5SDimitry Andric // If this is a fixup of a branch future's else target then it should be a
8800b57cec5SDimitry Andric // constant MCExpr representing the distance between the branch targetted
8810b57cec5SDimitry Andric // and the instruction after that same branch.
8820b57cec5SDimitry Andric Value = Target.getConstant();
8830b57cec5SDimitry Andric
8840b57cec5SDimitry Andric const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
8850b57cec5SDimitry Andric if (FixupDiagnostic) {
8860b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
8870b57cec5SDimitry Andric return 0;
8880b57cec5SDimitry Andric }
8890b57cec5SDimitry Andric uint32_t out = ((Value >> 2) & 1) << 17;
8905f757f3fSDimitry Andric return swapHalfWords(out, Endian == llvm::endianness::little);
8910b57cec5SDimitry Andric }
8920b57cec5SDimitry Andric case ARM::fixup_wls:
8930b57cec5SDimitry Andric case ARM::fixup_le: {
8940b57cec5SDimitry Andric const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
8950b57cec5SDimitry Andric if (FixupDiagnostic) {
8960b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
8970b57cec5SDimitry Andric return 0;
8980b57cec5SDimitry Andric }
8990b57cec5SDimitry Andric uint64_t real_value = Value - 4;
9000b57cec5SDimitry Andric uint32_t out = 0;
9010b57cec5SDimitry Andric if (Kind == ARM::fixup_le)
9020b57cec5SDimitry Andric real_value = -real_value;
9030b57cec5SDimitry Andric out |= ((real_value >> 1) & 0x1) << 11;
9040b57cec5SDimitry Andric out |= ((real_value >> 1) & 0x7fe);
9055f757f3fSDimitry Andric return swapHalfWords(out, Endian == llvm::endianness::little);
9060b57cec5SDimitry Andric }
9070b57cec5SDimitry Andric }
9080b57cec5SDimitry Andric }
9090b57cec5SDimitry Andric
shouldForceRelocation(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,const MCSubtargetInfo * STI)9100b57cec5SDimitry Andric bool ARMAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
9110b57cec5SDimitry Andric const MCFixup &Fixup,
9125f757f3fSDimitry Andric const MCValue &Target,
9135f757f3fSDimitry Andric const MCSubtargetInfo *STI) {
9140b57cec5SDimitry Andric const MCSymbolRefExpr *A = Target.getSymA();
9150b57cec5SDimitry Andric const MCSymbol *Sym = A ? &A->getSymbol() : nullptr;
9160b57cec5SDimitry Andric const unsigned FixupKind = Fixup.getKind();
9175ffd83dbSDimitry Andric if (FixupKind >= FirstLiteralRelocationKind)
9180b57cec5SDimitry Andric return true;
9190b57cec5SDimitry Andric if (FixupKind == ARM::fixup_arm_thumb_bl) {
9200b57cec5SDimitry Andric assert(Sym && "How did we resolve this?");
9210b57cec5SDimitry Andric
9220b57cec5SDimitry Andric // If the symbol is external the linker will handle it.
9230b57cec5SDimitry Andric // FIXME: Should we handle it as an optimization?
9240b57cec5SDimitry Andric
9250b57cec5SDimitry Andric // If the symbol is out of range, produce a relocation and hope the
9260b57cec5SDimitry Andric // linker can handle it. GNU AS produces an error in this case.
9270b57cec5SDimitry Andric if (Sym->isExternal())
9280b57cec5SDimitry Andric return true;
9290b57cec5SDimitry Andric }
9300b57cec5SDimitry Andric // Create relocations for unconditional branches to function symbols with
9310b57cec5SDimitry Andric // different execution mode in ELF binaries.
9320b57cec5SDimitry Andric if (Sym && Sym->isELF()) {
9330b57cec5SDimitry Andric unsigned Type = cast<MCSymbolELF>(Sym)->getType();
9340b57cec5SDimitry Andric if ((Type == ELF::STT_FUNC || Type == ELF::STT_GNU_IFUNC)) {
9350b57cec5SDimitry Andric if (Asm.isThumbFunc(Sym) && (FixupKind == ARM::fixup_arm_uncondbranch))
9360b57cec5SDimitry Andric return true;
9370b57cec5SDimitry Andric if (!Asm.isThumbFunc(Sym) && (FixupKind == ARM::fixup_arm_thumb_br ||
9380b57cec5SDimitry Andric FixupKind == ARM::fixup_arm_thumb_bl ||
9390b57cec5SDimitry Andric FixupKind == ARM::fixup_t2_condbranch ||
9400b57cec5SDimitry Andric FixupKind == ARM::fixup_t2_uncondbranch))
9410b57cec5SDimitry Andric return true;
9420b57cec5SDimitry Andric }
9430b57cec5SDimitry Andric }
9440b57cec5SDimitry Andric // We must always generate a relocation for BL/BLX instructions if we have
9450b57cec5SDimitry Andric // a symbol to reference, as the linker relies on knowing the destination
9460b57cec5SDimitry Andric // symbol's thumb-ness to get interworking right.
9470b57cec5SDimitry Andric if (A && (FixupKind == ARM::fixup_arm_thumb_blx ||
9480b57cec5SDimitry Andric FixupKind == ARM::fixup_arm_blx ||
9490b57cec5SDimitry Andric FixupKind == ARM::fixup_arm_uncondbl ||
9500b57cec5SDimitry Andric FixupKind == ARM::fixup_arm_condbl))
9510b57cec5SDimitry Andric return true;
9520b57cec5SDimitry Andric return false;
9530b57cec5SDimitry Andric }
9540b57cec5SDimitry Andric
9550b57cec5SDimitry Andric /// getFixupKindNumBytes - The number of bytes the fixup may change.
getFixupKindNumBytes(unsigned Kind)9560b57cec5SDimitry Andric static unsigned getFixupKindNumBytes(unsigned Kind) {
9570b57cec5SDimitry Andric switch (Kind) {
9580b57cec5SDimitry Andric default:
9590b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!");
9600b57cec5SDimitry Andric
9610b57cec5SDimitry Andric case FK_Data_1:
9620b57cec5SDimitry Andric case ARM::fixup_arm_thumb_bcc:
9630b57cec5SDimitry Andric case ARM::fixup_arm_thumb_cp:
9640b57cec5SDimitry Andric case ARM::fixup_thumb_adr_pcrel_10:
96506c3fb27SDimitry Andric case ARM::fixup_arm_thumb_upper_8_15:
96606c3fb27SDimitry Andric case ARM::fixup_arm_thumb_upper_0_7:
96706c3fb27SDimitry Andric case ARM::fixup_arm_thumb_lower_8_15:
96806c3fb27SDimitry Andric case ARM::fixup_arm_thumb_lower_0_7:
9690b57cec5SDimitry Andric return 1;
9700b57cec5SDimitry Andric
9710b57cec5SDimitry Andric case FK_Data_2:
9720b57cec5SDimitry Andric case ARM::fixup_arm_thumb_br:
9730b57cec5SDimitry Andric case ARM::fixup_arm_thumb_cb:
9740b57cec5SDimitry Andric case ARM::fixup_arm_mod_imm:
9750b57cec5SDimitry Andric return 2;
9760b57cec5SDimitry Andric
9770b57cec5SDimitry Andric case ARM::fixup_arm_pcrel_10_unscaled:
9780b57cec5SDimitry Andric case ARM::fixup_arm_ldst_pcrel_12:
9790b57cec5SDimitry Andric case ARM::fixup_arm_pcrel_10:
9800b57cec5SDimitry Andric case ARM::fixup_arm_pcrel_9:
981fe6060f1SDimitry Andric case ARM::fixup_arm_ldst_abs_12:
9820b57cec5SDimitry Andric case ARM::fixup_arm_adr_pcrel_12:
9830b57cec5SDimitry Andric case ARM::fixup_arm_uncondbl:
9840b57cec5SDimitry Andric case ARM::fixup_arm_condbl:
9850b57cec5SDimitry Andric case ARM::fixup_arm_blx:
9860b57cec5SDimitry Andric case ARM::fixup_arm_condbranch:
9870b57cec5SDimitry Andric case ARM::fixup_arm_uncondbranch:
9880b57cec5SDimitry Andric return 3;
9890b57cec5SDimitry Andric
9900b57cec5SDimitry Andric case FK_Data_4:
9910b57cec5SDimitry Andric case ARM::fixup_t2_ldst_pcrel_12:
9920b57cec5SDimitry Andric case ARM::fixup_t2_condbranch:
9930b57cec5SDimitry Andric case ARM::fixup_t2_uncondbranch:
9940b57cec5SDimitry Andric case ARM::fixup_t2_pcrel_10:
9950b57cec5SDimitry Andric case ARM::fixup_t2_pcrel_9:
9960b57cec5SDimitry Andric case ARM::fixup_t2_adr_pcrel_12:
9970b57cec5SDimitry Andric case ARM::fixup_arm_thumb_bl:
9980b57cec5SDimitry Andric case ARM::fixup_arm_thumb_blx:
9990b57cec5SDimitry Andric case ARM::fixup_arm_movt_hi16:
10000b57cec5SDimitry Andric case ARM::fixup_arm_movw_lo16:
10010b57cec5SDimitry Andric case ARM::fixup_t2_movt_hi16:
10020b57cec5SDimitry Andric case ARM::fixup_t2_movw_lo16:
10030b57cec5SDimitry Andric case ARM::fixup_t2_so_imm:
10040b57cec5SDimitry Andric case ARM::fixup_bf_branch:
10050b57cec5SDimitry Andric case ARM::fixup_bf_target:
10060b57cec5SDimitry Andric case ARM::fixup_bfl_target:
10070b57cec5SDimitry Andric case ARM::fixup_bfc_target:
10080b57cec5SDimitry Andric case ARM::fixup_bfcsel_else_target:
10090b57cec5SDimitry Andric case ARM::fixup_wls:
10100b57cec5SDimitry Andric case ARM::fixup_le:
10110b57cec5SDimitry Andric return 4;
10120b57cec5SDimitry Andric
10130b57cec5SDimitry Andric case FK_SecRel_2:
10140b57cec5SDimitry Andric return 2;
10150b57cec5SDimitry Andric case FK_SecRel_4:
10160b57cec5SDimitry Andric return 4;
10170b57cec5SDimitry Andric }
10180b57cec5SDimitry Andric }
10190b57cec5SDimitry Andric
10200b57cec5SDimitry Andric /// getFixupKindContainerSizeBytes - The number of bytes of the
10210b57cec5SDimitry Andric /// container involved in big endian.
getFixupKindContainerSizeBytes(unsigned Kind)10220b57cec5SDimitry Andric static unsigned getFixupKindContainerSizeBytes(unsigned Kind) {
10230b57cec5SDimitry Andric switch (Kind) {
10240b57cec5SDimitry Andric default:
10250b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!");
10260b57cec5SDimitry Andric
10270b57cec5SDimitry Andric case FK_Data_1:
10280b57cec5SDimitry Andric return 1;
10290b57cec5SDimitry Andric case FK_Data_2:
10300b57cec5SDimitry Andric return 2;
10310b57cec5SDimitry Andric case FK_Data_4:
10320b57cec5SDimitry Andric return 4;
10330b57cec5SDimitry Andric
10340b57cec5SDimitry Andric case ARM::fixup_arm_thumb_bcc:
10350b57cec5SDimitry Andric case ARM::fixup_arm_thumb_cp:
10360b57cec5SDimitry Andric case ARM::fixup_thumb_adr_pcrel_10:
10370b57cec5SDimitry Andric case ARM::fixup_arm_thumb_br:
10380b57cec5SDimitry Andric case ARM::fixup_arm_thumb_cb:
103906c3fb27SDimitry Andric case ARM::fixup_arm_thumb_upper_8_15:
104006c3fb27SDimitry Andric case ARM::fixup_arm_thumb_upper_0_7:
104106c3fb27SDimitry Andric case ARM::fixup_arm_thumb_lower_8_15:
104206c3fb27SDimitry Andric case ARM::fixup_arm_thumb_lower_0_7:
10430b57cec5SDimitry Andric // Instruction size is 2 bytes.
10440b57cec5SDimitry Andric return 2;
10450b57cec5SDimitry Andric
10460b57cec5SDimitry Andric case ARM::fixup_arm_pcrel_10_unscaled:
10470b57cec5SDimitry Andric case ARM::fixup_arm_ldst_pcrel_12:
10480b57cec5SDimitry Andric case ARM::fixup_arm_pcrel_10:
10490b57cec5SDimitry Andric case ARM::fixup_arm_pcrel_9:
10500b57cec5SDimitry Andric case ARM::fixup_arm_adr_pcrel_12:
10510b57cec5SDimitry Andric case ARM::fixup_arm_uncondbl:
10520b57cec5SDimitry Andric case ARM::fixup_arm_condbl:
10530b57cec5SDimitry Andric case ARM::fixup_arm_blx:
10540b57cec5SDimitry Andric case ARM::fixup_arm_condbranch:
10550b57cec5SDimitry Andric case ARM::fixup_arm_uncondbranch:
10560b57cec5SDimitry Andric case ARM::fixup_t2_ldst_pcrel_12:
10570b57cec5SDimitry Andric case ARM::fixup_t2_condbranch:
10580b57cec5SDimitry Andric case ARM::fixup_t2_uncondbranch:
10590b57cec5SDimitry Andric case ARM::fixup_t2_pcrel_10:
1060e8d8bef9SDimitry Andric case ARM::fixup_t2_pcrel_9:
10610b57cec5SDimitry Andric case ARM::fixup_t2_adr_pcrel_12:
10620b57cec5SDimitry Andric case ARM::fixup_arm_thumb_bl:
10630b57cec5SDimitry Andric case ARM::fixup_arm_thumb_blx:
10640b57cec5SDimitry Andric case ARM::fixup_arm_movt_hi16:
10650b57cec5SDimitry Andric case ARM::fixup_arm_movw_lo16:
10660b57cec5SDimitry Andric case ARM::fixup_t2_movt_hi16:
10670b57cec5SDimitry Andric case ARM::fixup_t2_movw_lo16:
10680b57cec5SDimitry Andric case ARM::fixup_arm_mod_imm:
10690b57cec5SDimitry Andric case ARM::fixup_t2_so_imm:
10700b57cec5SDimitry Andric case ARM::fixup_bf_branch:
10710b57cec5SDimitry Andric case ARM::fixup_bf_target:
10720b57cec5SDimitry Andric case ARM::fixup_bfl_target:
10730b57cec5SDimitry Andric case ARM::fixup_bfc_target:
10740b57cec5SDimitry Andric case ARM::fixup_bfcsel_else_target:
10750b57cec5SDimitry Andric case ARM::fixup_wls:
10760b57cec5SDimitry Andric case ARM::fixup_le:
10770b57cec5SDimitry Andric // Instruction size is 4 bytes.
10780b57cec5SDimitry Andric return 4;
10790b57cec5SDimitry Andric }
10800b57cec5SDimitry Andric }
10810b57cec5SDimitry Andric
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const10820b57cec5SDimitry Andric void ARMAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
10830b57cec5SDimitry Andric const MCValue &Target,
10840b57cec5SDimitry Andric MutableArrayRef<char> Data, uint64_t Value,
10850b57cec5SDimitry Andric bool IsResolved,
10860b57cec5SDimitry Andric const MCSubtargetInfo* STI) const {
10875ffd83dbSDimitry Andric unsigned Kind = Fixup.getKind();
10885ffd83dbSDimitry Andric if (Kind >= FirstLiteralRelocationKind)
10895ffd83dbSDimitry Andric return;
10900b57cec5SDimitry Andric MCContext &Ctx = Asm.getContext();
10910b57cec5SDimitry Andric Value = adjustFixupValue(Asm, Fixup, Target, Value, IsResolved, Ctx, STI);
10920b57cec5SDimitry Andric if (!Value)
10930b57cec5SDimitry Andric return; // Doesn't change encoding.
109404eeddc0SDimitry Andric const unsigned NumBytes = getFixupKindNumBytes(Kind);
10950b57cec5SDimitry Andric
10960b57cec5SDimitry Andric unsigned Offset = Fixup.getOffset();
10970b57cec5SDimitry Andric assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");
10980b57cec5SDimitry Andric
10990b57cec5SDimitry Andric // Used to point to big endian bytes.
11000b57cec5SDimitry Andric unsigned FullSizeBytes;
11015f757f3fSDimitry Andric if (Endian == llvm::endianness::big) {
11025ffd83dbSDimitry Andric FullSizeBytes = getFixupKindContainerSizeBytes(Kind);
11030b57cec5SDimitry Andric assert((Offset + FullSizeBytes) <= Data.size() && "Invalid fixup size!");
11040b57cec5SDimitry Andric assert(NumBytes <= FullSizeBytes && "Invalid fixup size!");
11050b57cec5SDimitry Andric }
11060b57cec5SDimitry Andric
11070b57cec5SDimitry Andric // For each byte of the fragment that the fixup touches, mask in the bits from
11080b57cec5SDimitry Andric // the fixup value. The Value has been "split up" into the appropriate
11090b57cec5SDimitry Andric // bitfields above.
11100b57cec5SDimitry Andric for (unsigned i = 0; i != NumBytes; ++i) {
11115f757f3fSDimitry Andric unsigned Idx =
11125f757f3fSDimitry Andric Endian == llvm::endianness::little ? i : (FullSizeBytes - 1 - i);
11130b57cec5SDimitry Andric Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff);
11140b57cec5SDimitry Andric }
11150b57cec5SDimitry Andric }
11160b57cec5SDimitry Andric
11170b57cec5SDimitry Andric namespace CU {
11180b57cec5SDimitry Andric
11190b57cec5SDimitry Andric /// Compact unwind encoding values.
11200b57cec5SDimitry Andric enum CompactUnwindEncodings {
11210b57cec5SDimitry Andric UNWIND_ARM_MODE_MASK = 0x0F000000,
11220b57cec5SDimitry Andric UNWIND_ARM_MODE_FRAME = 0x01000000,
11230b57cec5SDimitry Andric UNWIND_ARM_MODE_FRAME_D = 0x02000000,
11240b57cec5SDimitry Andric UNWIND_ARM_MODE_DWARF = 0x04000000,
11250b57cec5SDimitry Andric
11260b57cec5SDimitry Andric UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
11270b57cec5SDimitry Andric
11280b57cec5SDimitry Andric UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
11290b57cec5SDimitry Andric UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
11300b57cec5SDimitry Andric UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
11310b57cec5SDimitry Andric
11320b57cec5SDimitry Andric UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
11330b57cec5SDimitry Andric UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
11340b57cec5SDimitry Andric UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
11350b57cec5SDimitry Andric UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
11360b57cec5SDimitry Andric UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
11370b57cec5SDimitry Andric
11380b57cec5SDimitry Andric UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000F00,
11390b57cec5SDimitry Andric
11400b57cec5SDimitry Andric UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF
11410b57cec5SDimitry Andric };
11420b57cec5SDimitry Andric
11430b57cec5SDimitry Andric } // end CU namespace
11440b57cec5SDimitry Andric
11450b57cec5SDimitry Andric /// Generate compact unwind encoding for the function based on the CFI
11460b57cec5SDimitry Andric /// instructions. If the CFI instructions describe a frame that cannot be
11470b57cec5SDimitry Andric /// encoded in compact unwind, the method returns UNWIND_ARM_MODE_DWARF which
11480b57cec5SDimitry Andric /// tells the runtime to fallback and unwind using dwarf.
generateCompactUnwindEncoding(const MCDwarfFrameInfo * FI,const MCContext * Ctxt) const1149*36b606aeSDimitry Andric uint64_t ARMAsmBackendDarwin::generateCompactUnwindEncoding(
115006c3fb27SDimitry Andric const MCDwarfFrameInfo *FI, const MCContext *Ctxt) const {
11510b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind", llvm::dbgs() << "generateCU()\n");
11520b57cec5SDimitry Andric // Only armv7k uses CFI based unwinding.
11530b57cec5SDimitry Andric if (Subtype != MachO::CPU_SUBTYPE_ARM_V7K)
11540b57cec5SDimitry Andric return 0;
11550b57cec5SDimitry Andric // No .cfi directives means no frame.
115606c3fb27SDimitry Andric ArrayRef<MCCFIInstruction> Instrs = FI->Instructions;
11570b57cec5SDimitry Andric if (Instrs.empty())
11580b57cec5SDimitry Andric return 0;
115906c3fb27SDimitry Andric if (!isDarwinCanonicalPersonality(FI->Personality) &&
116006c3fb27SDimitry Andric !Ctxt->emitCompactUnwindNonCanonical())
116106c3fb27SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
116206c3fb27SDimitry Andric
11630b57cec5SDimitry Andric // Start off assuming CFA is at SP+0.
11648bcb0991SDimitry Andric unsigned CFARegister = ARM::SP;
11650b57cec5SDimitry Andric int CFARegisterOffset = 0;
11660b57cec5SDimitry Andric // Mark savable registers as initially unsaved
11670b57cec5SDimitry Andric DenseMap<unsigned, int> RegOffsets;
11680b57cec5SDimitry Andric int FloatRegCount = 0;
11690b57cec5SDimitry Andric // Process each .cfi directive and build up compact unwind info.
117004eeddc0SDimitry Andric for (const MCCFIInstruction &Inst : Instrs) {
11718bcb0991SDimitry Andric unsigned Reg;
11720b57cec5SDimitry Andric switch (Inst.getOperation()) {
11730b57cec5SDimitry Andric case MCCFIInstruction::OpDefCfa: // DW_CFA_def_cfa
11745ffd83dbSDimitry Andric CFARegisterOffset = Inst.getOffset();
11758bcb0991SDimitry Andric CFARegister = *MRI.getLLVMRegNum(Inst.getRegister(), true);
11760b57cec5SDimitry Andric break;
11770b57cec5SDimitry Andric case MCCFIInstruction::OpDefCfaOffset: // DW_CFA_def_cfa_offset
11785ffd83dbSDimitry Andric CFARegisterOffset = Inst.getOffset();
11790b57cec5SDimitry Andric break;
11800b57cec5SDimitry Andric case MCCFIInstruction::OpDefCfaRegister: // DW_CFA_def_cfa_register
11818bcb0991SDimitry Andric CFARegister = *MRI.getLLVMRegNum(Inst.getRegister(), true);
11820b57cec5SDimitry Andric break;
11830b57cec5SDimitry Andric case MCCFIInstruction::OpOffset: // DW_CFA_offset
11848bcb0991SDimitry Andric Reg = *MRI.getLLVMRegNum(Inst.getRegister(), true);
11850b57cec5SDimitry Andric if (ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg))
11860b57cec5SDimitry Andric RegOffsets[Reg] = Inst.getOffset();
11870b57cec5SDimitry Andric else if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg)) {
11880b57cec5SDimitry Andric RegOffsets[Reg] = Inst.getOffset();
11890b57cec5SDimitry Andric ++FloatRegCount;
11900b57cec5SDimitry Andric } else {
11910b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind",
11920b57cec5SDimitry Andric llvm::dbgs() << ".cfi_offset on unknown register="
11930b57cec5SDimitry Andric << Inst.getRegister() << "\n");
11940b57cec5SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
11950b57cec5SDimitry Andric }
11960b57cec5SDimitry Andric break;
11970b57cec5SDimitry Andric case MCCFIInstruction::OpRelOffset: // DW_CFA_advance_loc
11980b57cec5SDimitry Andric // Ignore
11990b57cec5SDimitry Andric break;
12000b57cec5SDimitry Andric default:
12010b57cec5SDimitry Andric // Directive not convertable to compact unwind, bail out.
12020b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind",
12030b57cec5SDimitry Andric llvm::dbgs()
120406c3fb27SDimitry Andric << "CFI directive not compatible with compact "
12050fca6ea1SDimitry Andric "unwind encoding, opcode="
12060fca6ea1SDimitry Andric << uint8_t(Inst.getOperation()) << "\n");
12070b57cec5SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
12080b57cec5SDimitry Andric break;
12090b57cec5SDimitry Andric }
12100b57cec5SDimitry Andric }
12110b57cec5SDimitry Andric
12120b57cec5SDimitry Andric // If no frame set up, return no unwind info.
12130b57cec5SDimitry Andric if ((CFARegister == ARM::SP) && (CFARegisterOffset == 0))
12140b57cec5SDimitry Andric return 0;
12150b57cec5SDimitry Andric
12160b57cec5SDimitry Andric // Verify standard frame (lr/r7) was used.
12170b57cec5SDimitry Andric if (CFARegister != ARM::R7) {
12180b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind", llvm::dbgs() << "frame register is "
12190b57cec5SDimitry Andric << CFARegister
12200b57cec5SDimitry Andric << " instead of r7\n");
12210b57cec5SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
12220b57cec5SDimitry Andric }
12230b57cec5SDimitry Andric int StackAdjust = CFARegisterOffset - 8;
12240b57cec5SDimitry Andric if (RegOffsets.lookup(ARM::LR) != (-4 - StackAdjust)) {
12250b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind",
12260b57cec5SDimitry Andric llvm::dbgs()
12270b57cec5SDimitry Andric << "LR not saved as standard frame, StackAdjust="
12280b57cec5SDimitry Andric << StackAdjust
12290b57cec5SDimitry Andric << ", CFARegisterOffset=" << CFARegisterOffset
12300b57cec5SDimitry Andric << ", lr save at offset=" << RegOffsets[14] << "\n");
12310b57cec5SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
12320b57cec5SDimitry Andric }
12330b57cec5SDimitry Andric if (RegOffsets.lookup(ARM::R7) != (-8 - StackAdjust)) {
12340b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind",
12350b57cec5SDimitry Andric llvm::dbgs() << "r7 not saved as standard frame\n");
12360b57cec5SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
12370b57cec5SDimitry Andric }
12380b57cec5SDimitry Andric uint32_t CompactUnwindEncoding = CU::UNWIND_ARM_MODE_FRAME;
12390b57cec5SDimitry Andric
12400b57cec5SDimitry Andric // If var-args are used, there may be a stack adjust required.
12410b57cec5SDimitry Andric switch (StackAdjust) {
12420b57cec5SDimitry Andric case 0:
12430b57cec5SDimitry Andric break;
12440b57cec5SDimitry Andric case 4:
12450b57cec5SDimitry Andric CompactUnwindEncoding |= 0x00400000;
12460b57cec5SDimitry Andric break;
12470b57cec5SDimitry Andric case 8:
12480b57cec5SDimitry Andric CompactUnwindEncoding |= 0x00800000;
12490b57cec5SDimitry Andric break;
12500b57cec5SDimitry Andric case 12:
12510b57cec5SDimitry Andric CompactUnwindEncoding |= 0x00C00000;
12520b57cec5SDimitry Andric break;
12530b57cec5SDimitry Andric default:
12540b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind", llvm::dbgs()
12550b57cec5SDimitry Andric << ".cfi_def_cfa stack adjust ("
12560b57cec5SDimitry Andric << StackAdjust << ") out of range\n");
12570b57cec5SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
12580b57cec5SDimitry Andric }
12590b57cec5SDimitry Andric
12600b57cec5SDimitry Andric // If r6 is saved, it must be right below r7.
12610b57cec5SDimitry Andric static struct {
12620b57cec5SDimitry Andric unsigned Reg;
12630b57cec5SDimitry Andric unsigned Encoding;
12640b57cec5SDimitry Andric } GPRCSRegs[] = {{ARM::R6, CU::UNWIND_ARM_FRAME_FIRST_PUSH_R6},
12650b57cec5SDimitry Andric {ARM::R5, CU::UNWIND_ARM_FRAME_FIRST_PUSH_R5},
12660b57cec5SDimitry Andric {ARM::R4, CU::UNWIND_ARM_FRAME_FIRST_PUSH_R4},
12670b57cec5SDimitry Andric {ARM::R12, CU::UNWIND_ARM_FRAME_SECOND_PUSH_R12},
12680b57cec5SDimitry Andric {ARM::R11, CU::UNWIND_ARM_FRAME_SECOND_PUSH_R11},
12690b57cec5SDimitry Andric {ARM::R10, CU::UNWIND_ARM_FRAME_SECOND_PUSH_R10},
12700b57cec5SDimitry Andric {ARM::R9, CU::UNWIND_ARM_FRAME_SECOND_PUSH_R9},
12710b57cec5SDimitry Andric {ARM::R8, CU::UNWIND_ARM_FRAME_SECOND_PUSH_R8}};
12720b57cec5SDimitry Andric
12730b57cec5SDimitry Andric int CurOffset = -8 - StackAdjust;
12740b57cec5SDimitry Andric for (auto CSReg : GPRCSRegs) {
12750b57cec5SDimitry Andric auto Offset = RegOffsets.find(CSReg.Reg);
12760b57cec5SDimitry Andric if (Offset == RegOffsets.end())
12770b57cec5SDimitry Andric continue;
12780b57cec5SDimitry Andric
12790b57cec5SDimitry Andric int RegOffset = Offset->second;
12800b57cec5SDimitry Andric if (RegOffset != CurOffset - 4) {
12810b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind",
12820b57cec5SDimitry Andric llvm::dbgs() << MRI.getName(CSReg.Reg) << " saved at "
12830b57cec5SDimitry Andric << RegOffset << " but only supported at "
12840b57cec5SDimitry Andric << CurOffset << "\n");
12850b57cec5SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
12860b57cec5SDimitry Andric }
12870b57cec5SDimitry Andric CompactUnwindEncoding |= CSReg.Encoding;
12880b57cec5SDimitry Andric CurOffset -= 4;
12890b57cec5SDimitry Andric }
12900b57cec5SDimitry Andric
12910b57cec5SDimitry Andric // If no floats saved, we are done.
12920b57cec5SDimitry Andric if (FloatRegCount == 0)
12930b57cec5SDimitry Andric return CompactUnwindEncoding;
12940b57cec5SDimitry Andric
12950b57cec5SDimitry Andric // Switch mode to include D register saving.
12960b57cec5SDimitry Andric CompactUnwindEncoding &= ~CU::UNWIND_ARM_MODE_MASK;
12970b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM_MODE_FRAME_D;
12980b57cec5SDimitry Andric
12990b57cec5SDimitry Andric // FIXME: supporting more than 4 saved D-registers compactly would be trivial,
13000b57cec5SDimitry Andric // but needs coordination with the linker and libunwind.
13010b57cec5SDimitry Andric if (FloatRegCount > 4) {
13020b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind",
13030b57cec5SDimitry Andric llvm::dbgs() << "unsupported number of D registers saved ("
13040b57cec5SDimitry Andric << FloatRegCount << ")\n");
13050b57cec5SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
13060b57cec5SDimitry Andric }
13070b57cec5SDimitry Andric
13080b57cec5SDimitry Andric // Floating point registers must either be saved sequentially, or we defer to
13090b57cec5SDimitry Andric // DWARF. No gaps allowed here so check that each saved d-register is
13100b57cec5SDimitry Andric // precisely where it should be.
13110b57cec5SDimitry Andric static unsigned FPRCSRegs[] = { ARM::D8, ARM::D10, ARM::D12, ARM::D14 };
13120b57cec5SDimitry Andric for (int Idx = FloatRegCount - 1; Idx >= 0; --Idx) {
13130b57cec5SDimitry Andric auto Offset = RegOffsets.find(FPRCSRegs[Idx]);
13140b57cec5SDimitry Andric if (Offset == RegOffsets.end()) {
13150b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind",
13160b57cec5SDimitry Andric llvm::dbgs() << FloatRegCount << " D-regs saved, but "
13170b57cec5SDimitry Andric << MRI.getName(FPRCSRegs[Idx])
13180b57cec5SDimitry Andric << " not saved\n");
13190b57cec5SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
13200b57cec5SDimitry Andric } else if (Offset->second != CurOffset - 8) {
13210b57cec5SDimitry Andric DEBUG_WITH_TYPE("compact-unwind",
13220b57cec5SDimitry Andric llvm::dbgs() << FloatRegCount << " D-regs saved, but "
13230b57cec5SDimitry Andric << MRI.getName(FPRCSRegs[Idx])
13240b57cec5SDimitry Andric << " saved at " << Offset->second
13250b57cec5SDimitry Andric << ", expected at " << CurOffset - 8
13260b57cec5SDimitry Andric << "\n");
13270b57cec5SDimitry Andric return CU::UNWIND_ARM_MODE_DWARF;
13280b57cec5SDimitry Andric }
13290b57cec5SDimitry Andric CurOffset -= 8;
13300b57cec5SDimitry Andric }
13310b57cec5SDimitry Andric
13320b57cec5SDimitry Andric return CompactUnwindEncoding | ((FloatRegCount - 1) << 8);
13330b57cec5SDimitry Andric }
13340b57cec5SDimitry Andric
createARMAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options,llvm::endianness Endian)13350b57cec5SDimitry Andric static MCAsmBackend *createARMAsmBackend(const Target &T,
13360b57cec5SDimitry Andric const MCSubtargetInfo &STI,
13370b57cec5SDimitry Andric const MCRegisterInfo &MRI,
13380b57cec5SDimitry Andric const MCTargetOptions &Options,
13395f757f3fSDimitry Andric llvm::endianness Endian) {
13400b57cec5SDimitry Andric const Triple &TheTriple = STI.getTargetTriple();
13410b57cec5SDimitry Andric switch (TheTriple.getObjectFormat()) {
13420b57cec5SDimitry Andric default:
13430b57cec5SDimitry Andric llvm_unreachable("unsupported object format");
13445ffd83dbSDimitry Andric case Triple::MachO:
13455ffd83dbSDimitry Andric return new ARMAsmBackendDarwin(T, STI, MRI);
13460b57cec5SDimitry Andric case Triple::COFF:
13470b57cec5SDimitry Andric assert(TheTriple.isOSWindows() && "non-Windows ARM COFF is not supported");
1348349cc55cSDimitry Andric return new ARMAsmBackendWinCOFF(T, STI.getTargetTriple().isThumb());
13490b57cec5SDimitry Andric case Triple::ELF:
13500b57cec5SDimitry Andric assert(TheTriple.isOSBinFormatELF() && "using ELF for non-ELF target");
13510fca6ea1SDimitry Andric uint8_t OSABI = Options.FDPIC
13520fca6ea1SDimitry Andric ? ELF::ELFOSABI_ARM_FDPIC
13530fca6ea1SDimitry Andric : MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
1354349cc55cSDimitry Andric return new ARMAsmBackendELF(T, STI.getTargetTriple().isThumb(), OSABI,
1355349cc55cSDimitry Andric Endian);
13560b57cec5SDimitry Andric }
13570b57cec5SDimitry Andric }
13580b57cec5SDimitry Andric
createARMLEAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)13590b57cec5SDimitry Andric MCAsmBackend *llvm::createARMLEAsmBackend(const Target &T,
13600b57cec5SDimitry Andric const MCSubtargetInfo &STI,
13610b57cec5SDimitry Andric const MCRegisterInfo &MRI,
13620b57cec5SDimitry Andric const MCTargetOptions &Options) {
13635f757f3fSDimitry Andric return createARMAsmBackend(T, STI, MRI, Options, llvm::endianness::little);
13640b57cec5SDimitry Andric }
13650b57cec5SDimitry Andric
createARMBEAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)13660b57cec5SDimitry Andric MCAsmBackend *llvm::createARMBEAsmBackend(const Target &T,
13670b57cec5SDimitry Andric const MCSubtargetInfo &STI,
13680b57cec5SDimitry Andric const MCRegisterInfo &MRI,
13690b57cec5SDimitry Andric const MCTargetOptions &Options) {
13705f757f3fSDimitry Andric return createARMAsmBackend(T, STI, MRI, Options, llvm::endianness::big);
13710b57cec5SDimitry Andric }
1372