diff options
Diffstat (limited to 'lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp')
-rw-r--r-- | lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp | 230 |
1 files changed, 141 insertions, 89 deletions
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp index 7624c7240d688..27993246eb07c 100644 --- a/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ b/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -12,6 +12,7 @@ #include "MCTargetDesc/AArch64FixupKinds.h" #include "llvm/ADT/Triple.h" #include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCFixupKindInfo.h" @@ -28,9 +29,12 @@ namespace { class AArch64AsmBackend : public MCAsmBackend { static const unsigned PCRelFlagVal = MCFixupKindInfo::FKF_IsAlignedDownTo32Bits | MCFixupKindInfo::FKF_IsPCRel; +public: + bool IsLittleEndian; public: - AArch64AsmBackend(const Target &T) : MCAsmBackend() {} + AArch64AsmBackend(const Target &T, bool IsLittleEndian) + : MCAsmBackend(), IsLittleEndian(IsLittleEndian) {} unsigned getNumFixupKinds() const override { return AArch64::NumTargetFixupKinds; @@ -74,12 +78,15 @@ public: bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const override; - void relaxInstruction(const MCInst &Inst, MCInst &Res) const override; + void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, + MCInst &Res) const override; bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; void HandleAssemblerFlag(MCAssemblerFlag Flag) {} unsigned getPointerSize() const { return 8; } + + unsigned getFixupKindContainereSizeInBytes(unsigned Kind) const; }; } // end anonymous namespace @@ -129,14 +136,16 @@ static unsigned AdrImmBits(unsigned Value) { return (hi19 << 5) | (lo2 << 29); } -static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) { +static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, + MCContext *Ctx) { + unsigned Kind = Fixup.getKind(); int64_t SignedValue = static_cast<int64_t>(Value); switch (Kind) { default: llvm_unreachable("Unknown fixup kind!"); case AArch64::fixup_aarch64_pcrel_adr_imm21: - if (SignedValue > 2097151 || SignedValue < -2097152) - report_fatal_error("fixup value out of range"); + if (Ctx && (SignedValue > 2097151 || SignedValue < -2097152)) + Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); return AdrImmBits(Value & 0x1fffffULL); case AArch64::fixup_aarch64_pcrel_adrp_imm21: return AdrImmBits((Value & 0x1fffff000ULL) >> 12); @@ -144,54 +153,66 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) { case AArch64::fixup_aarch64_pcrel_branch19: // Signed 21-bit immediate if (SignedValue > 2097151 || SignedValue < -2097152) - report_fatal_error("fixup value out of range"); + if (Ctx) Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); + if (Ctx && (Value & 0x3)) + Ctx->reportError(Fixup.getLoc(), "fixup not sufficiently aligned"); // Low two bits are not encoded. return (Value >> 2) & 0x7ffff; case AArch64::fixup_aarch64_add_imm12: case AArch64::fixup_aarch64_ldst_imm12_scale1: // Unsigned 12-bit immediate - if (Value >= 0x1000) - report_fatal_error("invalid imm12 fixup value"); + if (Ctx && Value >= 0x1000) + Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); return Value; case AArch64::fixup_aarch64_ldst_imm12_scale2: // Unsigned 12-bit immediate which gets multiplied by 2 - if (Value & 1 || Value >= 0x2000) - report_fatal_error("invalid imm12 fixup value"); + if (Ctx && (Value >= 0x2000)) + Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); + if (Ctx && (Value & 0x1)) + Ctx->reportError(Fixup.getLoc(), "fixup must be 2-byte aligned"); return Value >> 1; case AArch64::fixup_aarch64_ldst_imm12_scale4: // Unsigned 12-bit immediate which gets multiplied by 4 - if (Value & 3 || Value >= 0x4000) - report_fatal_error("invalid imm12 fixup value"); + if (Ctx && (Value >= 0x4000)) + Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); + if (Ctx && (Value & 0x3)) + Ctx->reportError(Fixup.getLoc(), "fixup must be 4-byte aligned"); return Value >> 2; case AArch64::fixup_aarch64_ldst_imm12_scale8: // Unsigned 12-bit immediate which gets multiplied by 8 - if (Value & 7 || Value >= 0x8000) - report_fatal_error("invalid imm12 fixup value"); + if (Ctx && (Value >= 0x8000)) + Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); + if (Ctx && (Value & 0x7)) + Ctx->reportError(Fixup.getLoc(), "fixup must be 8-byte aligned"); return Value >> 3; case AArch64::fixup_aarch64_ldst_imm12_scale16: // Unsigned 12-bit immediate which gets multiplied by 16 - if (Value & 15 || Value >= 0x10000) - report_fatal_error("invalid imm12 fixup value"); + if (Ctx && (Value >= 0x10000)) + Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); + if (Ctx && (Value & 0xf)) + Ctx->reportError(Fixup.getLoc(), "fixup must be 16-byte aligned"); return Value >> 4; case AArch64::fixup_aarch64_movw: - report_fatal_error("no resolvable MOVZ/MOVK fixups supported yet"); + if (Ctx) + Ctx->reportError(Fixup.getLoc(), + "no resolvable MOVZ/MOVK fixups supported yet"); return Value; case AArch64::fixup_aarch64_pcrel_branch14: // Signed 16-bit immediate - if (SignedValue > 32767 || SignedValue < -32768) - report_fatal_error("fixup value out of range"); + if (Ctx && (SignedValue > 32767 || SignedValue < -32768)) + Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); // Low two bits are not encoded (4-byte alignment assumed). - if (Value & 0x3) - report_fatal_error("fixup not sufficiently aligned"); + if (Ctx && (Value & 0x3)) + Ctx->reportError(Fixup.getLoc(), "fixup not sufficiently aligned"); return (Value >> 2) & 0x3fff; case AArch64::fixup_aarch64_pcrel_branch26: case AArch64::fixup_aarch64_pcrel_call26: // Signed 28-bit immediate - if (SignedValue > 134217727 || SignedValue < -134217728) - report_fatal_error("fixup value out of range"); + if (Ctx && (SignedValue > 134217727 || SignedValue < -134217728)) + Ctx->reportError(Fixup.getLoc(), "fixup value out of range"); // Low two bits are not encoded (4-byte alignment assumed). - if (Value & 0x3) - report_fatal_error("fixup not sufficiently aligned"); + if (Ctx && (Value & 0x3)) + Ctx->reportError(Fixup.getLoc(), "fixup not sufficiently aligned"); return (Value >> 2) & 0x3ffffff; case FK_Data_1: case FK_Data_2: @@ -201,6 +222,45 @@ static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) { } } +/// getFixupKindContainereSizeInBytes - The number of bytes of the +/// container involved in big endian or 0 if the item is little endian +unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) const { + if (IsLittleEndian) + return 0; + + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + + case FK_Data_1: + return 1; + case FK_Data_2: + return 2; + case FK_Data_4: + return 4; + case FK_Data_8: + return 8; + + case AArch64::fixup_aarch64_tlsdesc_call: + case AArch64::fixup_aarch64_movw: + case AArch64::fixup_aarch64_pcrel_branch14: + case AArch64::fixup_aarch64_add_imm12: + case AArch64::fixup_aarch64_ldst_imm12_scale1: + case AArch64::fixup_aarch64_ldst_imm12_scale2: + case AArch64::fixup_aarch64_ldst_imm12_scale4: + case AArch64::fixup_aarch64_ldst_imm12_scale8: + case AArch64::fixup_aarch64_ldst_imm12_scale16: + case AArch64::fixup_aarch64_ldr_pcrel_imm19: + case AArch64::fixup_aarch64_pcrel_branch19: + case AArch64::fixup_aarch64_pcrel_adr_imm21: + case AArch64::fixup_aarch64_pcrel_adrp_imm21: + case AArch64::fixup_aarch64_pcrel_branch26: + case AArch64::fixup_aarch64_pcrel_call26: + // Instructions are always little endian + return 0; + } +} + void AArch64AsmBackend::applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, uint64_t Value, bool IsPCRel) const { @@ -209,7 +269,7 @@ void AArch64AsmBackend::applyFixup(const MCFixup &Fixup, char *Data, return; // Doesn't change encoding. MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); // Apply any target-specific value adjustments. - Value = adjustFixupValue(Fixup.getKind(), Value); + Value = adjustFixupValue(Fixup, Value, nullptr); // Shift the value into position. Value <<= Info.TargetOffset; @@ -217,10 +277,25 @@ void AArch64AsmBackend::applyFixup(const MCFixup &Fixup, char *Data, unsigned Offset = Fixup.getOffset(); assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); + // Used to point to big endian bytes. + unsigned FulleSizeInBytes = getFixupKindContainereSizeInBytes(Fixup.getKind()); + // For each byte of the fragment that the fixup touches, mask in the // bits from the fixup value. - for (unsigned i = 0; i != NumBytes; ++i) - Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); + if (FulleSizeInBytes == 0) { + // Handle as little-endian + for (unsigned i = 0; i != NumBytes; ++i) { + Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); + } + } else { + // Handle as big-endian + assert((Offset + FulleSizeInBytes) <= DataSize && "Invalid fixup size!"); + assert(NumBytes <= FulleSizeInBytes && "Invalid fixup size!"); + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = FulleSizeInBytes - 1 - i; + Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff); + } + } } bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst) const { @@ -239,6 +314,7 @@ bool AArch64AsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, } void AArch64AsmBackend::relaxInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI, MCInst &Res) const { llvm_unreachable("AArch64AsmBackend::relaxInstruction() unimplemented"); } @@ -264,14 +340,14 @@ namespace CU { enum CompactUnwindEncodings { /// \brief A "frameless" leaf function, where no non-volatile registers are /// saved. The return remains in LR throughout the function. - UNWIND_AArch64_MODE_FRAMELESS = 0x02000000, + UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, /// \brief No compact unwind encoding available. Instead the low 23-bits of /// the compact unwind encoding is the offset of the DWARF FDE in the /// __eh_frame section. This mode is never used in object files. It is only /// generated by the linker in final linked images, which have only DWARF info /// for a function. - UNWIND_AArch64_MODE_DWARF = 0x03000000, + UNWIND_ARM64_MODE_DWARF = 0x03000000, /// \brief This is a standard arm64 prologue where FP/LR are immediately /// pushed on the stack, then SP is copied to FP. If there are any @@ -279,18 +355,18 @@ enum CompactUnwindEncodings { /// in a contiguous ranger right below the saved FP/LR pair. Any subset of the /// five X pairs and four D pairs can be saved, but the memory layout must be /// in register number order. - UNWIND_AArch64_MODE_FRAME = 0x04000000, + UNWIND_ARM64_MODE_FRAME = 0x04000000, /// \brief Frame register pair encodings. - UNWIND_AArch64_FRAME_X19_X20_PAIR = 0x00000001, - UNWIND_AArch64_FRAME_X21_X22_PAIR = 0x00000002, - UNWIND_AArch64_FRAME_X23_X24_PAIR = 0x00000004, - UNWIND_AArch64_FRAME_X25_X26_PAIR = 0x00000008, - UNWIND_AArch64_FRAME_X27_X28_PAIR = 0x00000010, - UNWIND_AArch64_FRAME_D8_D9_PAIR = 0x00000100, - UNWIND_AArch64_FRAME_D10_D11_PAIR = 0x00000200, - UNWIND_AArch64_FRAME_D12_D13_PAIR = 0x00000400, - UNWIND_AArch64_FRAME_D14_D15_PAIR = 0x00000800 + UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, + UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, + UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, + UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, + UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, + UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, + UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, + UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, + UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800 }; } // end CU namespace @@ -300,7 +376,7 @@ class DarwinAArch64AsmBackend : public AArch64AsmBackend { const MCRegisterInfo &MRI; /// \brief Encode compact unwind stack adjustment for frameless functions. - /// See UNWIND_AArch64_FRAMELESS_STACK_SIZE_MASK in compact_unwind_encoding.h. + /// See UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK in compact_unwind_encoding.h. /// The stack size always needs to be 16 byte aligned. uint32_t encodeStackAdjustment(uint32_t StackSize) const { return (StackSize / 16) << 12; @@ -308,7 +384,7 @@ class DarwinAArch64AsmBackend : public AArch64AsmBackend { public: DarwinAArch64AsmBackend(const Target &T, const MCRegisterInfo &MRI) - : AArch64AsmBackend(T), MRI(MRI) {} + : AArch64AsmBackend(T, /*IsLittleEndian*/true), MRI(MRI) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createAArch64MachObjectWriter(OS, MachO::CPU_TYPE_ARM64, @@ -319,7 +395,7 @@ public: uint32_t generateCompactUnwindEncoding( ArrayRef<MCCFIInstruction> Instrs) const override { if (Instrs.empty()) - return CU::UNWIND_AArch64_MODE_FRAMELESS; + return CU::UNWIND_ARM64_MODE_FRAMELESS; bool HasFP = false; unsigned StackSize = 0; @@ -331,7 +407,7 @@ public: switch (Inst.getOperation()) { default: // Cannot handle this directive: bail out. - return CU::UNWIND_AArch64_MODE_DWARF; + return CU::UNWIND_ARM64_MODE_DWARF; case MCCFIInstruction::OpDefCfa: { // Defines a frame pointer. assert(getXRegFromWReg(MRI.getLLVMRegNum(Inst.getRegister(), true)) == @@ -356,7 +432,7 @@ public: "Pushing invalid registers for frame!"); // Indicate that the function has a frame. - CompactUnwindEncoding |= CU::UNWIND_AArch64_MODE_FRAME; + CompactUnwindEncoding |= CU::UNWIND_ARM64_MODE_FRAME; HasFP = true; break; } @@ -370,11 +446,11 @@ public: // `.cfi_offset' instructions with the appropriate registers specified. unsigned Reg1 = MRI.getLLVMRegNum(Inst.getRegister(), true); if (i + 1 == e) - return CU::UNWIND_AArch64_MODE_DWARF; + return CU::UNWIND_ARM64_MODE_DWARF; const MCCFIInstruction &Inst2 = Instrs[++i]; if (Inst2.getOperation() != MCCFIInstruction::OpOffset) - return CU::UNWIND_AArch64_MODE_DWARF; + return CU::UNWIND_ARM64_MODE_DWARF; unsigned Reg2 = MRI.getLLVMRegNum(Inst2.getRegister(), true); // N.B. The encodings must be in register number order, and the X @@ -390,19 +466,19 @@ public: if (Reg1 == AArch64::X19 && Reg2 == AArch64::X20 && (CompactUnwindEncoding & 0xF1E) == 0) - CompactUnwindEncoding |= CU::UNWIND_AArch64_FRAME_X19_X20_PAIR; + CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X19_X20_PAIR; else if (Reg1 == AArch64::X21 && Reg2 == AArch64::X22 && (CompactUnwindEncoding & 0xF1C) == 0) - CompactUnwindEncoding |= CU::UNWIND_AArch64_FRAME_X21_X22_PAIR; + CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X21_X22_PAIR; else if (Reg1 == AArch64::X23 && Reg2 == AArch64::X24 && (CompactUnwindEncoding & 0xF18) == 0) - CompactUnwindEncoding |= CU::UNWIND_AArch64_FRAME_X23_X24_PAIR; + CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X23_X24_PAIR; else if (Reg1 == AArch64::X25 && Reg2 == AArch64::X26 && (CompactUnwindEncoding & 0xF10) == 0) - CompactUnwindEncoding |= CU::UNWIND_AArch64_FRAME_X25_X26_PAIR; + CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X25_X26_PAIR; else if (Reg1 == AArch64::X27 && Reg2 == AArch64::X28 && (CompactUnwindEncoding & 0xF00) == 0) - CompactUnwindEncoding |= CU::UNWIND_AArch64_FRAME_X27_X28_PAIR; + CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_X27_X28_PAIR; else { Reg1 = getDRegFromBReg(Reg1); Reg2 = getDRegFromBReg(Reg2); @@ -413,18 +489,18 @@ public: // D14/D15 pair = 0x00000800 if (Reg1 == AArch64::D8 && Reg2 == AArch64::D9 && (CompactUnwindEncoding & 0xE00) == 0) - CompactUnwindEncoding |= CU::UNWIND_AArch64_FRAME_D8_D9_PAIR; + CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D8_D9_PAIR; else if (Reg1 == AArch64::D10 && Reg2 == AArch64::D11 && (CompactUnwindEncoding & 0xC00) == 0) - CompactUnwindEncoding |= CU::UNWIND_AArch64_FRAME_D10_D11_PAIR; + CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D10_D11_PAIR; else if (Reg1 == AArch64::D12 && Reg2 == AArch64::D13 && (CompactUnwindEncoding & 0x800) == 0) - CompactUnwindEncoding |= CU::UNWIND_AArch64_FRAME_D12_D13_PAIR; + CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D12_D13_PAIR; else if (Reg1 == AArch64::D14 && Reg2 == AArch64::D15) - CompactUnwindEncoding |= CU::UNWIND_AArch64_FRAME_D14_D15_PAIR; + CompactUnwindEncoding |= CU::UNWIND_ARM64_FRAME_D14_D15_PAIR; else // A pair was pushed which we cannot handle. - return CU::UNWIND_AArch64_MODE_DWARF; + return CU::UNWIND_ARM64_MODE_DWARF; } break; @@ -436,9 +512,9 @@ public: // With compact unwind info we can only represent stack adjustments of up // to 65520 bytes. if (StackSize > 65520) - return CU::UNWIND_AArch64_MODE_DWARF; + return CU::UNWIND_ARM64_MODE_DWARF; - CompactUnwindEncoding |= CU::UNWIND_AArch64_MODE_FRAMELESS; + CompactUnwindEncoding |= CU::UNWIND_ARM64_MODE_FRAMELESS; CompactUnwindEncoding |= encodeStackAdjustment(StackSize); } @@ -453,10 +529,9 @@ namespace { class ELFAArch64AsmBackend : public AArch64AsmBackend { public: uint8_t OSABI; - bool IsLittleEndian; ELFAArch64AsmBackend(const Target &T, uint8_t OSABI, bool IsLittleEndian) - : AArch64AsmBackend(T), OSABI(OSABI), IsLittleEndian(IsLittleEndian) {} + : AArch64AsmBackend(T, IsLittleEndian), OSABI(OSABI) {} MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override { return createAArch64ELFObjectWriter(OS, OSABI, IsLittleEndian); @@ -466,9 +541,6 @@ public: const MCFixup &Fixup, const MCFragment *DF, const MCValue &Target, uint64_t &Value, bool &IsResolved) override; - - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel) const override; }; void ELFAArch64AsmBackend::processFixupValue( @@ -489,34 +561,14 @@ void ELFAArch64AsmBackend::processFixupValue( // to the linker -- a relocation! if ((uint32_t)Fixup.getKind() == AArch64::fixup_aarch64_pcrel_adrp_imm21) IsResolved = false; -} - -// Returns whether this fixup is based on an address in the .eh_frame section, -// and therefore should be byte swapped. -// FIXME: Should be replaced with something more principled. -static bool isByteSwappedFixup(const MCExpr *E) { - MCValue Val; - if (!E->evaluateAsRelocatable(Val, nullptr, nullptr)) - return false; - if (!Val.getSymA() || Val.getSymA()->getSymbol().isUndefined()) - return false; - - const MCSectionELF *SecELF = - dyn_cast<MCSectionELF>(&Val.getSymA()->getSymbol().getSection()); - return SecELF->getSectionName() == ".eh_frame"; + // Try to get the encoded value for the fixup as-if we're mapping it into + // the instruction. This allows adjustFixupValue() to issue a diagnostic + // if the value is invalid. + if (IsResolved) + (void)adjustFixupValue(Fixup, Value, &Asm.getContext()); } -void ELFAArch64AsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, - bool IsPCRel) const { - // store fixups in .eh_frame section in big endian order - if (!IsLittleEndian && Fixup.getKind() == FK_Data_4) { - if (isByteSwappedFixup(Fixup.getValue())) - Value = ByteSwap_32(unsigned(Value)); - } - AArch64AsmBackend::applyFixup (Fixup, Data, DataSize, Value, IsPCRel); -} } MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T, |