summaryrefslogtreecommitdiff
path: root/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp')
-rw-r--r--lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp101
1 files changed, 62 insertions, 39 deletions
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
index 2bd0cbf9f7c6..7b33b4b5b542 100644
--- a/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
@@ -30,12 +30,14 @@ namespace {
class AArch64AsmBackend : public MCAsmBackend {
static const unsigned PCRelFlagVal =
MCFixupKindInfo::FKF_IsAlignedDownTo32Bits | MCFixupKindInfo::FKF_IsPCRel;
+ Triple TheTriple;
+
public:
bool IsLittleEndian;
public:
- AArch64AsmBackend(const Target &T, bool IsLittleEndian)
- : MCAsmBackend(), IsLittleEndian(IsLittleEndian) {}
+ AArch64AsmBackend(const Target &T, const Triple &TT, bool IsLittleEndian)
+ : MCAsmBackend(), TheTriple(TT), IsLittleEndian(IsLittleEndian) {}
unsigned getNumFixupKinds() const override {
return AArch64::NumTargetFixupKinds;
@@ -88,6 +90,9 @@ public:
unsigned getPointerSize() const { return 8; }
unsigned getFixupKindContainereSizeInBytes(unsigned Kind) const;
+
+ bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
+ const MCValue &Target) override;
};
} // end anonymous namespace
@@ -140,7 +145,8 @@ static unsigned AdrImmBits(unsigned Value) {
}
static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
- MCContext &Ctx) {
+ MCContext &Ctx, const Triple &TheTriple,
+ bool IsResolved) {
unsigned Kind = Fixup.getKind();
int64_t SignedValue = static_cast<int64_t>(Value);
switch (Kind) {
@@ -151,6 +157,9 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
return AdrImmBits(Value & 0x1fffffULL);
case AArch64::fixup_aarch64_pcrel_adrp_imm21:
+ assert(!IsResolved);
+ if (TheTriple.isOSBinFormatCOFF())
+ return AdrImmBits(Value & 0x1fffffULL);
return AdrImmBits((Value & 0x1fffff000ULL) >> 12);
case AArch64::fixup_aarch64_ldr_pcrel_imm19:
case AArch64::fixup_aarch64_pcrel_branch19:
@@ -163,11 +172,15 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
return (Value >> 2) & 0x7ffff;
case AArch64::fixup_aarch64_add_imm12:
case AArch64::fixup_aarch64_ldst_imm12_scale1:
+ if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
+ Value &= 0xfff;
// Unsigned 12-bit immediate
if (Value >= 0x1000)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
return Value;
case AArch64::fixup_aarch64_ldst_imm12_scale2:
+ if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
+ Value &= 0xfff;
// Unsigned 12-bit immediate which gets multiplied by 2
if (Value >= 0x2000)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
@@ -175,6 +188,8 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
Ctx.reportError(Fixup.getLoc(), "fixup must be 2-byte aligned");
return Value >> 1;
case AArch64::fixup_aarch64_ldst_imm12_scale4:
+ if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
+ Value &= 0xfff;
// Unsigned 12-bit immediate which gets multiplied by 4
if (Value >= 0x4000)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
@@ -182,6 +197,8 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
Ctx.reportError(Fixup.getLoc(), "fixup must be 4-byte aligned");
return Value >> 2;
case AArch64::fixup_aarch64_ldst_imm12_scale8:
+ if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
+ Value &= 0xfff;
// Unsigned 12-bit immediate which gets multiplied by 8
if (Value >= 0x8000)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
@@ -189,6 +206,8 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
Ctx.reportError(Fixup.getLoc(), "fixup must be 8-byte aligned");
return Value >> 3;
case AArch64::fixup_aarch64_ldst_imm12_scale16:
+ if (TheTriple.isOSBinFormatCOFF() && !IsResolved)
+ Value &= 0xfff;
// Unsigned 12-bit immediate which gets multiplied by 16
if (Value >= 0x10000)
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
@@ -275,7 +294,7 @@ void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
MCContext &Ctx = Asm.getContext();
// Apply any target-specific value adjustments.
- Value = adjustFixupValue(Fixup, Value, Ctx);
+ Value = adjustFixupValue(Fixup, Value, Ctx, TheTriple, IsResolved);
// Shift the value into position.
Value <<= Info.TargetOffset;
@@ -338,6 +357,26 @@ bool AArch64AsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
return true;
}
+bool AArch64AsmBackend::shouldForceRelocation(const MCAssembler &Asm,
+ const MCFixup &Fixup,
+ const MCValue &Target) {
+ // 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_aarch64_pcrel_adrp_imm21)
+ return true;
+ return false;
+}
+
namespace {
namespace CU {
@@ -389,10 +428,12 @@ class DarwinAArch64AsmBackend : public AArch64AsmBackend {
}
public:
- DarwinAArch64AsmBackend(const Target &T, const MCRegisterInfo &MRI)
- : AArch64AsmBackend(T, /*IsLittleEndian*/true), MRI(MRI) {}
+ DarwinAArch64AsmBackend(const Target &T, const Triple &TT,
+ const MCRegisterInfo &MRI)
+ : AArch64AsmBackend(T, TT, /*IsLittleEndian*/ true), MRI(MRI) {}
- MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
+ std::unique_ptr<MCObjectWriter>
+ createObjectWriter(raw_pwrite_stream &OS) const override {
return createAArch64MachObjectWriter(OS, MachO::CPU_TYPE_ARM64,
MachO::CPU_SUBTYPE_ARM64_ALL);
}
@@ -537,47 +578,27 @@ public:
uint8_t OSABI;
bool IsILP32;
- ELFAArch64AsmBackend(const Target &T, uint8_t OSABI, bool IsLittleEndian,
- bool IsILP32)
- : AArch64AsmBackend(T, IsLittleEndian), OSABI(OSABI), IsILP32(IsILP32) {}
+ ELFAArch64AsmBackend(const Target &T, const Triple &TT, uint8_t OSABI,
+ bool IsLittleEndian, bool IsILP32)
+ : AArch64AsmBackend(T, TT, IsLittleEndian), OSABI(OSABI),
+ IsILP32(IsILP32) {}
- MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
+ std::unique_ptr<MCObjectWriter>
+ createObjectWriter(raw_pwrite_stream &OS) const override {
return createAArch64ELFObjectWriter(OS, OSABI, IsLittleEndian, IsILP32);
}
-
- bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
- const MCValue &Target) override;
};
-bool ELFAArch64AsmBackend::shouldForceRelocation(const MCAssembler &Asm,
- const MCFixup &Fixup,
- const MCValue &Target) {
- // 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_aarch64_pcrel_adrp_imm21)
- return true;
- return false;
-}
-
}
namespace {
class COFFAArch64AsmBackend : public AArch64AsmBackend {
public:
COFFAArch64AsmBackend(const Target &T, const Triple &TheTriple)
- : AArch64AsmBackend(T, /*IsLittleEndian*/true) {}
+ : AArch64AsmBackend(T, TheTriple, /*IsLittleEndian*/ true) {}
- MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
+ std::unique_ptr<MCObjectWriter>
+ createObjectWriter(raw_pwrite_stream &OS) const override {
return createAArch64WinCOFFObjectWriter(OS);
}
};
@@ -589,7 +610,7 @@ MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T,
StringRef CPU,
const MCTargetOptions &Options) {
if (TheTriple.isOSBinFormatMachO())
- return new DarwinAArch64AsmBackend(T, MRI);
+ return new DarwinAArch64AsmBackend(T, TheTriple, MRI);
if (TheTriple.isOSBinFormatCOFF())
return new COFFAArch64AsmBackend(T, TheTriple);
@@ -598,7 +619,8 @@ MCAsmBackend *llvm::createAArch64leAsmBackend(const Target &T,
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
bool IsILP32 = Options.getABIName() == "ilp32";
- return new ELFAArch64AsmBackend(T, OSABI, /*IsLittleEndian=*/true, IsILP32);
+ return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/true,
+ IsILP32);
}
MCAsmBackend *llvm::createAArch64beAsmBackend(const Target &T,
@@ -610,5 +632,6 @@ MCAsmBackend *llvm::createAArch64beAsmBackend(const Target &T,
"Big endian is only supported for ELF targets!");
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
bool IsILP32 = Options.getABIName() == "ilp32";
- return new ELFAArch64AsmBackend(T, OSABI, /*IsLittleEndian=*/false, IsILP32);
+ return new ELFAArch64AsmBackend(T, TheTriple, OSABI, /*IsLittleEndian=*/false,
+ IsILP32);
}