10b57cec5SDimitry Andric //===-- AArch64AsmBackend.cpp - AArch64 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/AArch64FixupKinds.h" 100b57cec5SDimitry Andric #include "MCTargetDesc/AArch64MCExpr.h" 110b57cec5SDimitry Andric #include "MCTargetDesc/AArch64MCTargetDesc.h" 120b57cec5SDimitry Andric #include "Utils/AArch64BaseInfo.h" 130b57cec5SDimitry Andric #include "llvm/BinaryFormat/MachO.h" 140b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h" 150b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h" 160b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCDirectives.h" 180b57cec5SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h" 190b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h" 200b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h" 210b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 220b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h" 230b57cec5SDimitry Andric #include "llvm/MC/MCSectionMachO.h" 2481ad6265SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 250b57cec5SDimitry Andric #include "llvm/MC/MCTargetOptions.h" 260b57cec5SDimitry Andric #include "llvm/MC/MCValue.h" 27349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 280b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 2906c3fb27SDimitry Andric #include "llvm/Support/MathExtras.h" 3006c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h" 310b57cec5SDimitry Andric using namespace llvm; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric namespace { 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric class AArch64AsmBackend : public MCAsmBackend { 360b57cec5SDimitry Andric static const unsigned PCRelFlagVal = 370b57cec5SDimitry Andric MCFixupKindInfo::FKF_IsAlignedDownTo32Bits | MCFixupKindInfo::FKF_IsPCRel; 385ffd83dbSDimitry Andric protected: 390b57cec5SDimitry Andric Triple TheTriple; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric public: 420b57cec5SDimitry Andric AArch64AsmBackend(const Target &T, const Triple &TT, bool IsLittleEndian) 435f757f3fSDimitry Andric : MCAsmBackend(IsLittleEndian ? llvm::endianness::little 445f757f3fSDimitry Andric : llvm::endianness::big), 450b57cec5SDimitry Andric TheTriple(TT) {} 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric unsigned getNumFixupKinds() const override { 480b57cec5SDimitry Andric return AArch64::NumTargetFixupKinds; 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric 51bdd1243dSDimitry Andric std::optional<MCFixupKind> getFixupKind(StringRef Name) const override; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { 540b57cec5SDimitry Andric const static MCFixupKindInfo Infos[AArch64::NumTargetFixupKinds] = { 550b57cec5SDimitry Andric // This table *must* be in the order that the fixup_* kinds are defined 560b57cec5SDimitry Andric // in AArch64FixupKinds.h. 570b57cec5SDimitry Andric // 580b57cec5SDimitry Andric // Name Offset (bits) Size (bits) Flags 590b57cec5SDimitry Andric {"fixup_aarch64_pcrel_adr_imm21", 0, 32, PCRelFlagVal}, 600b57cec5SDimitry Andric {"fixup_aarch64_pcrel_adrp_imm21", 0, 32, PCRelFlagVal}, 610b57cec5SDimitry Andric {"fixup_aarch64_add_imm12", 10, 12, 0}, 620b57cec5SDimitry Andric {"fixup_aarch64_ldst_imm12_scale1", 10, 12, 0}, 630b57cec5SDimitry Andric {"fixup_aarch64_ldst_imm12_scale2", 10, 12, 0}, 640b57cec5SDimitry Andric {"fixup_aarch64_ldst_imm12_scale4", 10, 12, 0}, 650b57cec5SDimitry Andric {"fixup_aarch64_ldst_imm12_scale8", 10, 12, 0}, 660b57cec5SDimitry Andric {"fixup_aarch64_ldst_imm12_scale16", 10, 12, 0}, 670b57cec5SDimitry Andric {"fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal}, 680b57cec5SDimitry Andric {"fixup_aarch64_movw", 5, 16, 0}, 690b57cec5SDimitry Andric {"fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal}, 70cb14a3feSDimitry Andric {"fixup_aarch64_pcrel_branch16", 5, 16, PCRelFlagVal}, 710b57cec5SDimitry Andric {"fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal}, 720b57cec5SDimitry Andric {"fixup_aarch64_pcrel_branch26", 0, 26, PCRelFlagVal}, 73fe6060f1SDimitry Andric {"fixup_aarch64_pcrel_call26", 0, 26, PCRelFlagVal}}; 740b57cec5SDimitry Andric 755ffd83dbSDimitry Andric // Fixup kinds from .reloc directive are like R_AARCH64_NONE. They do not 765ffd83dbSDimitry Andric // require any extra processing. 775ffd83dbSDimitry Andric if (Kind >= FirstLiteralRelocationKind) 785ffd83dbSDimitry Andric return MCAsmBackend::getFixupKindInfo(FK_NONE); 795ffd83dbSDimitry Andric 800b57cec5SDimitry Andric if (Kind < FirstTargetFixupKind) 810b57cec5SDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 840b57cec5SDimitry Andric "Invalid kind!"); 850b57cec5SDimitry Andric return Infos[Kind - FirstTargetFixupKind]; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 890b57cec5SDimitry Andric const MCValue &Target, MutableArrayRef<char> Data, 900b57cec5SDimitry Andric uint64_t Value, bool IsResolved, 910b57cec5SDimitry Andric const MCSubtargetInfo *STI) const override; 920b57cec5SDimitry Andric 930fca6ea1SDimitry Andric bool fixupNeedsRelaxation(const MCFixup &Fixup, 940fca6ea1SDimitry Andric uint64_t Value) const override; 955ffd83dbSDimitry Andric void relaxInstruction(MCInst &Inst, 965ffd83dbSDimitry Andric const MCSubtargetInfo &STI) const override; 97349cc55cSDimitry Andric bool writeNopData(raw_ostream &OS, uint64_t Count, 98349cc55cSDimitry Andric const MCSubtargetInfo *STI) const override; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric unsigned getFixupKindContainereSizeInBytes(unsigned Kind) const; 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, 1035f757f3fSDimitry Andric const MCValue &Target, 1045f757f3fSDimitry Andric const MCSubtargetInfo *STI) override; 1050b57cec5SDimitry Andric }; 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric } // end anonymous namespace 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric /// The number of bytes the fixup may change. 1100b57cec5SDimitry Andric static unsigned getFixupKindNumBytes(unsigned Kind) { 1110b57cec5SDimitry Andric switch (Kind) { 1120b57cec5SDimitry Andric default: 1130b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!"); 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric case FK_Data_1: 1160b57cec5SDimitry Andric return 1; 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric case FK_Data_2: 1190b57cec5SDimitry Andric case FK_SecRel_2: 1200b57cec5SDimitry Andric return 2; 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric case AArch64::fixup_aarch64_movw: 1230b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch14: 124cb14a3feSDimitry Andric case AArch64::fixup_aarch64_pcrel_branch16: 1250b57cec5SDimitry Andric case AArch64::fixup_aarch64_add_imm12: 1260b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale1: 1270b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale2: 1280b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale4: 1290b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale8: 1300b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale16: 1310b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldr_pcrel_imm19: 1320b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch19: 1330b57cec5SDimitry Andric return 3; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adr_imm21: 1360b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adrp_imm21: 1370b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch26: 1380b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_call26: 1390b57cec5SDimitry Andric case FK_Data_4: 1400b57cec5SDimitry Andric case FK_SecRel_4: 1410b57cec5SDimitry Andric return 4; 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric case FK_Data_8: 1440b57cec5SDimitry Andric return 8; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric static unsigned AdrImmBits(unsigned Value) { 1490b57cec5SDimitry Andric unsigned lo2 = Value & 0x3; 1500b57cec5SDimitry Andric unsigned hi19 = (Value & 0x1ffffc) >> 2; 1510b57cec5SDimitry Andric return (hi19 << 5) | (lo2 << 29); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric static uint64_t adjustFixupValue(const MCFixup &Fixup, const MCValue &Target, 1550b57cec5SDimitry Andric uint64_t Value, MCContext &Ctx, 1560b57cec5SDimitry Andric const Triple &TheTriple, bool IsResolved) { 1570b57cec5SDimitry Andric int64_t SignedValue = static_cast<int64_t>(Value); 1588bcb0991SDimitry Andric switch (Fixup.getTargetKind()) { 1590b57cec5SDimitry Andric default: 1600b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!"); 1610b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adr_imm21: 16206c3fb27SDimitry Andric if (!isInt<21>(SignedValue)) 1630b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 1640b57cec5SDimitry Andric return AdrImmBits(Value & 0x1fffffULL); 1650b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adrp_imm21: 1660b57cec5SDimitry Andric assert(!IsResolved); 167349cc55cSDimitry Andric if (TheTriple.isOSBinFormatCOFF()) { 168349cc55cSDimitry Andric if (!isInt<21>(SignedValue)) 169349cc55cSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 1700b57cec5SDimitry Andric return AdrImmBits(Value & 0x1fffffULL); 171349cc55cSDimitry Andric } 1720b57cec5SDimitry Andric return AdrImmBits((Value & 0x1fffff000ULL) >> 12); 1730b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldr_pcrel_imm19: 1740b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch19: 17506c3fb27SDimitry Andric // Signed 19-bit immediate which gets multiplied by 4 17606c3fb27SDimitry Andric if (!isInt<21>(SignedValue)) 1770b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 1780b57cec5SDimitry Andric if (Value & 0x3) 1790b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned"); 1800b57cec5SDimitry Andric // Low two bits are not encoded. 1810b57cec5SDimitry Andric return (Value >> 2) & 0x7ffff; 1820b57cec5SDimitry Andric case AArch64::fixup_aarch64_add_imm12: 1830b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale1: 1840b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved) 1850b57cec5SDimitry Andric Value &= 0xfff; 1860b57cec5SDimitry Andric // Unsigned 12-bit immediate 1875f757f3fSDimitry Andric if (!isUInt<12>(Value)) 1880b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 1890b57cec5SDimitry Andric return Value; 1900b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale2: 1910b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved) 1920b57cec5SDimitry Andric Value &= 0xfff; 1930b57cec5SDimitry Andric // Unsigned 12-bit immediate which gets multiplied by 2 1945f757f3fSDimitry Andric if (!isUInt<13>(Value)) 1950b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 1960b57cec5SDimitry Andric if (Value & 0x1) 1970b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup must be 2-byte aligned"); 1980b57cec5SDimitry Andric return Value >> 1; 1990b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale4: 2000b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved) 2010b57cec5SDimitry Andric Value &= 0xfff; 2020b57cec5SDimitry Andric // Unsigned 12-bit immediate which gets multiplied by 4 2035f757f3fSDimitry Andric if (!isUInt<14>(Value)) 2040b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 2050b57cec5SDimitry Andric if (Value & 0x3) 2060b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup must be 4-byte aligned"); 2070b57cec5SDimitry Andric return Value >> 2; 2080b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale8: 2090b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved) 2100b57cec5SDimitry Andric Value &= 0xfff; 2110b57cec5SDimitry Andric // Unsigned 12-bit immediate which gets multiplied by 8 2125f757f3fSDimitry Andric if (!isUInt<15>(Value)) 2130b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 2140b57cec5SDimitry Andric if (Value & 0x7) 2150b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup must be 8-byte aligned"); 2160b57cec5SDimitry Andric return Value >> 3; 2170b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale16: 2180b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved) 2190b57cec5SDimitry Andric Value &= 0xfff; 2200b57cec5SDimitry Andric // Unsigned 12-bit immediate which gets multiplied by 16 2215f757f3fSDimitry Andric if (!isUInt<16>(Value)) 2220b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 2230b57cec5SDimitry Andric if (Value & 0xf) 2240b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup must be 16-byte aligned"); 2250b57cec5SDimitry Andric return Value >> 4; 2260b57cec5SDimitry Andric case AArch64::fixup_aarch64_movw: { 2270b57cec5SDimitry Andric AArch64MCExpr::VariantKind RefKind = 2280b57cec5SDimitry Andric static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind()); 2290b57cec5SDimitry Andric if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_ABS && 2300b57cec5SDimitry Andric AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_SABS) { 2315ffd83dbSDimitry Andric if (!RefKind) { 2325ffd83dbSDimitry Andric // The fixup is an expression 2335ffd83dbSDimitry Andric if (SignedValue > 0xFFFF || SignedValue < -0xFFFF) 2345ffd83dbSDimitry Andric Ctx.reportError(Fixup.getLoc(), 2355ffd83dbSDimitry Andric "fixup value out of range [-0xFFFF, 0xFFFF]"); 2365ffd83dbSDimitry Andric 2375ffd83dbSDimitry Andric // Invert the negative immediate because it will feed into a MOVN. 2385ffd83dbSDimitry Andric if (SignedValue < 0) 2395ffd83dbSDimitry Andric SignedValue = ~SignedValue; 2405ffd83dbSDimitry Andric Value = static_cast<uint64_t>(SignedValue); 2415ffd83dbSDimitry Andric } else 2420b57cec5SDimitry Andric // VK_GOTTPREL, VK_TPREL, VK_DTPREL are movw fixups, but they can't 2430b57cec5SDimitry Andric // ever be resolved in the assembler. 2440b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), 2450b57cec5SDimitry Andric "relocation for a thread-local variable points to an " 2460b57cec5SDimitry Andric "absolute symbol"); 2470b57cec5SDimitry Andric return Value; 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric if (!IsResolved) { 2510b57cec5SDimitry Andric // FIXME: Figure out when this can actually happen, and verify our 2520b57cec5SDimitry Andric // behavior. 2530b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "unresolved movw fixup not yet " 2540b57cec5SDimitry Andric "implemented"); 2550b57cec5SDimitry Andric return Value; 2560b57cec5SDimitry Andric } 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS) { 2590b57cec5SDimitry Andric switch (AArch64MCExpr::getAddressFrag(RefKind)) { 2600b57cec5SDimitry Andric case AArch64MCExpr::VK_G0: 2610b57cec5SDimitry Andric break; 2620b57cec5SDimitry Andric case AArch64MCExpr::VK_G1: 2630b57cec5SDimitry Andric SignedValue = SignedValue >> 16; 2640b57cec5SDimitry Andric break; 2650b57cec5SDimitry Andric case AArch64MCExpr::VK_G2: 2660b57cec5SDimitry Andric SignedValue = SignedValue >> 32; 2670b57cec5SDimitry Andric break; 2680b57cec5SDimitry Andric case AArch64MCExpr::VK_G3: 2690b57cec5SDimitry Andric SignedValue = SignedValue >> 48; 2700b57cec5SDimitry Andric break; 2710b57cec5SDimitry Andric default: 2720b57cec5SDimitry Andric llvm_unreachable("Variant kind doesn't correspond to fixup"); 2730b57cec5SDimitry Andric } 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric } else { 2760b57cec5SDimitry Andric switch (AArch64MCExpr::getAddressFrag(RefKind)) { 2770b57cec5SDimitry Andric case AArch64MCExpr::VK_G0: 2780b57cec5SDimitry Andric break; 2790b57cec5SDimitry Andric case AArch64MCExpr::VK_G1: 2800b57cec5SDimitry Andric Value = Value >> 16; 2810b57cec5SDimitry Andric break; 2820b57cec5SDimitry Andric case AArch64MCExpr::VK_G2: 2830b57cec5SDimitry Andric Value = Value >> 32; 2840b57cec5SDimitry Andric break; 2850b57cec5SDimitry Andric case AArch64MCExpr::VK_G3: 2860b57cec5SDimitry Andric Value = Value >> 48; 2870b57cec5SDimitry Andric break; 2880b57cec5SDimitry Andric default: 2890b57cec5SDimitry Andric llvm_unreachable("Variant kind doesn't correspond to fixup"); 2900b57cec5SDimitry Andric } 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric if (RefKind & AArch64MCExpr::VK_NC) { 2940b57cec5SDimitry Andric Value &= 0xFFFF; 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric else if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS) { 2970b57cec5SDimitry Andric if (SignedValue > 0xFFFF || SignedValue < -0xFFFF) 2980b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric // Invert the negative immediate because it will feed into a MOVN. 3010b57cec5SDimitry Andric if (SignedValue < 0) 3020b57cec5SDimitry Andric SignedValue = ~SignedValue; 3030b57cec5SDimitry Andric Value = static_cast<uint64_t>(SignedValue); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric else if (Value > 0xFFFF) { 3060b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric return Value; 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch14: 3110b57cec5SDimitry Andric // Signed 16-bit immediate 3125f757f3fSDimitry Andric if (!isInt<16>(SignedValue)) 3130b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 3140b57cec5SDimitry Andric // Low two bits are not encoded (4-byte alignment assumed). 3150b57cec5SDimitry Andric if (Value & 0x3) 3160b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned"); 3170b57cec5SDimitry Andric return (Value >> 2) & 0x3fff; 318cb14a3feSDimitry Andric case AArch64::fixup_aarch64_pcrel_branch16: 319cb14a3feSDimitry Andric // Unsigned PC-relative offset, so invert the negative immediate. 320cb14a3feSDimitry Andric SignedValue = -SignedValue; 321cb14a3feSDimitry Andric Value = static_cast<uint64_t>(SignedValue); 322cb14a3feSDimitry Andric // Check valid 18-bit unsigned range. 323cb14a3feSDimitry Andric if (SignedValue < 0 || SignedValue > ((1 << 18) - 1)) 324cb14a3feSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 325cb14a3feSDimitry Andric // Low two bits are not encoded (4-byte alignment assumed). 326cb14a3feSDimitry Andric if (Value & 0b11) 327cb14a3feSDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned"); 328cb14a3feSDimitry Andric return (Value >> 2) & 0xffff; 3290b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch26: 3300b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_call26: 3315f757f3fSDimitry Andric if (TheTriple.isOSBinFormatCOFF() && !IsResolved && SignedValue != 0) { 3325f757f3fSDimitry Andric // MSVC link.exe and lld do not support this relocation type 3335f757f3fSDimitry Andric // with a non-zero offset 3345f757f3fSDimitry Andric Ctx.reportError(Fixup.getLoc(), 3355f757f3fSDimitry Andric "cannot perform a PC-relative fixup with a non-zero " 3365f757f3fSDimitry Andric "symbol offset"); 3375f757f3fSDimitry Andric } 3380b57cec5SDimitry Andric // Signed 28-bit immediate 3395f757f3fSDimitry Andric if (!isInt<28>(SignedValue)) 3400b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 3410b57cec5SDimitry Andric // Low two bits are not encoded (4-byte alignment assumed). 3420b57cec5SDimitry Andric if (Value & 0x3) 3430b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned"); 3440b57cec5SDimitry Andric return (Value >> 2) & 0x3ffffff; 3450b57cec5SDimitry Andric case FK_Data_1: 3460b57cec5SDimitry Andric case FK_Data_2: 3470b57cec5SDimitry Andric case FK_Data_4: 3480b57cec5SDimitry Andric case FK_Data_8: 3490b57cec5SDimitry Andric case FK_SecRel_2: 3500b57cec5SDimitry Andric case FK_SecRel_4: 3510b57cec5SDimitry Andric return Value; 3520b57cec5SDimitry Andric } 3530b57cec5SDimitry Andric } 3540b57cec5SDimitry Andric 355bdd1243dSDimitry Andric std::optional<MCFixupKind> 356bdd1243dSDimitry Andric AArch64AsmBackend::getFixupKind(StringRef Name) const { 3575ffd83dbSDimitry Andric if (!TheTriple.isOSBinFormatELF()) 358bdd1243dSDimitry Andric return std::nullopt; 3595ffd83dbSDimitry Andric 3605ffd83dbSDimitry Andric unsigned Type = llvm::StringSwitch<unsigned>(Name) 3615ffd83dbSDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y) 3625ffd83dbSDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/AArch64.def" 3635ffd83dbSDimitry Andric #undef ELF_RELOC 364fe6060f1SDimitry Andric .Case("BFD_RELOC_NONE", ELF::R_AARCH64_NONE) 365fe6060f1SDimitry Andric .Case("BFD_RELOC_16", ELF::R_AARCH64_ABS16) 366fe6060f1SDimitry Andric .Case("BFD_RELOC_32", ELF::R_AARCH64_ABS32) 367fe6060f1SDimitry Andric .Case("BFD_RELOC_64", ELF::R_AARCH64_ABS64) 3685ffd83dbSDimitry Andric .Default(-1u); 3695ffd83dbSDimitry Andric if (Type == -1u) 370bdd1243dSDimitry Andric return std::nullopt; 3715ffd83dbSDimitry Andric return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type); 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric /// getFixupKindContainereSizeInBytes - The number of bytes of the 3750b57cec5SDimitry Andric /// container involved in big endian or 0 if the item is little endian 3760b57cec5SDimitry Andric unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) const { 3775f757f3fSDimitry Andric if (Endian == llvm::endianness::little) 3780b57cec5SDimitry Andric return 0; 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric switch (Kind) { 3810b57cec5SDimitry Andric default: 3820b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!"); 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric case FK_Data_1: 3850b57cec5SDimitry Andric return 1; 3860b57cec5SDimitry Andric case FK_Data_2: 3870b57cec5SDimitry Andric return 2; 3880b57cec5SDimitry Andric case FK_Data_4: 3890b57cec5SDimitry Andric return 4; 3900b57cec5SDimitry Andric case FK_Data_8: 3910b57cec5SDimitry Andric return 8; 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric case AArch64::fixup_aarch64_movw: 3940b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch14: 395cb14a3feSDimitry Andric case AArch64::fixup_aarch64_pcrel_branch16: 3960b57cec5SDimitry Andric case AArch64::fixup_aarch64_add_imm12: 3970b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale1: 3980b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale2: 3990b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale4: 4000b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale8: 4010b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldst_imm12_scale16: 4020b57cec5SDimitry Andric case AArch64::fixup_aarch64_ldr_pcrel_imm19: 4030b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch19: 4040b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adr_imm21: 4050b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_adrp_imm21: 4060b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_branch26: 4070b57cec5SDimitry Andric case AArch64::fixup_aarch64_pcrel_call26: 4080b57cec5SDimitry Andric // Instructions are always little endian 4090b57cec5SDimitry Andric return 0; 4100b57cec5SDimitry Andric } 4110b57cec5SDimitry Andric } 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 4140b57cec5SDimitry Andric const MCValue &Target, 4150b57cec5SDimitry Andric MutableArrayRef<char> Data, uint64_t Value, 4160b57cec5SDimitry Andric bool IsResolved, 4170b57cec5SDimitry Andric const MCSubtargetInfo *STI) const { 4185f757f3fSDimitry Andric if (Fixup.getTargetKind() == FK_Data_8 && TheTriple.isOSBinFormatELF()) { 4195f757f3fSDimitry Andric auto RefKind = static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind()); 4205f757f3fSDimitry Andric AArch64MCExpr::VariantKind SymLoc = AArch64MCExpr::getSymbolLoc(RefKind); 4215f757f3fSDimitry Andric if (SymLoc == AArch64AuthMCExpr::VK_AUTH || 4225f757f3fSDimitry Andric SymLoc == AArch64AuthMCExpr::VK_AUTHADDR) { 4235f757f3fSDimitry Andric assert(Value == 0); 4245f757f3fSDimitry Andric const auto *Expr = cast<AArch64AuthMCExpr>(Fixup.getValue()); 4255f757f3fSDimitry Andric Value = (uint64_t(Expr->getDiscriminator()) << 32) | 4265f757f3fSDimitry Andric (uint64_t(Expr->getKey()) << 60) | 4275f757f3fSDimitry Andric (uint64_t(Expr->hasAddressDiversity()) << 63); 4285f757f3fSDimitry Andric } 4295f757f3fSDimitry Andric } 4305f757f3fSDimitry Andric 4310b57cec5SDimitry Andric if (!Value) 4320b57cec5SDimitry Andric return; // Doesn't change encoding. 4335ffd83dbSDimitry Andric unsigned Kind = Fixup.getKind(); 4345ffd83dbSDimitry Andric if (Kind >= FirstLiteralRelocationKind) 4355ffd83dbSDimitry Andric return; 4365ffd83dbSDimitry Andric unsigned NumBytes = getFixupKindNumBytes(Kind); 4370b57cec5SDimitry Andric MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); 4380b57cec5SDimitry Andric MCContext &Ctx = Asm.getContext(); 4390b57cec5SDimitry Andric int64_t SignedValue = static_cast<int64_t>(Value); 4400b57cec5SDimitry Andric // Apply any target-specific value adjustments. 4410b57cec5SDimitry Andric Value = adjustFixupValue(Fixup, Target, Value, Ctx, TheTriple, IsResolved); 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric // Shift the value into position. 4440b57cec5SDimitry Andric Value <<= Info.TargetOffset; 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric unsigned Offset = Fixup.getOffset(); 4470b57cec5SDimitry Andric assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric // Used to point to big endian bytes. 4500b57cec5SDimitry Andric unsigned FulleSizeInBytes = getFixupKindContainereSizeInBytes(Fixup.getKind()); 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric // For each byte of the fragment that the fixup touches, mask in the 4530b57cec5SDimitry Andric // bits from the fixup value. 4540b57cec5SDimitry Andric if (FulleSizeInBytes == 0) { 4550b57cec5SDimitry Andric // Handle as little-endian 4560b57cec5SDimitry Andric for (unsigned i = 0; i != NumBytes; ++i) { 4570b57cec5SDimitry Andric Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric } else { 4600b57cec5SDimitry Andric // Handle as big-endian 4610b57cec5SDimitry Andric assert((Offset + FulleSizeInBytes) <= Data.size() && "Invalid fixup size!"); 4620b57cec5SDimitry Andric assert(NumBytes <= FulleSizeInBytes && "Invalid fixup size!"); 4630b57cec5SDimitry Andric for (unsigned i = 0; i != NumBytes; ++i) { 4640b57cec5SDimitry Andric unsigned Idx = FulleSizeInBytes - 1 - i; 4650b57cec5SDimitry Andric Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff); 4660b57cec5SDimitry Andric } 4670b57cec5SDimitry Andric } 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric // FIXME: getFixupKindInfo() and getFixupKindNumBytes() could be fixed to 4700b57cec5SDimitry Andric // handle this more cleanly. This may affect the output of -show-mc-encoding. 4710b57cec5SDimitry Andric AArch64MCExpr::VariantKind RefKind = 4720b57cec5SDimitry Andric static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind()); 4735ffd83dbSDimitry Andric if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS || 4745ffd83dbSDimitry Andric (!RefKind && Fixup.getTargetKind() == AArch64::fixup_aarch64_movw)) { 4750b57cec5SDimitry Andric // If the immediate is negative, generate MOVN else MOVZ. 4760b57cec5SDimitry Andric // (Bit 30 = 0) ==> MOVN, (Bit 30 = 1) ==> MOVZ. 4770b57cec5SDimitry Andric if (SignedValue < 0) 4780b57cec5SDimitry Andric Data[Offset + 3] &= ~(1 << 6); 4790b57cec5SDimitry Andric else 4800b57cec5SDimitry Andric Data[Offset + 3] |= (1 << 6); 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric } 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric bool AArch64AsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, 4850fca6ea1SDimitry Andric uint64_t Value) const { 4860b57cec5SDimitry Andric // FIXME: This isn't correct for AArch64. Just moving the "generic" logic 4870b57cec5SDimitry Andric // into the targets for now. 4880b57cec5SDimitry Andric // 4890b57cec5SDimitry Andric // Relax if the value is too big for a (signed) i8. 4900b57cec5SDimitry Andric return int64_t(Value) != int64_t(int8_t(Value)); 4910b57cec5SDimitry Andric } 4920b57cec5SDimitry Andric 4935ffd83dbSDimitry Andric void AArch64AsmBackend::relaxInstruction(MCInst &Inst, 4945ffd83dbSDimitry Andric const MCSubtargetInfo &STI) const { 4950b57cec5SDimitry Andric llvm_unreachable("AArch64AsmBackend::relaxInstruction() unimplemented"); 4960b57cec5SDimitry Andric } 4970b57cec5SDimitry Andric 498349cc55cSDimitry Andric bool AArch64AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 499349cc55cSDimitry Andric const MCSubtargetInfo *STI) const { 5000b57cec5SDimitry Andric // If the count is not 4-byte aligned, we must be writing data into the text 5010b57cec5SDimitry Andric // section (otherwise we have unaligned instructions, and thus have far 5020b57cec5SDimitry Andric // bigger problems), so just write zeros instead. 5030b57cec5SDimitry Andric OS.write_zeros(Count % 4); 5040b57cec5SDimitry Andric 5050b57cec5SDimitry Andric // We are properly aligned, so write NOPs as requested. 5060b57cec5SDimitry Andric Count /= 4; 5070b57cec5SDimitry Andric for (uint64_t i = 0; i != Count; ++i) 50881ad6265SDimitry Andric OS.write("\x1f\x20\x03\xd5", 4); 5090b57cec5SDimitry Andric return true; 5100b57cec5SDimitry Andric } 5110b57cec5SDimitry Andric 5120b57cec5SDimitry Andric bool AArch64AsmBackend::shouldForceRelocation(const MCAssembler &Asm, 5130b57cec5SDimitry Andric const MCFixup &Fixup, 5145f757f3fSDimitry Andric const MCValue &Target, 5155f757f3fSDimitry Andric const MCSubtargetInfo *STI) { 5160b57cec5SDimitry Andric unsigned Kind = Fixup.getKind(); 5175ffd83dbSDimitry Andric if (Kind >= FirstLiteralRelocationKind) 5180b57cec5SDimitry Andric return true; 5190b57cec5SDimitry Andric 5200b57cec5SDimitry Andric // The ADRP instruction adds some multiple of 0x1000 to the current PC & 5210b57cec5SDimitry Andric // ~0xfff. This means that the required offset to reach a symbol can vary by 5220b57cec5SDimitry Andric // up to one step depending on where the ADRP is in memory. For example: 5230b57cec5SDimitry Andric // 5240b57cec5SDimitry Andric // ADRP x0, there 5250b57cec5SDimitry Andric // there: 5260b57cec5SDimitry Andric // 5270b57cec5SDimitry Andric // If the ADRP occurs at address 0xffc then "there" will be at 0x1000 and 5280b57cec5SDimitry Andric // we'll need that as an offset. At any other address "there" will be in the 5290b57cec5SDimitry Andric // same page as the ADRP and the instruction should encode 0x0. Assuming the 5300b57cec5SDimitry Andric // section isn't 0x1000-aligned, we therefore need to delegate this decision 5310b57cec5SDimitry Andric // to the linker -- a relocation! 5320b57cec5SDimitry Andric if (Kind == AArch64::fixup_aarch64_pcrel_adrp_imm21) 5330b57cec5SDimitry Andric return true; 5340b57cec5SDimitry Andric 5350b57cec5SDimitry Andric return false; 5360b57cec5SDimitry Andric } 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andric namespace { 5390b57cec5SDimitry Andric 5400b57cec5SDimitry Andric namespace CU { 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric /// Compact unwind encoding values. 5430b57cec5SDimitry Andric enum CompactUnwindEncodings { 5440b57cec5SDimitry Andric /// A "frameless" leaf function, where no non-volatile registers are 5450b57cec5SDimitry Andric /// saved. The return remains in LR throughout the function. 5460b57cec5SDimitry Andric UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric /// No compact unwind encoding available. Instead the low 23-bits of 5490b57cec5SDimitry Andric /// the compact unwind encoding is the offset of the DWARF FDE in the 5500b57cec5SDimitry Andric /// __eh_frame section. This mode is never used in object files. It is only 5510b57cec5SDimitry Andric /// generated by the linker in final linked images, which have only DWARF info 5520b57cec5SDimitry Andric /// for a function. 5530b57cec5SDimitry Andric UNWIND_ARM64_MODE_DWARF = 0x03000000, 5540b57cec5SDimitry Andric 5550b57cec5SDimitry Andric /// This is a standard arm64 prologue where FP/LR are immediately 5560b57cec5SDimitry Andric /// pushed on the stack, then SP is copied to FP. If there are any 5570b57cec5SDimitry Andric /// non-volatile register saved, they are copied into the stack fame in pairs 5580b57cec5SDimitry Andric /// in a contiguous ranger right below the saved FP/LR pair. Any subset of the 5590b57cec5SDimitry Andric /// five X pairs and four D pairs can be saved, but the memory layout must be 5600b57cec5SDimitry Andric /// in register number order. 5610b57cec5SDimitry Andric UNWIND_ARM64_MODE_FRAME = 0x04000000, 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric /// Frame register pair encodings. 5640b57cec5SDimitry Andric UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, 5650b57cec5SDimitry Andric UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, 5660b57cec5SDimitry Andric UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, 5670b57cec5SDimitry Andric UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, 5680b57cec5SDimitry Andric UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, 5690b57cec5SDimitry Andric UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, 5700b57cec5SDimitry Andric UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, 5710b57cec5SDimitry Andric UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, 5720b57cec5SDimitry Andric UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800 5730b57cec5SDimitry Andric }; 5740b57cec5SDimitry Andric 5750b57cec5SDimitry Andric } // end CU namespace 5760b57cec5SDimitry Andric 5770b57cec5SDimitry Andric // FIXME: This should be in a separate file. 5780b57cec5SDimitry Andric class DarwinAArch64AsmBackend : public AArch64AsmBackend { 5790b57cec5SDimitry Andric const MCRegisterInfo &MRI; 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric /// Encode compact unwind stack adjustment for frameless functions. 5820b57cec5SDimitry Andric /// See UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK in compact_unwind_encoding.h. 5830b57cec5SDimitry Andric /// The stack size always needs to be 16 byte aligned. 5840b57cec5SDimitry Andric uint32_t encodeStackAdjustment(uint32_t StackSize) const { 5850b57cec5SDimitry Andric return (StackSize / 16) << 12; 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric public: 5890b57cec5SDimitry Andric DarwinAArch64AsmBackend(const Target &T, const Triple &TT, 5905ffd83dbSDimitry Andric const MCRegisterInfo &MRI) 5915ffd83dbSDimitry Andric : AArch64AsmBackend(T, TT, /*IsLittleEndian*/ true), MRI(MRI) {} 5920b57cec5SDimitry Andric 5930b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 5940b57cec5SDimitry Andric createObjectTargetWriter() const override { 5955ffd83dbSDimitry Andric uint32_t CPUType = cantFail(MachO::getCPUType(TheTriple)); 5965ffd83dbSDimitry Andric uint32_t CPUSubType = cantFail(MachO::getCPUSubType(TheTriple)); 5975ffd83dbSDimitry Andric return createAArch64MachObjectWriter(CPUType, CPUSubType, 5985ffd83dbSDimitry Andric TheTriple.isArch32Bit()); 5990b57cec5SDimitry Andric } 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric /// Generate the compact unwind encoding from the CFI directives. 602*36b606aeSDimitry Andric uint64_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI, 60306c3fb27SDimitry Andric const MCContext *Ctxt) const override { 60406c3fb27SDimitry Andric ArrayRef<MCCFIInstruction> Instrs = FI->Instructions; 6050b57cec5SDimitry Andric if (Instrs.empty()) 6060b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_FRAMELESS; 60706c3fb27SDimitry Andric if (!isDarwinCanonicalPersonality(FI->Personality) && 60806c3fb27SDimitry Andric !Ctxt->emitCompactUnwindNonCanonical()) 60906c3fb27SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 6100b57cec5SDimitry Andric 6110b57cec5SDimitry Andric bool HasFP = false; 612*36b606aeSDimitry Andric uint64_t StackSize = 0; 6130b57cec5SDimitry Andric 614*36b606aeSDimitry Andric uint64_t CompactUnwindEncoding = 0; 615*36b606aeSDimitry Andric int64_t CurOffset = 0; 6160b57cec5SDimitry Andric for (size_t i = 0, e = Instrs.size(); i != e; ++i) { 6170b57cec5SDimitry Andric const MCCFIInstruction &Inst = Instrs[i]; 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric switch (Inst.getOperation()) { 6200b57cec5SDimitry Andric default: 6210b57cec5SDimitry Andric // Cannot handle this directive: bail out. 6220b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 6230b57cec5SDimitry Andric case MCCFIInstruction::OpDefCfa: { 6240b57cec5SDimitry Andric // Defines a frame pointer. 6250b57cec5SDimitry Andric unsigned XReg = 6268bcb0991SDimitry Andric getXRegFromWReg(*MRI.getLLVMRegNum(Inst.getRegister(), true)); 6270b57cec5SDimitry Andric 6280b57cec5SDimitry Andric // Other CFA registers than FP are not supported by compact unwind. 6290b57cec5SDimitry Andric // Fallback on DWARF. 6300b57cec5SDimitry Andric // FIXME: When opt-remarks are supported in MC, add a remark to notify 6310b57cec5SDimitry Andric // the user. 6320b57cec5SDimitry Andric if (XReg != AArch64::FP) 6330b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 6340b57cec5SDimitry Andric 63581ad6265SDimitry Andric if (i + 2 >= e) 63681ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric const MCCFIInstruction &LRPush = Instrs[++i]; 63981ad6265SDimitry Andric if (LRPush.getOperation() != MCCFIInstruction::OpOffset) 64081ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 6410b57cec5SDimitry Andric const MCCFIInstruction &FPPush = Instrs[++i]; 64281ad6265SDimitry Andric if (FPPush.getOperation() != MCCFIInstruction::OpOffset) 64381ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 6440b57cec5SDimitry Andric 64581ad6265SDimitry Andric if (FPPush.getOffset() + 8 != LRPush.getOffset()) 64681ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 647fe6060f1SDimitry Andric CurOffset = FPPush.getOffset(); 648fe6060f1SDimitry Andric 6498bcb0991SDimitry Andric unsigned LRReg = *MRI.getLLVMRegNum(LRPush.getRegister(), true); 6508bcb0991SDimitry Andric unsigned FPReg = *MRI.getLLVMRegNum(FPPush.getRegister(), true); 6510b57cec5SDimitry Andric 6520b57cec5SDimitry Andric LRReg = getXRegFromWReg(LRReg); 6530b57cec5SDimitry Andric FPReg = getXRegFromWReg(FPReg); 6540b57cec5SDimitry Andric 65581ad6265SDimitry Andric if (LRReg != AArch64::LR || FPReg != AArch64::FP) 65681ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 6570b57cec5SDimitry Andric 6580b57cec5SDimitry Andric // Indicate that the function has a frame. 6590b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_MODE_FRAME; 6600b57cec5SDimitry Andric HasFP = true; 6610b57cec5SDimitry Andric break; 6620b57cec5SDimitry Andric } 6630b57cec5SDimitry Andric case MCCFIInstruction::OpDefCfaOffset: { 66481ad6265SDimitry Andric if (StackSize != 0) 66581ad6265SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 6660b57cec5SDimitry Andric StackSize = std::abs(Inst.getOffset()); 6670b57cec5SDimitry Andric break; 6680b57cec5SDimitry Andric } 6690b57cec5SDimitry Andric case MCCFIInstruction::OpOffset: { 6700b57cec5SDimitry Andric // Registers are saved in pairs. We expect there to be two consecutive 6710b57cec5SDimitry Andric // `.cfi_offset' instructions with the appropriate registers specified. 6728bcb0991SDimitry Andric unsigned Reg1 = *MRI.getLLVMRegNum(Inst.getRegister(), true); 6730b57cec5SDimitry Andric if (i + 1 == e) 6740b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 6750b57cec5SDimitry Andric 676fe6060f1SDimitry Andric if (CurOffset != 0 && Inst.getOffset() != CurOffset - 8) 677fe6060f1SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 678fe6060f1SDimitry Andric CurOffset = Inst.getOffset(); 679fe6060f1SDimitry Andric 6800b57cec5SDimitry Andric const MCCFIInstruction &Inst2 = Instrs[++i]; 6810b57cec5SDimitry Andric if (Inst2.getOperation() != MCCFIInstruction::OpOffset) 6820b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 6838bcb0991SDimitry Andric unsigned Reg2 = *MRI.getLLVMRegNum(Inst2.getRegister(), true); 6840b57cec5SDimitry Andric 685fe6060f1SDimitry Andric if (Inst2.getOffset() != CurOffset - 8) 686fe6060f1SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 687fe6060f1SDimitry Andric CurOffset = Inst2.getOffset(); 688fe6060f1SDimitry Andric 6890b57cec5SDimitry Andric // N.B. The encodings must be in register number order, and the X 6900b57cec5SDimitry Andric // registers before the D registers. 6910b57cec5SDimitry Andric 6920b57cec5SDimitry Andric // X19/X20 pair = 0x00000001, 6930b57cec5SDimitry Andric // X21/X22 pair = 0x00000002, 6940b57cec5SDimitry Andric // X23/X24 pair = 0x00000004, 6950b57cec5SDimitry Andric // X25/X26 pair = 0x00000008, 6960b57cec5SDimitry Andric // X27/X28 pair = 0x00000010 6970b57cec5SDimitry Andric Reg1 = getXRegFromWReg(Reg1); 6980b57cec5SDimitry Andric Reg2 = getXRegFromWReg(Reg2); 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric if (Reg1 == AArch64::X19 && Reg2 == AArch64::X20 && 7010b57cec5SDimitry Andric (CompactUnwindEncoding & 0xF1E) == 0) 7020b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X19_X20_PAIR; 7030b57cec5SDimitry Andric else if (Reg1 == AArch64::X21 && Reg2 == AArch64::X22 && 7040b57cec5SDimitry Andric (CompactUnwindEncoding & 0xF1C) == 0) 7050b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X21_X22_PAIR; 7060b57cec5SDimitry Andric else if (Reg1 == AArch64::X23 && Reg2 == AArch64::X24 && 7070b57cec5SDimitry Andric (CompactUnwindEncoding & 0xF18) == 0) 7080b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X23_X24_PAIR; 7090b57cec5SDimitry Andric else if (Reg1 == AArch64::X25 && Reg2 == AArch64::X26 && 7100b57cec5SDimitry Andric (CompactUnwindEncoding & 0xF10) == 0) 7110b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X25_X26_PAIR; 7120b57cec5SDimitry Andric else if (Reg1 == AArch64::X27 && Reg2 == AArch64::X28 && 7130b57cec5SDimitry Andric (CompactUnwindEncoding & 0xF00) == 0) 7140b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X27_X28_PAIR; 7150b57cec5SDimitry Andric else { 7160b57cec5SDimitry Andric Reg1 = getDRegFromBReg(Reg1); 7170b57cec5SDimitry Andric Reg2 = getDRegFromBReg(Reg2); 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric // D8/D9 pair = 0x00000100, 7200b57cec5SDimitry Andric // D10/D11 pair = 0x00000200, 7210b57cec5SDimitry Andric // D12/D13 pair = 0x00000400, 7220b57cec5SDimitry Andric // D14/D15 pair = 0x00000800 7230b57cec5SDimitry Andric if (Reg1 == AArch64::D8 && Reg2 == AArch64::D9 && 7240b57cec5SDimitry Andric (CompactUnwindEncoding & 0xE00) == 0) 7250b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D8_D9_PAIR; 7260b57cec5SDimitry Andric else if (Reg1 == AArch64::D10 && Reg2 == AArch64::D11 && 7270b57cec5SDimitry Andric (CompactUnwindEncoding & 0xC00) == 0) 7280b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D10_D11_PAIR; 7290b57cec5SDimitry Andric else if (Reg1 == AArch64::D12 && Reg2 == AArch64::D13 && 7300b57cec5SDimitry Andric (CompactUnwindEncoding & 0x800) == 0) 7310b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D12_D13_PAIR; 7320b57cec5SDimitry Andric else if (Reg1 == AArch64::D14 && Reg2 == AArch64::D15) 7330b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D14_D15_PAIR; 7340b57cec5SDimitry Andric else 7350b57cec5SDimitry Andric // A pair was pushed which we cannot handle. 7360b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 7370b57cec5SDimitry Andric } 7380b57cec5SDimitry Andric 7390b57cec5SDimitry Andric break; 7400b57cec5SDimitry Andric } 7410b57cec5SDimitry Andric } 7420b57cec5SDimitry Andric } 7430b57cec5SDimitry Andric 7440b57cec5SDimitry Andric if (!HasFP) { 7450b57cec5SDimitry Andric // With compact unwind info we can only represent stack adjustments of up 7460b57cec5SDimitry Andric // to 65520 bytes. 7470b57cec5SDimitry Andric if (StackSize > 65520) 7480b57cec5SDimitry Andric return CU::UNWIND_ARM64_MODE_DWARF; 7490b57cec5SDimitry Andric 7500b57cec5SDimitry Andric CompactUnwindEncoding |= CU::UNWIND_ARM64_MODE_FRAMELESS; 7510b57cec5SDimitry Andric CompactUnwindEncoding |= encodeStackAdjustment(StackSize); 7520b57cec5SDimitry Andric } 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric return CompactUnwindEncoding; 7550b57cec5SDimitry Andric } 7560b57cec5SDimitry Andric }; 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric } // end anonymous namespace 7590b57cec5SDimitry Andric 7600b57cec5SDimitry Andric namespace { 7610b57cec5SDimitry Andric 7620b57cec5SDimitry Andric class ELFAArch64AsmBackend : public AArch64AsmBackend { 7630b57cec5SDimitry Andric public: 7640b57cec5SDimitry Andric uint8_t OSABI; 7650b57cec5SDimitry Andric bool IsILP32; 7660b57cec5SDimitry Andric 7670b57cec5SDimitry Andric ELFAArch64AsmBackend(const Target &T, const Triple &TT, uint8_t OSABI, 7680b57cec5SDimitry Andric bool IsLittleEndian, bool IsILP32) 7690b57cec5SDimitry Andric : AArch64AsmBackend(T, TT, IsLittleEndian), OSABI(OSABI), 7700b57cec5SDimitry Andric IsILP32(IsILP32) {} 7710b57cec5SDimitry Andric 7720b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 7730b57cec5SDimitry Andric createObjectTargetWriter() const override { 7740b57cec5SDimitry Andric return createAArch64ELFObjectWriter(OSABI, IsILP32); 7750b57cec5SDimitry Andric } 7760b57cec5SDimitry Andric }; 7770b57cec5SDimitry Andric 7780b57cec5SDimitry Andric } 7790b57cec5SDimitry Andric 7800b57cec5SDimitry Andric namespace { 7810b57cec5SDimitry Andric class COFFAArch64AsmBackend : public AArch64AsmBackend { 7820b57cec5SDimitry Andric public: 7830b57cec5SDimitry Andric COFFAArch64AsmBackend(const Target &T, const Triple &TheTriple) 7840b57cec5SDimitry Andric : AArch64AsmBackend(T, TheTriple, /*IsLittleEndian*/ true) {} 7850b57cec5SDimitry Andric 7860b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 7870b57cec5SDimitry Andric createObjectTargetWriter() const override { 788bdd1243dSDimitry Andric return createAArch64WinCOFFObjectWriter(TheTriple); 7890b57cec5SDimitry Andric } 7900b57cec5SDimitry Andric }; 7910b57cec5SDimitry Andric } 7920b57cec5SDimitry Andric 7930b57cec5SDimitry Andric MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T, 7940b57cec5SDimitry Andric const MCSubtargetInfo &STI, 7950b57cec5SDimitry Andric const MCRegisterInfo &MRI, 7960b57cec5SDimitry Andric const MCTargetOptions &Options) { 7970b57cec5SDimitry Andric const Triple &TheTriple = STI.getTargetTriple(); 7980b57cec5SDimitry Andric if (TheTriple.isOSBinFormatMachO()) { 7995ffd83dbSDimitry Andric return new DarwinAArch64AsmBackend(T, TheTriple, MRI); 8000b57cec5SDimitry Andric } 8010b57cec5SDimitry Andric 8020b57cec5SDimitry Andric if (TheTriple.isOSBinFormatCOFF()) 8030b57cec5SDimitry Andric return new COFFAArch64AsmBackend(T, TheTriple); 8040b57cec5SDimitry Andric 8050b57cec5SDimitry Andric assert(TheTriple.isOSBinFormatELF() && "Invalid target"); 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS()); 808e8d8bef9SDimitry Andric bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32; 8090b57cec5SDimitry Andric return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/true, 8100b57cec5SDimitry Andric IsILP32); 8110b57cec5SDimitry Andric } 8120b57cec5SDimitry Andric 8130b57cec5SDimitry Andric MCAsmBackend *llvm::createAArch64beAsmBackend(const Target &T, 8140b57cec5SDimitry Andric const MCSubtargetInfo &STI, 8150b57cec5SDimitry Andric const MCRegisterInfo &MRI, 8160b57cec5SDimitry Andric const MCTargetOptions &Options) { 8170b57cec5SDimitry Andric const Triple &TheTriple = STI.getTargetTriple(); 8180b57cec5SDimitry Andric assert(TheTriple.isOSBinFormatELF() && 8190b57cec5SDimitry Andric "Big endian is only supported for ELF targets!"); 8200b57cec5SDimitry Andric uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS()); 821e8d8bef9SDimitry Andric bool IsILP32 = STI.getTargetTriple().getEnvironment() == Triple::GNUILP32; 8220b57cec5SDimitry Andric return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/false, 8230b57cec5SDimitry Andric IsILP32); 8240b57cec5SDimitry Andric } 825