10b57cec5SDimitry Andric //===-- BPFAsmBackend.cpp - BPF 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 9*5f757f3fSDimitry Andric #include "MCTargetDesc/BPFMCFixups.h" 100b57cec5SDimitry Andric #include "MCTargetDesc/BPFMCTargetDesc.h" 110b57cec5SDimitry Andric #include "llvm/ADT/StringRef.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/MCFixup.h" 16*5f757f3fSDimitry Andric #include "llvm/MC/MCFixupKindInfo.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h" 180b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h" 190b57cec5SDimitry Andric #include <cassert> 200b57cec5SDimitry Andric #include <cstdint> 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric using namespace llvm; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace { 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric class BPFAsmBackend : public MCAsmBackend { 270b57cec5SDimitry Andric public: 28*5f757f3fSDimitry Andric BPFAsmBackend(llvm::endianness Endian) : MCAsmBackend(Endian) {} 290b57cec5SDimitry Andric ~BPFAsmBackend() override = default; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 320b57cec5SDimitry Andric const MCValue &Target, MutableArrayRef<char> Data, 330b57cec5SDimitry Andric uint64_t Value, bool IsResolved, 340b57cec5SDimitry Andric const MCSubtargetInfo *STI) const override; 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 370b57cec5SDimitry Andric createObjectTargetWriter() const override; 380b57cec5SDimitry Andric 39*5f757f3fSDimitry Andric unsigned getNumFixupKinds() const override { 40*5f757f3fSDimitry Andric return BPF::NumTargetFixupKinds; 41*5f757f3fSDimitry Andric } 42*5f757f3fSDimitry Andric const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; 430b57cec5SDimitry Andric 44349cc55cSDimitry Andric bool writeNopData(raw_ostream &OS, uint64_t Count, 45349cc55cSDimitry Andric const MCSubtargetInfo *STI) const override; 460b57cec5SDimitry Andric }; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric } // end anonymous namespace 490b57cec5SDimitry Andric 50*5f757f3fSDimitry Andric const MCFixupKindInfo & 51*5f757f3fSDimitry Andric BPFAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 52*5f757f3fSDimitry Andric const static MCFixupKindInfo Infos[BPF::NumTargetFixupKinds] = { 53*5f757f3fSDimitry Andric { "FK_BPF_PCRel_4", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, 54*5f757f3fSDimitry Andric }; 55*5f757f3fSDimitry Andric 56*5f757f3fSDimitry Andric if (Kind < FirstTargetFixupKind) 57*5f757f3fSDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind); 58*5f757f3fSDimitry Andric 59*5f757f3fSDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 60*5f757f3fSDimitry Andric "Invalid kind!"); 61*5f757f3fSDimitry Andric return Infos[Kind - FirstTargetFixupKind]; 62*5f757f3fSDimitry Andric } 63*5f757f3fSDimitry Andric 64349cc55cSDimitry Andric bool BPFAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 65349cc55cSDimitry Andric const MCSubtargetInfo *STI) const { 660b57cec5SDimitry Andric if ((Count % 8) != 0) 670b57cec5SDimitry Andric return false; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric for (uint64_t i = 0; i < Count; i += 8) 700b57cec5SDimitry Andric support::endian::write<uint64_t>(OS, 0x15000000, Endian); 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric return true; 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 760b57cec5SDimitry Andric const MCValue &Target, 770b57cec5SDimitry Andric MutableArrayRef<char> Data, uint64_t Value, 780b57cec5SDimitry Andric bool IsResolved, 790b57cec5SDimitry Andric const MCSubtargetInfo *STI) const { 80fe6060f1SDimitry Andric if (Fixup.getKind() == FK_SecRel_8) { 810b57cec5SDimitry Andric // The Value is 0 for global variables, and the in-section offset 820b57cec5SDimitry Andric // for static variables. Write to the immediate field of the inst. 830b57cec5SDimitry Andric assert(Value <= UINT32_MAX); 840b57cec5SDimitry Andric support::endian::write<uint32_t>(&Data[Fixup.getOffset() + 4], 850b57cec5SDimitry Andric static_cast<uint32_t>(Value), 860b57cec5SDimitry Andric Endian); 870b57cec5SDimitry Andric } else if (Fixup.getKind() == FK_Data_4) { 880b57cec5SDimitry Andric support::endian::write<uint32_t>(&Data[Fixup.getOffset()], Value, Endian); 890b57cec5SDimitry Andric } else if (Fixup.getKind() == FK_Data_8) { 900b57cec5SDimitry Andric support::endian::write<uint64_t>(&Data[Fixup.getOffset()], Value, Endian); 910b57cec5SDimitry Andric } else if (Fixup.getKind() == FK_PCRel_4) { 920b57cec5SDimitry Andric Value = (uint32_t)((Value - 8) / 8); 93*5f757f3fSDimitry Andric if (Endian == llvm::endianness::little) { 940b57cec5SDimitry Andric Data[Fixup.getOffset() + 1] = 0x10; 950b57cec5SDimitry Andric support::endian::write32le(&Data[Fixup.getOffset() + 4], Value); 960b57cec5SDimitry Andric } else { 970b57cec5SDimitry Andric Data[Fixup.getOffset() + 1] = 0x1; 980b57cec5SDimitry Andric support::endian::write32be(&Data[Fixup.getOffset() + 4], Value); 990b57cec5SDimitry Andric } 100*5f757f3fSDimitry Andric } else if (Fixup.getTargetKind() == BPF::FK_BPF_PCRel_4) { 101*5f757f3fSDimitry Andric // The input Value represents the number of bytes. 102*5f757f3fSDimitry Andric Value = (uint32_t)((Value - 8) / 8); 103*5f757f3fSDimitry Andric support::endian::write<uint32_t>(&Data[Fixup.getOffset() + 4], Value, 104*5f757f3fSDimitry Andric Endian); 1050b57cec5SDimitry Andric } else { 1060b57cec5SDimitry Andric assert(Fixup.getKind() == FK_PCRel_2); 10781ad6265SDimitry Andric 10881ad6265SDimitry Andric int64_t ByteOff = (int64_t)Value - 8; 10981ad6265SDimitry Andric if (ByteOff > INT16_MAX * 8 || ByteOff < INT16_MIN * 8) 11081ad6265SDimitry Andric report_fatal_error("Branch target out of insn range"); 11181ad6265SDimitry Andric 1120b57cec5SDimitry Andric Value = (uint16_t)((Value - 8) / 8); 1130b57cec5SDimitry Andric support::endian::write<uint16_t>(&Data[Fixup.getOffset() + 2], Value, 1140b57cec5SDimitry Andric Endian); 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter> 1190b57cec5SDimitry Andric BPFAsmBackend::createObjectTargetWriter() const { 1200b57cec5SDimitry Andric return createBPFELFObjectWriter(0); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric MCAsmBackend *llvm::createBPFAsmBackend(const Target &T, 1240b57cec5SDimitry Andric const MCSubtargetInfo &STI, 1250b57cec5SDimitry Andric const MCRegisterInfo &MRI, 1260b57cec5SDimitry Andric const MCTargetOptions &) { 127*5f757f3fSDimitry Andric return new BPFAsmBackend(llvm::endianness::little); 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric MCAsmBackend *llvm::createBPFbeAsmBackend(const Target &T, 1310b57cec5SDimitry Andric const MCSubtargetInfo &STI, 1320b57cec5SDimitry Andric const MCRegisterInfo &MRI, 1330b57cec5SDimitry Andric const MCTargetOptions &) { 134*5f757f3fSDimitry Andric return new BPFAsmBackend(llvm::endianness::big); 1350b57cec5SDimitry Andric } 136