10b57cec5SDimitry Andric //===-- MSP430AsmBackend.cpp - MSP430 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/MSP430FixupKinds.h" 100b57cec5SDimitry Andric #include "MCTargetDesc/MSP430MCTargetDesc.h" 110b57cec5SDimitry Andric #include "llvm/ADT/APInt.h" 120b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h" 130b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h" 140b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 150b57cec5SDimitry Andric #include "llvm/MC/MCDirectives.h" 160b57cec5SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h" 180b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h" 190b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h" 200b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 210b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 220b57cec5SDimitry Andric #include "llvm/MC/MCTargetOptions.h" 230b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric namespace { 290b57cec5SDimitry Andric class MSP430AsmBackend : public MCAsmBackend { 300b57cec5SDimitry Andric uint8_t OSABI; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, 330b57cec5SDimitry Andric MCContext &Ctx) const; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric public: 360b57cec5SDimitry Andric MSP430AsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI) 375f757f3fSDimitry Andric : MCAsmBackend(llvm::endianness::little), OSABI(OSABI) {} 3881ad6265SDimitry Andric ~MSP430AsmBackend() override = default; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 410b57cec5SDimitry Andric const MCValue &Target, MutableArrayRef<char> Data, 420b57cec5SDimitry Andric uint64_t Value, bool IsResolved, 430b57cec5SDimitry Andric const MCSubtargetInfo *STI) const override; 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 460b57cec5SDimitry Andric createObjectTargetWriter() const override { 470b57cec5SDimitry Andric return createMSP430ELFObjectWriter(OSABI); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 50*0fca6ea1SDimitry Andric bool fixupNeedsRelaxationAdvanced(const MCAssembler &Asm, 51*0fca6ea1SDimitry Andric const MCFixup &Fixup, bool Resolved, 520b57cec5SDimitry Andric uint64_t Value, 530b57cec5SDimitry Andric const MCRelaxableFragment *DF, 540b57cec5SDimitry Andric const bool WasForced) const override { 550b57cec5SDimitry Andric return false; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric unsigned getNumFixupKinds() const override { 590b57cec5SDimitry Andric return MSP430::NumTargetFixupKinds; 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { 630b57cec5SDimitry Andric const static MCFixupKindInfo Infos[MSP430::NumTargetFixupKinds] = { 640b57cec5SDimitry Andric // This table must be in the same order of enum in MSP430FixupKinds.h. 650b57cec5SDimitry Andric // 660b57cec5SDimitry Andric // name offset bits flags 670b57cec5SDimitry Andric {"fixup_32", 0, 32, 0}, 680b57cec5SDimitry Andric {"fixup_10_pcrel", 0, 10, MCFixupKindInfo::FKF_IsPCRel}, 690b57cec5SDimitry Andric {"fixup_16", 0, 16, 0}, 700b57cec5SDimitry Andric {"fixup_16_pcrel", 0, 16, MCFixupKindInfo::FKF_IsPCRel}, 710b57cec5SDimitry Andric {"fixup_16_byte", 0, 16, 0}, 720b57cec5SDimitry Andric {"fixup_16_pcrel_byte", 0, 16, MCFixupKindInfo::FKF_IsPCRel}, 730b57cec5SDimitry Andric {"fixup_2x_pcrel", 0, 10, MCFixupKindInfo::FKF_IsPCRel}, 740b57cec5SDimitry Andric {"fixup_rl_pcrel", 0, 16, MCFixupKindInfo::FKF_IsPCRel}, 750b57cec5SDimitry Andric {"fixup_8", 0, 8, 0}, 760b57cec5SDimitry Andric {"fixup_sym_diff", 0, 32, 0}, 770b57cec5SDimitry Andric }; 78bdd1243dSDimitry Andric static_assert((std::size(Infos)) == MSP430::NumTargetFixupKinds, 790b57cec5SDimitry Andric "Not all fixup kinds added to Infos array"); 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric if (Kind < FirstTargetFixupKind) 820b57cec5SDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind); 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric return Infos[Kind - FirstTargetFixupKind]; 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 87349cc55cSDimitry Andric bool writeNopData(raw_ostream &OS, uint64_t Count, 88349cc55cSDimitry Andric const MCSubtargetInfo *STI) const override; 890b57cec5SDimitry Andric }; 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric uint64_t MSP430AsmBackend::adjustFixupValue(const MCFixup &Fixup, 920b57cec5SDimitry Andric uint64_t Value, 930b57cec5SDimitry Andric MCContext &Ctx) const { 940b57cec5SDimitry Andric unsigned Kind = Fixup.getKind(); 950b57cec5SDimitry Andric switch (Kind) { 960b57cec5SDimitry Andric case MSP430::fixup_10_pcrel: { 970b57cec5SDimitry Andric if (Value & 0x1) 980b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned"); 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric // Offset is signed 1010b57cec5SDimitry Andric int16_t Offset = Value; 1020b57cec5SDimitry Andric // Jumps are in words 1030b57cec5SDimitry Andric Offset >>= 1; 1040b57cec5SDimitry Andric // PC points to the next instruction so decrement by one 1050b57cec5SDimitry Andric --Offset; 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric if (Offset < -512 || Offset > 511) 1080b57cec5SDimitry Andric Ctx.reportError(Fixup.getLoc(), "fixup value out of range"); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric // Mask 10 bits 1110b57cec5SDimitry Andric Offset &= 0x3ff; 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric return Offset; 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric default: 1160b57cec5SDimitry Andric return Value; 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric void MSP430AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 1210b57cec5SDimitry Andric const MCValue &Target, 1220b57cec5SDimitry Andric MutableArrayRef<char> Data, 1230b57cec5SDimitry Andric uint64_t Value, bool IsResolved, 1240b57cec5SDimitry Andric const MCSubtargetInfo *STI) const { 1250b57cec5SDimitry Andric Value = adjustFixupValue(Fixup, Value, Asm.getContext()); 1260b57cec5SDimitry Andric MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); 1270b57cec5SDimitry Andric if (!Value) 1280b57cec5SDimitry Andric return; // Doesn't change encoding. 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric // Shift the value into position. 1310b57cec5SDimitry Andric Value <<= Info.TargetOffset; 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric unsigned Offset = Fixup.getOffset(); 1340b57cec5SDimitry Andric unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8; 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric // For each byte of the fragment that the fixup touches, mask in the 1390b57cec5SDimitry Andric // bits from the fixup value. 1400b57cec5SDimitry Andric for (unsigned i = 0; i != NumBytes; ++i) { 1410b57cec5SDimitry Andric Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 145349cc55cSDimitry Andric bool MSP430AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 146349cc55cSDimitry Andric const MCSubtargetInfo *STI) const { 1470b57cec5SDimitry Andric if ((Count % 2) != 0) 1480b57cec5SDimitry Andric return false; 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric // The canonical nop on MSP430 is mov #0, r3 1510b57cec5SDimitry Andric uint64_t NopCount = Count / 2; 1520b57cec5SDimitry Andric while (NopCount--) 1530b57cec5SDimitry Andric OS.write("\x03\x43", 2); 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric return true; 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric } // end anonymous namespace 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric MCAsmBackend *llvm::createMSP430MCAsmBackend(const Target &T, 1610b57cec5SDimitry Andric const MCSubtargetInfo &STI, 1620b57cec5SDimitry Andric const MCRegisterInfo &MRI, 1630b57cec5SDimitry Andric const MCTargetOptions &Options) { 1640b57cec5SDimitry Andric return new MSP430AsmBackend(STI, ELF::ELFOSABI_STANDALONE); 1650b57cec5SDimitry Andric } 166