xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/MCObjectWriter.h"
16 #include "llvm/Support/EndianStream.h"
17 #include <cassert>
18 #include <cstdint>
19 
20 using namespace llvm;
21 
22 namespace {
23 
24 class BPFAsmBackend : public MCAsmBackend {
25 public:
BPFAsmBackend(llvm::endianness Endian)26   BPFAsmBackend(llvm::endianness Endian) : MCAsmBackend(Endian) {}
27   ~BPFAsmBackend() override = default;
28 
29   void applyFixup(const MCFragment &, const MCFixup &, const MCValue &Target,
30                   MutableArrayRef<char> Data, uint64_t Value,
31                   bool IsResolved) override;
32 
33   std::unique_ptr<MCObjectTargetWriter>
34   createObjectTargetWriter() const override;
35 
36   MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;
37 
38   bool writeNopData(raw_ostream &OS, uint64_t Count,
39                     const MCSubtargetInfo *STI) const override;
40 };
41 
42 } // end anonymous namespace
43 
getFixupKindInfo(MCFixupKind Kind) const44 MCFixupKindInfo BPFAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
45   const static MCFixupKindInfo Infos[BPF::NumTargetFixupKinds] = {
46       {"FK_BPF_PCRel_4", 0, 32, 0},
47   };
48 
49   if (Kind < FirstTargetFixupKind)
50     return MCAsmBackend::getFixupKindInfo(Kind);
51 
52   assert(unsigned(Kind - FirstTargetFixupKind) < BPF::NumTargetFixupKinds &&
53          "Invalid kind!");
54   return Infos[Kind - FirstTargetFixupKind];
55 }
56 
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const57 bool BPFAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
58                                  const MCSubtargetInfo *STI) 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 
applyFixup(const MCFragment & F,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved)68 void BPFAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
69                                const MCValue &Target,
70                                MutableArrayRef<char> Data, uint64_t Value,
71                                bool IsResolved) {
72   maybeAddReloc(F, Fixup, Target, Value, IsResolved);
73   if (Fixup.getKind() == FK_SecRel_8) {
74     // The Value is 0 for global variables, and the in-section offset
75     // for static variables. Write to the immediate field of the inst.
76     assert(Value <= UINT32_MAX);
77     support::endian::write<uint32_t>(&Data[Fixup.getOffset() + 4],
78                                      static_cast<uint32_t>(Value),
79                                      Endian);
80   } else if (Fixup.getKind() == FK_Data_4 && !Fixup.isPCRel()) {
81     support::endian::write<uint32_t>(&Data[Fixup.getOffset()], Value, Endian);
82   } else if (Fixup.getKind() == FK_Data_8) {
83     support::endian::write<uint64_t>(&Data[Fixup.getOffset()], Value, Endian);
84   } else if (Fixup.getKind() == FK_Data_4 && Fixup.isPCRel()) {
85     Value = (uint32_t)((Value - 8) / 8);
86     if (Endian == llvm::endianness::little) {
87       Data[Fixup.getOffset() + 1] = 0x10;
88       support::endian::write32le(&Data[Fixup.getOffset() + 4], Value);
89     } else {
90       Data[Fixup.getOffset() + 1] = 0x1;
91       support::endian::write32be(&Data[Fixup.getOffset() + 4], Value);
92     }
93   } else if (Fixup.getKind() == BPF::FK_BPF_PCRel_4) {
94     // The input Value represents the number of bytes.
95     Value = (uint32_t)((Value - 8) / 8);
96     support::endian::write<uint32_t>(&Data[Fixup.getOffset() + 4], Value,
97                                      Endian);
98   } else {
99     assert(Fixup.getKind() == FK_Data_2 && Fixup.isPCRel());
100 
101     int64_t ByteOff = (int64_t)Value - 8;
102     if (ByteOff > INT16_MAX * 8 || ByteOff < INT16_MIN * 8)
103       report_fatal_error("Branch target out of insn range");
104 
105     Value = (uint16_t)((Value - 8) / 8);
106     support::endian::write<uint16_t>(&Data[Fixup.getOffset() + 2], Value,
107                                      Endian);
108   }
109 }
110 
111 std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const112 BPFAsmBackend::createObjectTargetWriter() const {
113   return createBPFELFObjectWriter(0);
114 }
115 
createBPFAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions &)116 MCAsmBackend *llvm::createBPFAsmBackend(const Target &T,
117                                         const MCSubtargetInfo &STI,
118                                         const MCRegisterInfo &MRI,
119                                         const MCTargetOptions &) {
120   return new BPFAsmBackend(llvm::endianness::little);
121 }
122 
createBPFbeAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions &)123 MCAsmBackend *llvm::createBPFbeAsmBackend(const Target &T,
124                                           const MCSubtargetInfo &STI,
125                                           const MCRegisterInfo &MRI,
126                                           const MCTargetOptions &) {
127   return new BPFAsmBackend(llvm::endianness::big);
128 }
129