1e4c8c807SAlexei Starovoitov //===-- BPFELFObjectWriter.cpp - BPF ELF Writer ---------------------------===//
2e4c8c807SAlexei Starovoitov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e4c8c807SAlexei Starovoitov //
7e4c8c807SAlexei Starovoitov //===----------------------------------------------------------------------===//
8e4c8c807SAlexei Starovoitov 
9e4c8c807SAlexei Starovoitov #include "MCTargetDesc/BPFMCTargetDesc.h"
10264b5d9eSZachary Turner #include "llvm/BinaryFormat/ELF.h"
11e4c8c807SAlexei Starovoitov #include "llvm/MC/MCELFObjectWriter.h"
12e4c8c807SAlexei Starovoitov #include "llvm/MC/MCFixup.h"
1360fbc7ccSLang Hames #include "llvm/MC/MCObjectWriter.h"
14821c93d5SYonghong Song #include "llvm/MC/MCValue.h"
15e4c8c807SAlexei Starovoitov #include "llvm/Support/ErrorHandling.h"
164282c404SEugene Zelenko #include <cstdint>
17e4c8c807SAlexei Starovoitov 
18e4c8c807SAlexei Starovoitov using namespace llvm;
19e4c8c807SAlexei Starovoitov 
20e4c8c807SAlexei Starovoitov namespace {
214282c404SEugene Zelenko 
22e4c8c807SAlexei Starovoitov class BPFELFObjectWriter : public MCELFObjectTargetWriter {
23e4c8c807SAlexei Starovoitov public:
24e4c8c807SAlexei Starovoitov   BPFELFObjectWriter(uint8_t OSABI);
254282c404SEugene Zelenko   ~BPFELFObjectWriter() override = default;
26e4c8c807SAlexei Starovoitov 
27e4c8c807SAlexei Starovoitov protected:
288340f94dSRafael Espindola   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
298340f94dSRafael Espindola                         const MCFixup &Fixup, bool IsPCRel) const override;
30e4c8c807SAlexei Starovoitov };
314282c404SEugene Zelenko 
324282c404SEugene Zelenko } // end anonymous namespace
33e4c8c807SAlexei Starovoitov 
BPFELFObjectWriter(uint8_t OSABI)34e4c8c807SAlexei Starovoitov BPFELFObjectWriter::BPFELFObjectWriter(uint8_t OSABI)
35cfb51f54SAlexei Starovoitov     : MCELFObjectTargetWriter(/*Is64Bit*/ true, OSABI, ELF::EM_BPF,
36e4c8c807SAlexei Starovoitov                               /*HasRelocationAddend*/ false) {}
37e4c8c807SAlexei Starovoitov 
getRelocType(MCContext & Ctx,const MCValue & Target,const MCFixup & Fixup,bool IsPCRel) const388340f94dSRafael Espindola unsigned BPFELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
39e4c8c807SAlexei Starovoitov                                           const MCFixup &Fixup,
40e4c8c807SAlexei Starovoitov                                           bool IsPCRel) const {
41e4c8c807SAlexei Starovoitov   // determine the type of the relocation
4290b6bb75SSam Clegg   switch (Fixup.getKind()) {
43e4c8c807SAlexei Starovoitov   default:
44e4c8c807SAlexei Starovoitov     llvm_unreachable("invalid fixup kind!");
45e4c8c807SAlexei Starovoitov   case FK_SecRel_8:
46*6a2ea846SYonghong Song     // LD_imm64 instruction.
477ab125dbSAlexei Starovoitov     return ELF::R_BPF_64_64;
489a67245dSAlexei Starovoitov   case FK_PCRel_4:
49*6a2ea846SYonghong Song     // CALL instruction.
507ab125dbSAlexei Starovoitov     return ELF::R_BPF_64_32;
5101886a05SAlexei Starovoitov   case FK_Data_8:
52*6a2ea846SYonghong Song     return ELF::R_BPF_64_ABS64;
5301886a05SAlexei Starovoitov   case FK_Data_4:
54e698958aSYonghong Song     if (const MCSymbolRefExpr *A = Target.getSymA()) {
55e698958aSYonghong Song       const MCSymbol &Sym = A->getSymbol();
56e698958aSYonghong Song 
57e698958aSYonghong Song       if (Sym.isDefined()) {
58e698958aSYonghong Song         MCSection &Section = Sym.getSection();
59e698958aSYonghong Song         const MCSectionELF *SectionELF = dyn_cast<MCSectionELF>(&Section);
60e698958aSYonghong Song         assert(SectionELF && "Null section for reloc symbol");
61e698958aSYonghong Song 
62e698958aSYonghong Song         unsigned Flags = SectionELF->getFlags();
63e698958aSYonghong Song 
64e698958aSYonghong Song         if (Sym.isTemporary()) {
65821c93d5SYonghong Song           // .BTF.ext generates FK_Data_4 relocations for
66821c93d5SYonghong Song           // insn offset by creating temporary labels.
670d99031dSYonghong Song           // The reloc symbol should be in text section.
68*6a2ea846SYonghong Song           // Use a different relocation to instruct ExecutionEngine
69*6a2ea846SYonghong Song           // RuntimeDyld not to do relocation for it, yet still to
70*6a2ea846SYonghong Song           // allow lld to do proper adjustment when merging sections.
710d99031dSYonghong Song           if ((Flags & ELF::SHF_ALLOC) && (Flags & ELF::SHF_EXECINSTR))
72*6a2ea846SYonghong Song             return ELF::R_BPF_64_NODYLD32;
73e698958aSYonghong Song         } else {
74e698958aSYonghong Song           // .BTF generates FK_Data_4 relocations for variable
75*6a2ea846SYonghong Song           // offset in DataSec kind.
76e698958aSYonghong Song           // The reloc symbol should be in data section.
77e698958aSYonghong Song           if ((Flags & ELF::SHF_ALLOC) && (Flags & ELF::SHF_WRITE))
78*6a2ea846SYonghong Song             return ELF::R_BPF_64_NODYLD32;
79e698958aSYonghong Song         }
80821c93d5SYonghong Song       }
810d99031dSYonghong Song     }
82*6a2ea846SYonghong Song     return ELF::R_BPF_64_ABS32;
83e4c8c807SAlexei Starovoitov   }
84e4c8c807SAlexei Starovoitov }
85e4c8c807SAlexei Starovoitov 
86dcd7d6c3SPeter Collingbourne std::unique_ptr<MCObjectTargetWriter>
createBPFELFObjectWriter(uint8_t OSABI)87dcd7d6c3SPeter Collingbourne llvm::createBPFELFObjectWriter(uint8_t OSABI) {
880eaee545SJonas Devlieghere   return std::make_unique<BPFELFObjectWriter>(OSABI);
89e4c8c807SAlexei Starovoitov }
90