1 //===-- BPFAsmBackend.cpp - BPF Assembler Backend -------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "MCTargetDesc/BPFMCTargetDesc.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/MC/MCAsmBackend.h"
13 #include "llvm/MC/MCFixup.h"
14 #include "llvm/MC/MCObjectWriter.h"
15 #include "llvm/Support/EndianStream.h"
16 #include <cassert>
17 #include <cstdint>
18 
19 using namespace llvm;
20 
21 namespace {
22 
23 class BPFAsmBackend : public MCAsmBackend {
24 public:
25   BPFAsmBackend(support::endianness Endian) : MCAsmBackend(Endian) {}
26   ~BPFAsmBackend() override = default;
27 
28   void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
29                   const MCValue &Target, MutableArrayRef<char> Data,
30                   uint64_t Value, bool IsResolved,
31                   const MCSubtargetInfo *STI) const override;
32 
33   std::unique_ptr<MCObjectTargetWriter>
34   createObjectTargetWriter() const override;
35 
36   // No instruction requires relaxation
37   bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
38                             const MCRelaxableFragment *DF,
39                             const MCAsmLayout &Layout) const override {
40     return false;
41   }
42 
43   unsigned getNumFixupKinds() const override { return 1; }
44 
45   bool mayNeedRelaxation(const MCInst &Inst,
46                          const MCSubtargetInfo &STI) const override {
47     return false;
48   }
49 
50   void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
51                         MCInst &Res) const override {}
52 
53   bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
54 };
55 
56 } // end anonymous namespace
57 
58 bool BPFAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
59   if ((Count % 8) != 0)
60     return false;
61 
62   for (uint64_t i = 0; i < Count; i += 8)
63     support::endian::write<uint64_t>(OS, 0x15000000, Endian);
64 
65   return true;
66 }
67 
68 void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
69                                const MCValue &Target,
70                                MutableArrayRef<char> Data, uint64_t Value,
71                                bool IsResolved,
72                                const MCSubtargetInfo *STI) const {
73   if (Fixup.getKind() == FK_SecRel_4 || Fixup.getKind() == FK_SecRel_8) {
74     assert(Value == 0);
75   } else if (Fixup.getKind() == FK_Data_4) {
76     support::endian::write<uint32_t>(&Data[Fixup.getOffset()], Value, Endian);
77   } else if (Fixup.getKind() == FK_Data_8) {
78     support::endian::write<uint64_t>(&Data[Fixup.getOffset()], Value, Endian);
79   } else if (Fixup.getKind() == FK_PCRel_4) {
80     Value = (uint32_t)((Value - 8) / 8);
81     if (Endian == support::little) {
82       Data[Fixup.getOffset() + 1] = 0x10;
83       support::endian::write32le(&Data[Fixup.getOffset() + 4], Value);
84     } else {
85       Data[Fixup.getOffset() + 1] = 0x1;
86       support::endian::write32be(&Data[Fixup.getOffset() + 4], Value);
87     }
88   } else {
89     assert(Fixup.getKind() == FK_PCRel_2);
90     Value = (uint16_t)((Value - 8) / 8);
91     support::endian::write<uint16_t>(&Data[Fixup.getOffset() + 2], Value,
92                                      Endian);
93   }
94 }
95 
96 std::unique_ptr<MCObjectTargetWriter>
97 BPFAsmBackend::createObjectTargetWriter() const {
98   return createBPFELFObjectWriter(0);
99 }
100 
101 MCAsmBackend *llvm::createBPFAsmBackend(const Target &T,
102                                         const MCSubtargetInfo &STI,
103                                         const MCRegisterInfo &MRI,
104                                         const MCTargetOptions &) {
105   return new BPFAsmBackend(support::little);
106 }
107 
108 MCAsmBackend *llvm::createBPFbeAsmBackend(const Target &T,
109                                           const MCSubtargetInfo &STI,
110                                           const MCRegisterInfo &MRI,
111                                           const MCTargetOptions &) {
112   return new BPFAsmBackend(support::big);
113 }
114