1 //===-- BPFAsmBackend.cpp - BPF Assembler Backend -------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "MCTargetDesc/BPFMCFixups.h" 10 #include "MCTargetDesc/BPFMCTargetDesc.h" 11 #include "llvm/MC/MCAsmBackend.h" 12 #include "llvm/MC/MCAssembler.h" 13 #include "llvm/MC/MCContext.h" 14 #include "llvm/MC/MCFixup.h" 15 #include "llvm/MC/MCFixupKindInfo.h" 16 #include "llvm/MC/MCObjectWriter.h" 17 #include "llvm/Support/EndianStream.h" 18 #include <cassert> 19 #include <cstdint> 20 21 using namespace llvm; 22 23 namespace { 24 25 class BPFAsmBackend : public MCAsmBackend { 26 public: 27 BPFAsmBackend(llvm::endianness Endian) : MCAsmBackend(Endian) {} 28 ~BPFAsmBackend() override = default; 29 30 void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 31 const MCValue &Target, MutableArrayRef<char> Data, 32 uint64_t Value, bool IsResolved, 33 const MCSubtargetInfo *STI) const override; 34 35 std::unique_ptr<MCObjectTargetWriter> 36 createObjectTargetWriter() const override; 37 38 unsigned getNumFixupKinds() const override { 39 return BPF::NumTargetFixupKinds; 40 } 41 const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; 42 43 bool writeNopData(raw_ostream &OS, uint64_t Count, 44 const MCSubtargetInfo *STI) const override; 45 }; 46 47 } // end anonymous namespace 48 49 const MCFixupKindInfo & 50 BPFAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 51 const static MCFixupKindInfo Infos[BPF::NumTargetFixupKinds] = { 52 { "FK_BPF_PCRel_4", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, 53 }; 54 55 if (Kind < FirstTargetFixupKind) 56 return MCAsmBackend::getFixupKindInfo(Kind); 57 58 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 59 "Invalid kind!"); 60 return Infos[Kind - FirstTargetFixupKind]; 61 } 62 63 bool BPFAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 64 const MCSubtargetInfo *STI) const { 65 if ((Count % 8) != 0) 66 return false; 67 68 for (uint64_t i = 0; i < Count; i += 8) 69 support::endian::write<uint64_t>(OS, 0x15000000, Endian); 70 71 return true; 72 } 73 74 void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 75 const MCValue &Target, 76 MutableArrayRef<char> Data, uint64_t Value, 77 bool IsResolved, 78 const MCSubtargetInfo *STI) const { 79 if (Fixup.getKind() == FK_SecRel_8) { 80 // The Value is 0 for global variables, and the in-section offset 81 // for static variables. Write to the immediate field of the inst. 82 assert(Value <= UINT32_MAX); 83 support::endian::write<uint32_t>(&Data[Fixup.getOffset() + 4], 84 static_cast<uint32_t>(Value), 85 Endian); 86 } else if (Fixup.getKind() == FK_Data_4) { 87 support::endian::write<uint32_t>(&Data[Fixup.getOffset()], Value, Endian); 88 } else if (Fixup.getKind() == FK_Data_8) { 89 support::endian::write<uint64_t>(&Data[Fixup.getOffset()], Value, Endian); 90 } else if (Fixup.getKind() == FK_PCRel_4) { 91 Value = (uint32_t)((Value - 8) / 8); 92 if (Endian == llvm::endianness::little) { 93 Data[Fixup.getOffset() + 1] = 0x10; 94 support::endian::write32le(&Data[Fixup.getOffset() + 4], Value); 95 } else { 96 Data[Fixup.getOffset() + 1] = 0x1; 97 support::endian::write32be(&Data[Fixup.getOffset() + 4], Value); 98 } 99 } else if (Fixup.getTargetKind() == BPF::FK_BPF_PCRel_4) { 100 // The input Value represents the number of bytes. 101 Value = (uint32_t)((Value - 8) / 8); 102 support::endian::write<uint32_t>(&Data[Fixup.getOffset() + 4], Value, 103 Endian); 104 } else { 105 assert(Fixup.getKind() == FK_PCRel_2); 106 107 int64_t ByteOff = (int64_t)Value - 8; 108 if (ByteOff > INT16_MAX * 8 || ByteOff < INT16_MIN * 8) 109 report_fatal_error("Branch target out of insn range"); 110 111 Value = (uint16_t)((Value - 8) / 8); 112 support::endian::write<uint16_t>(&Data[Fixup.getOffset() + 2], Value, 113 Endian); 114 } 115 } 116 117 std::unique_ptr<MCObjectTargetWriter> 118 BPFAsmBackend::createObjectTargetWriter() const { 119 return createBPFELFObjectWriter(0); 120 } 121 122 MCAsmBackend *llvm::createBPFAsmBackend(const Target &T, 123 const MCSubtargetInfo &STI, 124 const MCRegisterInfo &MRI, 125 const MCTargetOptions &) { 126 return new BPFAsmBackend(llvm::endianness::little); 127 } 128 129 MCAsmBackend *llvm::createBPFbeAsmBackend(const Target &T, 130 const MCSubtargetInfo &STI, 131 const MCRegisterInfo &MRI, 132 const MCTargetOptions &) { 133 return new BPFAsmBackend(llvm::endianness::big); 134 } 135