1321369Sdim//===- llvm/MC/MCELFObjectWriter.h - ELF Object Writer ----------*- C++ -*-===//
2218885Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6218885Sdim//
7218885Sdim//===----------------------------------------------------------------------===//
8218885Sdim
9218885Sdim#ifndef LLVM_MC_MCELFOBJECTWRITER_H
10218885Sdim#define LLVM_MC_MCELFOBJECTWRITER_H
11218885Sdim
12234353Sdim#include "llvm/ADT/Triple.h"
13321369Sdim#include "llvm/BinaryFormat/ELF.h"
14341825Sdim#include "llvm/MC/MCObjectWriter.h"
15344779Sdim#include "llvm/MC/MCSectionELF.h"
16321369Sdim#include "llvm/Support/Casting.h"
17309124Sdim#include "llvm/Support/raw_ostream.h"
18321369Sdim#include <cstdint>
19234353Sdim#include <vector>
20218885Sdim
21218885Sdimnamespace llvm {
22321369Sdim
23234353Sdimclass MCAssembler;
24309124Sdimclass MCContext;
25234353Sdimclass MCFixup;
26234353Sdimclass MCObjectWriter;
27234353Sdimclass MCSymbol;
28288943Sdimclass MCSymbolELF;
29234353Sdimclass MCValue;
30234353Sdim
31288943Sdimstruct ELFRelocationEntry {
32288943Sdim  uint64_t Offset; // Where is the relocation.
33288943Sdim  const MCSymbolELF *Symbol; // The symbol to relocate with.
34288943Sdim  unsigned Type;   // The type of the relocation.
35288943Sdim  uint64_t Addend; // The addend to use.
36309124Sdim  const MCSymbolELF *OriginalSymbol; // The original value of Symbol if we changed it.
37309124Sdim  uint64_t OriginalAddend; // The original value of addend.
38288943Sdim
39288943Sdim  ELFRelocationEntry(uint64_t Offset, const MCSymbolELF *Symbol, unsigned Type,
40309124Sdim                     uint64_t Addend, const MCSymbolELF *OriginalSymbol,
41309124Sdim                     uint64_t OriginalAddend)
42309124Sdim      : Offset(Offset), Symbol(Symbol), Type(Type), Addend(Addend),
43309124Sdim        OriginalSymbol(OriginalSymbol), OriginalAddend(OriginalAddend) {}
44309124Sdim
45309124Sdim  void print(raw_ostream &Out) const {
46309124Sdim    Out << "Off=" << Offset << ", Sym=" << Symbol << ", Type=" << Type
47309124Sdim        << ", Addend=" << Addend << ", OriginalSymbol=" << OriginalSymbol
48309124Sdim        << ", OriginalAddend=" << OriginalAddend;
49309124Sdim  }
50321369Sdim
51309124Sdim  void dump() const { print(errs()); }
52288943Sdim};
53288943Sdim
54341825Sdimclass MCELFObjectTargetWriter : public MCObjectTargetWriter {
55234353Sdim  const uint8_t OSABI;
56353358Sdim  const uint8_t ABIVersion;
57218885Sdim  const uint16_t EMachine;
58218885Sdim  const unsigned HasRelocationAddend : 1;
59218885Sdim  const unsigned Is64Bit : 1;
60234353Sdim
61218885Sdimprotected:
62321369Sdim  MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_, uint16_t EMachine_,
63353358Sdim                          bool HasRelocationAddend_, uint8_t ABIVersion_ = 0);
64234353Sdim
65321369Sdimpublic:
66321369Sdim  virtual ~MCELFObjectTargetWriter() = default;
67218885Sdim
68341825Sdim  virtual Triple::ObjectFormatType getFormat() const { return Triple::ELF; }
69341825Sdim  static bool classof(const MCObjectTargetWriter *W) {
70341825Sdim    return W->getFormat() == Triple::ELF;
71341825Sdim  }
72341825Sdim
73234353Sdim  static uint8_t getOSABI(Triple::OSType OSType) {
74234353Sdim    switch (OSType) {
75288943Sdim      case Triple::CloudABI:
76288943Sdim        return ELF::ELFOSABI_CLOUDABI;
77344779Sdim      case Triple::HermitCore:
78344779Sdim        return ELF::ELFOSABI_STANDALONE;
79288943Sdim      case Triple::PS4:
80234353Sdim      case Triple::FreeBSD:
81234353Sdim        return ELF::ELFOSABI_FREEBSD;
82234353Sdim      default:
83234353Sdim        return ELF::ELFOSABI_NONE;
84234353Sdim    }
85234353Sdim  }
86218885Sdim
87309124Sdim  virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
88309124Sdim                                const MCFixup &Fixup, bool IsPCRel) const = 0;
89234353Sdim
90288943Sdim  virtual bool needsRelocateWithSymbol(const MCSymbol &Sym,
91276479Sdim                                       unsigned Type) const;
92234353Sdim
93288943Sdim  virtual void sortRelocs(const MCAssembler &Asm,
94288943Sdim                          std::vector<ELFRelocationEntry> &Relocs);
95288943Sdim
96344779Sdim  virtual void addTargetSectionFlags(MCContext &Ctx, MCSectionELF &Sec);
97344779Sdim
98288943Sdim  /// \name Accessors
99218885Sdim  /// @{
100243830Sdim  uint8_t getOSABI() const { return OSABI; }
101353358Sdim  uint8_t getABIVersion() const { return ABIVersion; }
102243830Sdim  uint16_t getEMachine() const { return EMachine; }
103243830Sdim  bool hasRelocationAddend() const { return HasRelocationAddend; }
104234353Sdim  bool is64Bit() const { return Is64Bit; }
105218885Sdim  /// @}
106239462Sdim
107239462Sdim  // Instead of changing everyone's API we pack the N64 Type fields
108239462Sdim  // into the existing 32 bit data unsigned.
109239462Sdim#define R_TYPE_SHIFT 0
110239462Sdim#define R_TYPE_MASK 0xffffff00
111239462Sdim#define R_TYPE2_SHIFT 8
112239462Sdim#define R_TYPE2_MASK 0xffff00ff
113239462Sdim#define R_TYPE3_SHIFT 16
114239462Sdim#define R_TYPE3_MASK 0xff00ffff
115239462Sdim#define R_SSYM_SHIFT 24
116239462Sdim#define R_SSYM_MASK 0x00ffffff
117239462Sdim
118239462Sdim  // N64 relocation type accessors
119276479Sdim  uint8_t getRType(uint32_t Type) const {
120239462Sdim    return (unsigned)((Type >> R_TYPE_SHIFT) & 0xff);
121239462Sdim  }
122276479Sdim  uint8_t getRType2(uint32_t Type) const {
123239462Sdim    return (unsigned)((Type >> R_TYPE2_SHIFT) & 0xff);
124239462Sdim  }
125276479Sdim  uint8_t getRType3(uint32_t Type) const {
126239462Sdim    return (unsigned)((Type >> R_TYPE3_SHIFT) & 0xff);
127239462Sdim  }
128276479Sdim  uint8_t getRSsym(uint32_t Type) const {
129239462Sdim    return (unsigned)((Type >> R_SSYM_SHIFT) & 0xff);
130239462Sdim  }
131239462Sdim
132239462Sdim  // N64 relocation type setting
133239462Sdim  unsigned setRType(unsigned Value, unsigned Type) const {
134239462Sdim    return ((Type & R_TYPE_MASK) | ((Value & 0xff) << R_TYPE_SHIFT));
135239462Sdim  }
136239462Sdim  unsigned setRType2(unsigned Value, unsigned Type) const {
137239462Sdim    return (Type & R_TYPE2_MASK) | ((Value & 0xff) << R_TYPE2_SHIFT);
138239462Sdim  }
139239462Sdim  unsigned setRType3(unsigned Value, unsigned Type) const {
140239462Sdim    return (Type & R_TYPE3_MASK) | ((Value & 0xff) << R_TYPE3_SHIFT);
141239462Sdim  }
142239462Sdim  unsigned setRSsym(unsigned Value, unsigned Type) const {
143239462Sdim    return (Type & R_SSYM_MASK) | ((Value & 0xff) << R_SSYM_SHIFT);
144239462Sdim  }
145218885Sdim};
146218885Sdim
147341825Sdim/// Construct a new ELF writer instance.
148218885Sdim///
149218885Sdim/// \param MOTW - The target specific ELF writer subclass.
150218885Sdim/// \param OS - The stream to write to.
151218885Sdim/// \returns The constructed object writer.
152327952Sdimstd::unique_ptr<MCObjectWriter>
153327952SdimcreateELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
154327952Sdim                      raw_pwrite_stream &OS, bool IsLittleEndian);
155218885Sdim
156341825Sdimstd::unique_ptr<MCObjectWriter>
157341825SdimcreateELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
158341825Sdim                         raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS,
159341825Sdim                         bool IsLittleEndian);
160341825Sdim
161321369Sdim} // end namespace llvm
162321369Sdim
163321369Sdim#endif // LLVM_MC_MCELFOBJECTWRITER_H
164