AArch64AsmBackend.cpp [plain text]
#include "MCTargetDesc/AArch64FixupKinds.h"
#include "MCTargetDesc/AArch64MCTargetDesc.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSubtargetInfo.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);
};
}
void AArch64AsmBackend::processFixupValue(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFixup &Fixup,
const MCFragment *DF,
MCValue &Target, uint64_t &Value,
bool &IsResolved) {
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] = {
{ "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;
unsigned Offset = Fixup.getOffset();
assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!");
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);
}
};
}
bool
ELFAArch64AsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const {
return false;
}
bool AArch64AsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
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:
case AArch64::fixup_a64_ld_prel:
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:
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:
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:
case AArch64::fixup_a64_add_tprel_hi12:
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:
case AArch64::fixup_a64_add_tprel_lo12:
assert((int64_t)Value >= 0 &&
(int64_t)Value < (1LL << 12) && "Out of range ADD fixup");
case AArch64::fixup_a64_add_dtprel_lo12_nc:
case AArch64::fixup_a64_add_tprel_lo12_nc:
case AArch64::fixup_a64_tlsdesc_add_lo12_nc:
case AArch64::fixup_a64_add_lo12:
return (Value & 0xfff) << 10;
case AArch64::fixup_a64_ldst8_dtprel_lo12:
case AArch64::fixup_a64_ldst8_tprel_lo12:
assert((int64_t) Value >= 0 &&
(int64_t) Value < (1LL << 12) && "Out of range LD/ST fixup");
case AArch64::fixup_a64_ldst8_dtprel_lo12_nc:
case AArch64::fixup_a64_ldst8_tprel_lo12_nc:
case AArch64::fixup_a64_ldst8_lo12:
return (Value & 0xfff) << 10;
case AArch64::fixup_a64_ldst16_dtprel_lo12:
case AArch64::fixup_a64_ldst16_tprel_lo12:
assert((int64_t) Value >= 0 &&
(int64_t) Value < (1LL << 12) && "Out of range LD/ST fixup");
case AArch64::fixup_a64_ldst16_dtprel_lo12_nc:
case AArch64::fixup_a64_ldst16_tprel_lo12_nc:
case AArch64::fixup_a64_ldst16_lo12:
return (Value & 0xffe) << 9;
case AArch64::fixup_a64_ldst32_dtprel_lo12:
case AArch64::fixup_a64_ldst32_tprel_lo12:
assert((int64_t) Value >= 0 &&
(int64_t) Value < (1LL << 12) && "Out of range LD/ST fixup");
case AArch64::fixup_a64_ldst32_dtprel_lo12_nc:
case AArch64::fixup_a64_ldst32_tprel_lo12_nc:
case AArch64::fixup_a64_ldst32_lo12:
return (Value & 0xffc) << 8;
case AArch64::fixup_a64_ldst64_dtprel_lo12:
case AArch64::fixup_a64_ldst64_tprel_lo12:
assert((int64_t) Value >= 0 &&
(int64_t) Value < (1LL << 12) && "Out of range LD/ST fixup");
case AArch64::fixup_a64_ldst64_dtprel_lo12_nc:
case AArch64::fixup_a64_ldst64_tprel_lo12_nc:
case AArch64::fixup_a64_ldst64_lo12:
return (Value & 0xff8) << 7;
case AArch64::fixup_a64_ldst128_lo12:
return (Value & 0xff0) << 6;
case AArch64::fixup_a64_movw_uabs_g0:
assert(Value <= 0xffff && "Out of range move wide fixup");
return (Value & 0xffff) << 5;
case AArch64::fixup_a64_movw_dtprel_g0_nc:
case AArch64::fixup_a64_movw_gottprel_g0_nc:
case AArch64::fixup_a64_movw_tprel_g0_nc:
case AArch64::fixup_a64_movw_uabs_g0_nc:
return (Value & 0xffff) << 5;
case AArch64::fixup_a64_movw_uabs_g1:
assert(Value <= 0xffffffffull && "Out of range move wide fixup");
return ((Value >> 16) & 0xffff) << 5;
case AArch64::fixup_a64_movw_dtprel_g1_nc:
case AArch64::fixup_a64_movw_tprel_g1_nc:
case AArch64::fixup_a64_movw_uabs_g1_nc:
return ((Value >> 16) & 0xffff) << 5;
case AArch64::fixup_a64_movw_uabs_g2:
assert(Value <= 0xffffffffffffull && "Out of range move wide fixup");
return ((Value >> 32) & 0xffff) << 5;
case AArch64::fixup_a64_movw_uabs_g2_nc:
return ((Value >> 32) & 0xffff) << 5;
case AArch64::fixup_a64_movw_uabs_g3:
return ((Value >> 48) & 0xffff) << 5;
case AArch64::fixup_a64_movw_dtprel_g0:
case AArch64::fixup_a64_movw_tprel_g0:
case AArch64::fixup_a64_movw_sabs_g0: {
int64_t Signed = Value;
assert(Signed >= -(1LL << 16) && Signed < (1LL << 16)
&& "Out of range move wide fixup");
if (Signed >= 0) {
Value = (Value & 0xffff) << 5;
Value |= 1 << 30;
} else {
Value = (~Value & 0xffff) << 5;
}
return Value;
}
case AArch64::fixup_a64_movw_dtprel_g1:
case AArch64::fixup_a64_movw_gottprel_g1:
case AArch64::fixup_a64_movw_tprel_g1:
case AArch64::fixup_a64_movw_sabs_g1: {
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;
Value |= 1 << 30;
} else {
Value = ((~Value >> 16) & 0xffff) << 5;
}
return Value;
}
case AArch64::fixup_a64_movw_dtprel_g2:
case AArch64::fixup_a64_movw_tprel_g2:
case AArch64::fixup_a64_movw_sabs_g2: {
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;
Value |= 1 << 30;
} else {
Value = ((~Value >> 32) & 0xffff) << 5;
}
return Value;
}
case AArch64::fixup_a64_tstbr:
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:
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:
case AArch64::fixup_a64_call:
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:
case AArch64::fixup_a64_tlsdesc_adr_page:
case AArch64::fixup_a64_adr_prel_got_page:
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:
case AArch64::fixup_a64_tlsdesc_ld64_lo12_nc:
case AArch64::fixup_a64_ld64_got_lo12_nc:
assert(((int64_t)Value & 7) == 0 && "Misaligned fixup");
return (Value & 0xff8) << 7;
case AArch64::fixup_a64_tlsdesc_call:
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());
}