mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-17 18:31:04 +00:00
c3cee57f7d
We used to generate the compact unwind encoding from the machine instructions. However, this had the problem that if the user used `-save-temps' or compiled their hand-written `.s' file (with CFI directives), we wouldn't generate the compact unwind encoding. Move the algorithm that generates the compact unwind encoding into the MCAsmBackend. This way we can generate the encoding whether the code is from a `.ll' or `.s' file. <rdar://problem/13623355> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190290 91177308-0d34-0410-b5e6-96231b3b80d8
586 lines
26 KiB
C++
586 lines
26 KiB
C++
//===-- AArch64AsmBackend.cpp - AArch64 Assembler Backend -----------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains the AArch64 implementation of the MCAsmBackend class,
|
|
// which is principally concerned with relaxation of the various fixup kinds.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "MCTargetDesc/AArch64FixupKinds.h"
|
|
#include "MCTargetDesc/AArch64MCTargetDesc.h"
|
|
#include "llvm/MC/MCAsmBackend.h"
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
#include "llvm/MC/MCELFObjectWriter.h"
|
|
#include "llvm/MC/MCFixupKindInfo.h"
|
|
#include "llvm/MC/MCObjectWriter.h"
|
|
#include "llvm/Support/ELF.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
class AArch64AsmBackend : public MCAsmBackend {
|
|
const MCSubtargetInfo* STI;
|
|
public:
|
|
AArch64AsmBackend(const Target &T, const StringRef TT)
|
|
: MCAsmBackend(),
|
|
STI(AArch64_MC::createAArch64MCSubtargetInfo(TT, "", ""))
|
|
{}
|
|
|
|
|
|
~AArch64AsmBackend() {
|
|
delete STI;
|
|
}
|
|
|
|
bool writeNopData(uint64_t Count, MCObjectWriter *OW) const;
|
|
|
|
virtual void processFixupValue(const MCAssembler &Asm,
|
|
const MCAsmLayout &Layout,
|
|
const MCFixup &Fixup, const MCFragment *DF,
|
|
MCValue &Target, uint64_t &Value,
|
|
bool &IsResolved);
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
void AArch64AsmBackend::processFixupValue(const MCAssembler &Asm,
|
|
const MCAsmLayout &Layout,
|
|
const MCFixup &Fixup,
|
|
const MCFragment *DF,
|
|
MCValue &Target, uint64_t &Value,
|
|
bool &IsResolved) {
|
|
// The ADRP instruction adds some multiple of 0x1000 to the current PC &
|
|
// ~0xfff. This means that the required offset to reach a symbol can vary by
|
|
// up to one step depending on where the ADRP is in memory. For example:
|
|
//
|
|
// ADRP x0, there
|
|
// there:
|
|
//
|
|
// If the ADRP occurs at address 0xffc then "there" will be at 0x1000 and
|
|
// we'll need that as an offset. At any other address "there" will be in the
|
|
// same page as the ADRP and the instruction should encode 0x0. Assuming the
|
|
// section isn't 0x1000-aligned, we therefore need to delegate this decision
|
|
// to the linker -- a relocation!
|
|
if ((uint32_t)Fixup.getKind() == AArch64::fixup_a64_adr_prel_page ||
|
|
(uint32_t)Fixup.getKind() == AArch64::fixup_a64_adr_prel_got_page ||
|
|
(uint32_t)Fixup.getKind() == AArch64::fixup_a64_adr_gottprel_page ||
|
|
(uint32_t)Fixup.getKind() == AArch64::fixup_a64_tlsdesc_adr_page)
|
|
IsResolved = false;
|
|
}
|
|
|
|
|
|
static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value);
|
|
|
|
namespace {
|
|
|
|
class ELFAArch64AsmBackend : public AArch64AsmBackend {
|
|
public:
|
|
uint8_t OSABI;
|
|
ELFAArch64AsmBackend(const Target &T, const StringRef TT,
|
|
uint8_t _OSABI)
|
|
: AArch64AsmBackend(T, TT), OSABI(_OSABI) { }
|
|
|
|
bool fixupNeedsRelaxation(const MCFixup &Fixup,
|
|
uint64_t Value,
|
|
const MCRelaxableFragment *DF,
|
|
const MCAsmLayout &Layout) const;
|
|
|
|
unsigned int getNumFixupKinds() const {
|
|
return AArch64::NumTargetFixupKinds;
|
|
}
|
|
|
|
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
|
|
const static MCFixupKindInfo Infos[AArch64::NumTargetFixupKinds] = {
|
|
// This table *must* be in the order that the fixup_* kinds are defined in
|
|
// AArch64FixupKinds.h.
|
|
//
|
|
// Name Offset (bits) Size (bits) Flags
|
|
{ "fixup_a64_ld_prel", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_adr_prel", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_adr_prel_page", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_add_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst8_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst16_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst32_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst64_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst128_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_tstbr", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_condbr", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_uncondbr", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_call", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_movw_uabs_g0", 0, 32, 0 },
|
|
{ "fixup_a64_movw_uabs_g0_nc", 0, 32, 0 },
|
|
{ "fixup_a64_movw_uabs_g1", 0, 32, 0 },
|
|
{ "fixup_a64_movw_uabs_g1_nc", 0, 32, 0 },
|
|
{ "fixup_a64_movw_uabs_g2", 0, 32, 0 },
|
|
{ "fixup_a64_movw_uabs_g2_nc", 0, 32, 0 },
|
|
{ "fixup_a64_movw_uabs_g3", 0, 32, 0 },
|
|
{ "fixup_a64_movw_sabs_g0", 0, 32, 0 },
|
|
{ "fixup_a64_movw_sabs_g1", 0, 32, 0 },
|
|
{ "fixup_a64_movw_sabs_g2", 0, 32, 0 },
|
|
{ "fixup_a64_adr_prel_got_page", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_ld64_got_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_movw_dtprel_g2", 0, 32, 0 },
|
|
{ "fixup_a64_movw_dtprel_g1", 0, 32, 0 },
|
|
{ "fixup_a64_movw_dtprel_g1_nc", 0, 32, 0 },
|
|
{ "fixup_a64_movw_dtprel_g0", 0, 32, 0 },
|
|
{ "fixup_a64_movw_dtprel_g0_nc", 0, 32, 0 },
|
|
{ "fixup_a64_add_dtprel_hi12", 0, 32, 0 },
|
|
{ "fixup_a64_add_dtprel_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_add_dtprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_ldst8_dtprel_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst8_dtprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_ldst16_dtprel_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst16_dtprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_ldst32_dtprel_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst32_dtprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_ldst64_dtprel_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst64_dtprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_movw_gottprel_g1", 0, 32, 0 },
|
|
{ "fixup_a64_movw_gottprel_g0_nc", 0, 32, 0 },
|
|
{ "fixup_a64_adr_gottprel_page", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_ld64_gottprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_ld_gottprel_prel19", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_movw_tprel_g2", 0, 32, 0 },
|
|
{ "fixup_a64_movw_tprel_g1", 0, 32, 0 },
|
|
{ "fixup_a64_movw_tprel_g1_nc", 0, 32, 0 },
|
|
{ "fixup_a64_movw_tprel_g0", 0, 32, 0 },
|
|
{ "fixup_a64_movw_tprel_g0_nc", 0, 32, 0 },
|
|
{ "fixup_a64_add_tprel_hi12", 0, 32, 0 },
|
|
{ "fixup_a64_add_tprel_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_add_tprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_ldst8_tprel_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst8_tprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_ldst16_tprel_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst16_tprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_ldst32_tprel_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst32_tprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_ldst64_tprel_lo12", 0, 32, 0 },
|
|
{ "fixup_a64_ldst64_tprel_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_tlsdesc_adr_page", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
|
|
{ "fixup_a64_tlsdesc_ld64_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_tlsdesc_add_lo12_nc", 0, 32, 0 },
|
|
{ "fixup_a64_tlsdesc_call", 0, 0, 0 }
|
|
};
|
|
if (Kind < FirstTargetFixupKind)
|
|
return MCAsmBackend::getFixupKindInfo(Kind);
|
|
|
|
assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
|
|
"Invalid kind!");
|
|
return Infos[Kind - FirstTargetFixupKind];
|
|
}
|
|
|
|
void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
|
|
uint64_t Value) const {
|
|
unsigned NumBytes = getFixupKindInfo(Fixup.getKind()).TargetSize / 8;
|
|
Value = adjustFixupValue(Fixup.getKind(), Value);
|
|
if (!Value) return; // Doesn't change encoding.
|
|
|
|
unsigned Offset = Fixup.getOffset();
|
|
assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!");
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
bool mayNeedRelaxation(const MCInst&) const {
|
|
return false;
|
|
}
|
|
|
|
void relaxInstruction(const MCInst&, llvm::MCInst&) const {
|
|
llvm_unreachable("Cannot relax instructions");
|
|
}
|
|
|
|
MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
|
|
return createAArch64ELFObjectWriter(OS, OSABI);
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
bool
|
|
ELFAArch64AsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
|
|
uint64_t Value,
|
|
const MCRelaxableFragment *DF,
|
|
const MCAsmLayout &Layout) const {
|
|
// Correct for now. With all instructions 32-bit only very low-level
|
|
// considerations could make you select something which may fail.
|
|
return false;
|
|
}
|
|
|
|
|
|
bool AArch64AsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
|
|
// Can't emit NOP with size not multiple of 32-bits
|
|
if (Count % 4 != 0)
|
|
return false;
|
|
|
|
uint64_t NumNops = Count / 4;
|
|
for (uint64_t i = 0; i != NumNops; ++i)
|
|
OW->Write32(0xd503201f);
|
|
|
|
return true;
|
|
}
|
|
|
|
static unsigned ADRImmBits(unsigned Value) {
|
|
unsigned lo2 = Value & 0x3;
|
|
unsigned hi19 = (Value & 0x1fffff) >> 2;
|
|
|
|
return (hi19 << 5) | (lo2 << 29);
|
|
}
|
|
|
|
static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
|
|
switch (Kind) {
|
|
default:
|
|
llvm_unreachable("Unknown fixup kind!");
|
|
case FK_Data_2:
|
|
assert((int64_t)Value >= -32768 &&
|
|
(int64_t)Value <= 65536 &&
|
|
"Out of range ABS16 fixup");
|
|
return Value;
|
|
case FK_Data_4:
|
|
assert((int64_t)Value >= -(1LL << 31) &&
|
|
(int64_t)Value <= (1LL << 32) - 1 &&
|
|
"Out of range ABS32 fixup");
|
|
return Value;
|
|
case FK_Data_8:
|
|
return Value;
|
|
|
|
case AArch64::fixup_a64_ld_gottprel_prel19:
|
|
// R_AARCH64_LD_GOTTPREL_PREL19: Set a load-literal immediate to bits 1F
|
|
// FFFC of G(TPREL(S+A)) - P; check -2^20 <= X < 2^20.
|
|
case AArch64::fixup_a64_ld_prel:
|
|
// R_AARCH64_LD_PREL_LO19: Sets a load-literal (immediate) value to bits
|
|
// 1F FFFC of S+A-P, checking that -2^20 <= S+A-P < 2^20.
|
|
assert((int64_t)Value >= -(1LL << 20) &&
|
|
(int64_t)Value < (1LL << 20) && "Out of range LDR (lit) fixup");
|
|
return (Value & 0x1ffffc) << 3;
|
|
|
|
case AArch64::fixup_a64_adr_prel:
|
|
// R_AARCH64_ADR_PREL_LO21: Sets an ADR immediate value to bits 1F FFFF of
|
|
// the result of S+A-P, checking that -2^20 <= S+A-P < 2^20.
|
|
assert((int64_t)Value >= -(1LL << 20) &&
|
|
(int64_t)Value < (1LL << 20) && "Out of range ADR fixup");
|
|
return ADRImmBits(Value & 0x1fffff);
|
|
|
|
case AArch64::fixup_a64_adr_prel_page:
|
|
// R_AARCH64_ADR_PREL_PG_HI21: Sets an ADRP immediate value to bits 1 FFFF
|
|
// F000 of the result of the operation, checking that -2^32 <= result <
|
|
// 2^32.
|
|
assert((int64_t)Value >= -(1LL << 32) &&
|
|
(int64_t)Value < (1LL << 32) && "Out of range ADRP fixup");
|
|
return ADRImmBits((Value & 0x1fffff000ULL) >> 12);
|
|
|
|
case AArch64::fixup_a64_add_dtprel_hi12:
|
|
// R_AARCH64_TLSLD_ADD_DTPREL_LO12: Set an ADD immediate field to bits
|
|
// FF F000 of DTPREL(S+A), check 0 <= X < 2^24.
|
|
case AArch64::fixup_a64_add_tprel_hi12:
|
|
// R_AARCH64_TLSLD_ADD_TPREL_LO12: Set an ADD immediate field to bits
|
|
// FF F000 of TPREL(S+A), check 0 <= X < 2^24.
|
|
assert((int64_t)Value >= 0 &&
|
|
(int64_t)Value < (1LL << 24) && "Out of range ADD fixup");
|
|
return (Value & 0xfff000) >> 2;
|
|
|
|
case AArch64::fixup_a64_add_dtprel_lo12:
|
|
// R_AARCH64_TLSLD_ADD_DTPREL_LO12: Set an ADD immediate field to bits
|
|
// FFF of DTPREL(S+A), check 0 <= X < 2^12.
|
|
case AArch64::fixup_a64_add_tprel_lo12:
|
|
// R_AARCH64_TLSLD_ADD_TPREL_LO12: Set an ADD immediate field to bits
|
|
// FFF of TPREL(S+A), check 0 <= X < 2^12.
|
|
assert((int64_t)Value >= 0 &&
|
|
(int64_t)Value < (1LL << 12) && "Out of range ADD fixup");
|
|
// ... fallthrough to no-checking versions ...
|
|
case AArch64::fixup_a64_add_dtprel_lo12_nc:
|
|
// R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: Set an ADD immediate field to bits
|
|
// FFF of DTPREL(S+A) with no overflow check.
|
|
case AArch64::fixup_a64_add_tprel_lo12_nc:
|
|
// R_AARCH64_TLSLD_ADD_TPREL_LO12_NC: Set an ADD immediate field to bits
|
|
// FFF of TPREL(S+A) with no overflow check.
|
|
case AArch64::fixup_a64_tlsdesc_add_lo12_nc:
|
|
// R_AARCH64_TLSDESC_ADD_LO12_NC: Set an ADD immediate field to bits
|
|
// FFF of G(TLSDESC(S+A)), with no overflow check.
|
|
case AArch64::fixup_a64_add_lo12:
|
|
// R_AARCH64_ADD_ABS_LO12_NC: Sets an ADD immediate value to bits FFF of
|
|
// S+A, with no overflow check.
|
|
return (Value & 0xfff) << 10;
|
|
|
|
case AArch64::fixup_a64_ldst8_dtprel_lo12:
|
|
// R_AARCH64_TLSLD_LDST8_DTPREL_LO12: Set an LD/ST offset field to bits FFF
|
|
// of DTPREL(S+A), check 0 <= X < 2^12.
|
|
case AArch64::fixup_a64_ldst8_tprel_lo12:
|
|
// R_AARCH64_TLSLE_LDST8_TPREL_LO12: Set an LD/ST offset field to bits FFF
|
|
// of DTPREL(S+A), check 0 <= X < 2^12.
|
|
assert((int64_t) Value >= 0 &&
|
|
(int64_t) Value < (1LL << 12) && "Out of range LD/ST fixup");
|
|
// ... fallthrough to no-checking versions ...
|
|
case AArch64::fixup_a64_ldst8_dtprel_lo12_nc:
|
|
// R_AARCH64_TLSLD_LDST8_DTPREL_LO12: Set an LD/ST offset field to bits FFF
|
|
// of DTPREL(S+A), with no overflow check.
|
|
case AArch64::fixup_a64_ldst8_tprel_lo12_nc:
|
|
// R_AARCH64_TLSLD_LDST8_TPREL_LO12: Set an LD/ST offset field to bits FFF
|
|
// of TPREL(S+A), with no overflow check.
|
|
case AArch64::fixup_a64_ldst8_lo12:
|
|
// R_AARCH64_LDST8_ABS_LO12_NC: Sets an LD/ST immediate value to bits FFF
|
|
// of S+A, with no overflow check.
|
|
return (Value & 0xfff) << 10;
|
|
|
|
case AArch64::fixup_a64_ldst16_dtprel_lo12:
|
|
// R_AARCH64_TLSLD_LDST16_DTPREL_LO12: Set an LD/ST offset field to bits FFE
|
|
// of DTPREL(S+A), check 0 <= X < 2^12.
|
|
case AArch64::fixup_a64_ldst16_tprel_lo12:
|
|
// R_AARCH64_TLSLE_LDST16_TPREL_LO12: Set an LD/ST offset field to bits FFE
|
|
// of DTPREL(S+A), check 0 <= X < 2^12.
|
|
assert((int64_t) Value >= 0 &&
|
|
(int64_t) Value < (1LL << 12) && "Out of range LD/ST fixup");
|
|
// ... fallthrough to no-checking versions ...
|
|
case AArch64::fixup_a64_ldst16_dtprel_lo12_nc:
|
|
// R_AARCH64_TLSLD_LDST16_DTPREL_LO12: Set an LD/ST offset field to bits FFE
|
|
// of DTPREL(S+A), with no overflow check.
|
|
case AArch64::fixup_a64_ldst16_tprel_lo12_nc:
|
|
// R_AARCH64_TLSLD_LDST16_TPREL_LO12: Set an LD/ST offset field to bits FFE
|
|
// of TPREL(S+A), with no overflow check.
|
|
case AArch64::fixup_a64_ldst16_lo12:
|
|
// R_AARCH64_LDST16_ABS_LO12_NC: Sets an LD/ST immediate value to bits FFE
|
|
// of S+A, with no overflow check.
|
|
return (Value & 0xffe) << 9;
|
|
|
|
case AArch64::fixup_a64_ldst32_dtprel_lo12:
|
|
// R_AARCH64_TLSLD_LDST32_DTPREL_LO12: Set an LD/ST offset field to bits FFC
|
|
// of DTPREL(S+A), check 0 <= X < 2^12.
|
|
case AArch64::fixup_a64_ldst32_tprel_lo12:
|
|
// R_AARCH64_TLSLE_LDST32_TPREL_LO12: Set an LD/ST offset field to bits FFC
|
|
// of DTPREL(S+A), check 0 <= X < 2^12.
|
|
assert((int64_t) Value >= 0 &&
|
|
(int64_t) Value < (1LL << 12) && "Out of range LD/ST fixup");
|
|
// ... fallthrough to no-checking versions ...
|
|
case AArch64::fixup_a64_ldst32_dtprel_lo12_nc:
|
|
// R_AARCH64_TLSLD_LDST32_DTPREL_LO12: Set an LD/ST offset field to bits FFC
|
|
// of DTPREL(S+A), with no overflow check.
|
|
case AArch64::fixup_a64_ldst32_tprel_lo12_nc:
|
|
// R_AARCH64_TLSLD_LDST32_TPREL_LO12: Set an LD/ST offset field to bits FFC
|
|
// of TPREL(S+A), with no overflow check.
|
|
case AArch64::fixup_a64_ldst32_lo12:
|
|
// R_AARCH64_LDST32_ABS_LO12_NC: Sets an LD/ST immediate value to bits FFC
|
|
// of S+A, with no overflow check.
|
|
return (Value & 0xffc) << 8;
|
|
|
|
case AArch64::fixup_a64_ldst64_dtprel_lo12:
|
|
// R_AARCH64_TLSLD_LDST64_DTPREL_LO12: Set an LD/ST offset field to bits FF8
|
|
// of DTPREL(S+A), check 0 <= X < 2^12.
|
|
case AArch64::fixup_a64_ldst64_tprel_lo12:
|
|
// R_AARCH64_TLSLE_LDST64_TPREL_LO12: Set an LD/ST offset field to bits FF8
|
|
// of DTPREL(S+A), check 0 <= X < 2^12.
|
|
assert((int64_t) Value >= 0 &&
|
|
(int64_t) Value < (1LL << 12) && "Out of range LD/ST fixup");
|
|
// ... fallthrough to no-checking versions ...
|
|
case AArch64::fixup_a64_ldst64_dtprel_lo12_nc:
|
|
// R_AARCH64_TLSLD_LDST64_DTPREL_LO12: Set an LD/ST offset field to bits FF8
|
|
// of DTPREL(S+A), with no overflow check.
|
|
case AArch64::fixup_a64_ldst64_tprel_lo12_nc:
|
|
// R_AARCH64_TLSLD_LDST64_TPREL_LO12: Set an LD/ST offset field to bits FF8
|
|
// of TPREL(S+A), with no overflow check.
|
|
case AArch64::fixup_a64_ldst64_lo12:
|
|
// R_AARCH64_LDST64_ABS_LO12_NC: Sets an LD/ST immediate value to bits FF8
|
|
// of S+A, with no overflow check.
|
|
return (Value & 0xff8) << 7;
|
|
|
|
case AArch64::fixup_a64_ldst128_lo12:
|
|
// R_AARCH64_LDST128_ABS_LO12_NC: Sets an LD/ST immediate value to bits FF0
|
|
// of S+A, with no overflow check.
|
|
return (Value & 0xff0) << 6;
|
|
|
|
case AArch64::fixup_a64_movw_uabs_g0:
|
|
// R_AARCH64_MOVW_UABS_G0: Sets a MOVZ immediate field to bits FFFF of S+A
|
|
// with a check that S+A < 2^16
|
|
assert(Value <= 0xffff && "Out of range move wide fixup");
|
|
return (Value & 0xffff) << 5;
|
|
|
|
case AArch64::fixup_a64_movw_dtprel_g0_nc:
|
|
// R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: Sets a MOVK immediate field to bits
|
|
// FFFF of DTPREL(S+A) with no overflow check.
|
|
case AArch64::fixup_a64_movw_gottprel_g0_nc:
|
|
// R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: Sets a MOVK immediate field to bits
|
|
// FFFF of G(TPREL(S+A)) - GOT with no overflow check.
|
|
case AArch64::fixup_a64_movw_tprel_g0_nc:
|
|
// R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: Sets a MOVK immediate field to bits
|
|
// FFFF of TPREL(S+A) with no overflow check.
|
|
case AArch64::fixup_a64_movw_uabs_g0_nc:
|
|
// R_AARCH64_MOVW_UABS_G0_NC: Sets a MOVK immediate field to bits FFFF of
|
|
// S+A with no overflow check.
|
|
return (Value & 0xffff) << 5;
|
|
|
|
case AArch64::fixup_a64_movw_uabs_g1:
|
|
// R_AARCH64_MOVW_UABS_G1: Sets a MOVZ immediate field to bits FFFF0000 of
|
|
// S+A with a check that S+A < 2^32
|
|
assert(Value <= 0xffffffffull && "Out of range move wide fixup");
|
|
return ((Value >> 16) & 0xffff) << 5;
|
|
|
|
case AArch64::fixup_a64_movw_dtprel_g1_nc:
|
|
// R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: Set a MOVK immediate field
|
|
// to bits FFFF0000 of DTPREL(S+A), with no overflow check.
|
|
case AArch64::fixup_a64_movw_tprel_g1_nc:
|
|
// R_AARCH64_TLSLD_MOVW_TPREL_G1_NC: Set a MOVK immediate field
|
|
// to bits FFFF0000 of TPREL(S+A), with no overflow check.
|
|
case AArch64::fixup_a64_movw_uabs_g1_nc:
|
|
// R_AARCH64_MOVW_UABS_G1_NC: Sets a MOVK immediate field to bits
|
|
// FFFF0000 of S+A with no overflow check.
|
|
return ((Value >> 16) & 0xffff) << 5;
|
|
|
|
case AArch64::fixup_a64_movw_uabs_g2:
|
|
// R_AARCH64_MOVW_UABS_G2: Sets a MOVZ immediate field to bits FFFF 0000
|
|
// 0000 of S+A with a check that S+A < 2^48
|
|
assert(Value <= 0xffffffffffffull && "Out of range move wide fixup");
|
|
return ((Value >> 32) & 0xffff) << 5;
|
|
|
|
case AArch64::fixup_a64_movw_uabs_g2_nc:
|
|
// R_AARCH64_MOVW_UABS_G2: Sets a MOVK immediate field to bits FFFF 0000
|
|
// 0000 of S+A with no overflow check.
|
|
return ((Value >> 32) & 0xffff) << 5;
|
|
|
|
case AArch64::fixup_a64_movw_uabs_g3:
|
|
// R_AARCH64_MOVW_UABS_G3: Sets a MOVZ immediate field to bits FFFF 0000
|
|
// 0000 0000 of S+A (no overflow check needed)
|
|
return ((Value >> 48) & 0xffff) << 5;
|
|
|
|
case AArch64::fixup_a64_movw_dtprel_g0:
|
|
// R_AARCH64_TLSLD_MOVW_DTPREL_G0: Set a MOV[NZ] immediate field
|
|
// to bits FFFF of DTPREL(S+A).
|
|
case AArch64::fixup_a64_movw_tprel_g0:
|
|
// R_AARCH64_TLSLE_MOVW_TPREL_G0: Set a MOV[NZ] immediate field to
|
|
// bits FFFF of TPREL(S+A).
|
|
case AArch64::fixup_a64_movw_sabs_g0: {
|
|
// R_AARCH64_MOVW_SABS_G0: Sets MOV[NZ] immediate field using bits FFFF of
|
|
// S+A (see notes below); check -2^16 <= S+A < 2^16. (notes say that we
|
|
// should convert between MOVN and MOVZ to achieve our goals).
|
|
int64_t Signed = Value;
|
|
assert(Signed >= -(1LL << 16) && Signed < (1LL << 16)
|
|
&& "Out of range move wide fixup");
|
|
if (Signed >= 0) {
|
|
Value = (Value & 0xffff) << 5;
|
|
// Bit 30 converts the MOVN encoding into a MOVZ
|
|
Value |= 1 << 30;
|
|
} else {
|
|
// MCCodeEmitter should have encoded a MOVN, which is fine.
|
|
Value = (~Value & 0xffff) << 5;
|
|
}
|
|
return Value;
|
|
}
|
|
|
|
case AArch64::fixup_a64_movw_dtprel_g1:
|
|
// R_AARCH64_TLSLD_MOVW_DTPREL_G1: Set a MOV[NZ] immediate field
|
|
// to bits FFFF0000 of DTPREL(S+A).
|
|
case AArch64::fixup_a64_movw_gottprel_g1:
|
|
// R_AARCH64_TLSIE_MOVW_GOTTPREL_G1: Set a MOV[NZ] immediate field
|
|
// to bits FFFF0000 of G(TPREL(S+A)) - GOT.
|
|
case AArch64::fixup_a64_movw_tprel_g1:
|
|
// R_AARCH64_TLSLE_MOVW_TPREL_G1: Set a MOV[NZ] immediate field to
|
|
// bits FFFF0000 of TPREL(S+A).
|
|
case AArch64::fixup_a64_movw_sabs_g1: {
|
|
// R_AARCH64_MOVW_SABS_G1: Sets MOV[NZ] immediate field using bits FFFF 0000
|
|
// of S+A (see notes below); check -2^32 <= S+A < 2^32. (notes say that we
|
|
// should convert between MOVN and MOVZ to achieve our goals).
|
|
int64_t Signed = Value;
|
|
assert(Signed >= -(1LL << 32) && Signed < (1LL << 32)
|
|
&& "Out of range move wide fixup");
|
|
if (Signed >= 0) {
|
|
Value = ((Value >> 16) & 0xffff) << 5;
|
|
// Bit 30 converts the MOVN encoding into a MOVZ
|
|
Value |= 1 << 30;
|
|
} else {
|
|
Value = ((~Value >> 16) & 0xffff) << 5;
|
|
}
|
|
return Value;
|
|
}
|
|
|
|
case AArch64::fixup_a64_movw_dtprel_g2:
|
|
// R_AARCH64_TLSLD_MOVW_DTPREL_G2: Set a MOV[NZ] immediate field
|
|
// to bits FFFF 0000 0000 of DTPREL(S+A).
|
|
case AArch64::fixup_a64_movw_tprel_g2:
|
|
// R_AARCH64_TLSLE_MOVW_TPREL_G2: Set a MOV[NZ] immediate field to
|
|
// bits FFFF 0000 0000 of TPREL(S+A).
|
|
case AArch64::fixup_a64_movw_sabs_g2: {
|
|
// R_AARCH64_MOVW_SABS_G2: Sets MOV[NZ] immediate field using bits FFFF 0000
|
|
// 0000 of S+A (see notes below); check -2^48 <= S+A < 2^48. (notes say that
|
|
// we should convert between MOVN and MOVZ to achieve our goals).
|
|
int64_t Signed = Value;
|
|
assert(Signed >= -(1LL << 48) && Signed < (1LL << 48)
|
|
&& "Out of range move wide fixup");
|
|
if (Signed >= 0) {
|
|
Value = ((Value >> 32) & 0xffff) << 5;
|
|
// Bit 30 converts the MOVN encoding into a MOVZ
|
|
Value |= 1 << 30;
|
|
} else {
|
|
Value = ((~Value >> 32) & 0xffff) << 5;
|
|
}
|
|
return Value;
|
|
}
|
|
|
|
case AArch64::fixup_a64_tstbr:
|
|
// R_AARCH64_TSTBR14: Sets the immediate field of a TBZ/TBNZ instruction to
|
|
// bits FFFC of S+A-P, checking -2^15 <= S+A-P < 2^15.
|
|
assert((int64_t)Value >= -(1LL << 15) &&
|
|
(int64_t)Value < (1LL << 15) && "Out of range TBZ/TBNZ fixup");
|
|
return (Value & 0xfffc) << (5 - 2);
|
|
|
|
case AArch64::fixup_a64_condbr:
|
|
// R_AARCH64_CONDBR19: Sets the immediate field of a conditional branch
|
|
// instruction to bits 1FFFFC of S+A-P, checking -2^20 <= S+A-P < 2^20.
|
|
assert((int64_t)Value >= -(1LL << 20) &&
|
|
(int64_t)Value < (1LL << 20) && "Out of range B.cond fixup");
|
|
return (Value & 0x1ffffc) << (5 - 2);
|
|
|
|
case AArch64::fixup_a64_uncondbr:
|
|
// R_AARCH64_JUMP26 same as below (except to a linker, possibly).
|
|
case AArch64::fixup_a64_call:
|
|
// R_AARCH64_CALL26: Sets a CALL immediate field to bits FFFFFFC of S+A-P,
|
|
// checking that -2^27 <= S+A-P < 2^27.
|
|
assert((int64_t)Value >= -(1LL << 27) &&
|
|
(int64_t)Value < (1LL << 27) && "Out of range branch fixup");
|
|
return (Value & 0xffffffc) >> 2;
|
|
|
|
case AArch64::fixup_a64_adr_gottprel_page:
|
|
// R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: Set an ADRP immediate field to bits
|
|
// 1FFFFF000 of Page(G(TPREL(S+A))) - Page(P); check -2^32 <= X < 2^32.
|
|
case AArch64::fixup_a64_tlsdesc_adr_page:
|
|
// R_AARCH64_TLSDESC_ADR_PAGE: Set an ADRP immediate field to bits 1FFFFF000
|
|
// of Page(G(TLSDESC(S+A))) - Page(P); check -2^32 <= X < 2^32.
|
|
case AArch64::fixup_a64_adr_prel_got_page:
|
|
// R_AARCH64_ADR_GOT_PAGE: Sets the immediate value of an ADRP to bits
|
|
// 1FFFFF000 of the operation, checking that -2^32 < Page(G(S))-Page(GOT) <
|
|
// 2^32.
|
|
assert((int64_t)Value >= -(1LL << 32) &&
|
|
(int64_t)Value < (1LL << 32) && "Out of range ADRP fixup");
|
|
return ADRImmBits((Value & 0x1fffff000ULL) >> 12);
|
|
|
|
case AArch64::fixup_a64_ld64_gottprel_lo12_nc:
|
|
// R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: Set an LD offset field to bits FF8
|
|
// of X, with no overflow check. Check that X & 7 == 0.
|
|
case AArch64::fixup_a64_tlsdesc_ld64_lo12_nc:
|
|
// R_AARCH64_TLSDESC_LD64_LO12_NC: Set an LD offset field to bits FF8 of
|
|
// G(TLSDESC(S+A)), with no overflow check. Check that X & 7 == 0.
|
|
case AArch64::fixup_a64_ld64_got_lo12_nc:
|
|
// R_AARCH64_LD64_GOT_LO12_NC: Sets the LD/ST immediate field to bits FF8 of
|
|
// G(S) with no overflow check. Check X & 7 == 0
|
|
assert(((int64_t)Value & 7) == 0 && "Misaligned fixup");
|
|
return (Value & 0xff8) << 7;
|
|
|
|
case AArch64::fixup_a64_tlsdesc_call:
|
|
// R_AARCH64_TLSDESC_CALL: For relaxation only.
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
MCAsmBackend *
|
|
llvm::createAArch64AsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
|
StringRef TT, StringRef CPU) {
|
|
Triple TheTriple(TT);
|
|
return new ELFAArch64AsmBackend(T, TT, TheTriple.getOS());
|
|
}
|