xref: /freebsd/contrib/llvm-project/llvm/include/llvm/MC/MCELFObjectWriter.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===- llvm/MC/MCELFObjectWriter.h - ELF Object Writer ----------*- C++ -*-===//
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 #ifndef LLVM_MC_MCELFOBJECTWRITER_H
10 #define LLVM_MC_MCELFOBJECTWRITER_H
11 
12 #include "llvm/ADT/DenseMap.h"
13 #include "llvm/ADT/SmallVector.h"
14 #include "llvm/BinaryFormat/ELF.h"
15 #include "llvm/MC/MCObjectWriter.h"
16 #include "llvm/MC/MCSectionELF.h"
17 #include "llvm/Support/Casting.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include "llvm/TargetParser/Triple.h"
20 #include <cstdint>
21 #include <memory>
22 #include <optional>
23 #include <vector>
24 
25 namespace llvm {
26 
27 class MCAssembler;
28 class MCContext;
29 class MCFixup;
30 class MCSymbol;
31 class MCSymbolELF;
32 class MCTargetOptions;
33 class MCValue;
34 
35 struct ELFRelocationEntry {
36   uint64_t Offset; // Where is the relocation.
37   const MCSymbolELF *Symbol; // The symbol to relocate with.
38   unsigned Type;   // The type of the relocation.
39   uint64_t Addend; // The addend to use.
40   const MCSymbolELF *OriginalSymbol; // The original value of Symbol if we changed it.
41   uint64_t OriginalAddend; // The original value of addend.
42 
ELFRelocationEntryELFRelocationEntry43   ELFRelocationEntry(uint64_t Offset, const MCSymbolELF *Symbol, unsigned Type,
44                      uint64_t Addend, const MCSymbolELF *OriginalSymbol,
45                      uint64_t OriginalAddend)
46       : Offset(Offset), Symbol(Symbol), Type(Type), Addend(Addend),
47         OriginalSymbol(OriginalSymbol), OriginalAddend(OriginalAddend) {}
48 
printELFRelocationEntry49   void print(raw_ostream &Out) const {
50     Out << "Off=" << Offset << ", Sym=" << Symbol << ", Type=" << Type
51         << ", Addend=" << Addend << ", OriginalSymbol=" << OriginalSymbol
52         << ", OriginalAddend=" << OriginalAddend;
53   }
54 
dumpELFRelocationEntry55   LLVM_DUMP_METHOD void dump() const { print(errs()); }
56 };
57 
58 class MCELFObjectTargetWriter : public MCObjectTargetWriter {
59   const uint8_t OSABI;
60   const uint8_t ABIVersion;
61   const uint16_t EMachine;
62   const unsigned HasRelocationAddend : 1;
63   const unsigned Is64Bit : 1;
64 
65 protected:
66   MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_, uint16_t EMachine_,
67                           bool HasRelocationAddend_, uint8_t ABIVersion_ = 0);
68 
69 public:
70   virtual ~MCELFObjectTargetWriter() = default;
71 
getFormat()72   Triple::ObjectFormatType getFormat() const override { return Triple::ELF; }
classof(const MCObjectTargetWriter * W)73   static bool classof(const MCObjectTargetWriter *W) {
74     return W->getFormat() == Triple::ELF;
75   }
76 
getOSABI(Triple::OSType OSType)77   static uint8_t getOSABI(Triple::OSType OSType) {
78     switch (OSType) {
79       case Triple::HermitCore:
80         return ELF::ELFOSABI_STANDALONE;
81       case Triple::PS4:
82       case Triple::FreeBSD:
83         return ELF::ELFOSABI_FREEBSD;
84       case Triple::Solaris:
85         return ELF::ELFOSABI_SOLARIS;
86       case Triple::OpenBSD:
87         return ELF::ELFOSABI_OPENBSD;
88       default:
89         return ELF::ELFOSABI_NONE;
90     }
91   }
92 
93   virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
94                                 const MCFixup &Fixup, bool IsPCRel) const = 0;
95 
96   virtual bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym,
97                                        unsigned Type) const;
98 
99   virtual void sortRelocs(const MCAssembler &Asm,
100                           std::vector<ELFRelocationEntry> &Relocs);
101 
102   virtual void addTargetSectionFlags(MCContext &Ctx, MCSectionELF &Sec);
103 
104   /// \name Accessors
105   /// @{
getOSABI()106   uint8_t getOSABI() const { return OSABI; }
getABIVersion()107   uint8_t getABIVersion() const { return ABIVersion; }
getEMachine()108   uint16_t getEMachine() const { return EMachine; }
hasRelocationAddend()109   bool hasRelocationAddend() const { return HasRelocationAddend; }
is64Bit()110   bool is64Bit() const { return Is64Bit; }
111   /// @}
112 
113   // Instead of changing everyone's API we pack the N64 Type fields
114   // into the existing 32 bit data unsigned.
115 #define R_TYPE_SHIFT 0
116 #define R_TYPE_MASK 0xffffff00
117 #define R_TYPE2_SHIFT 8
118 #define R_TYPE2_MASK 0xffff00ff
119 #define R_TYPE3_SHIFT 16
120 #define R_TYPE3_MASK 0xff00ffff
121 #define R_SSYM_SHIFT 24
122 #define R_SSYM_MASK 0x00ffffff
123 
124   // N64 relocation type accessors
getRType(uint32_t Type)125   uint8_t getRType(uint32_t Type) const {
126     return (unsigned)((Type >> R_TYPE_SHIFT) & 0xff);
127   }
getRType2(uint32_t Type)128   uint8_t getRType2(uint32_t Type) const {
129     return (unsigned)((Type >> R_TYPE2_SHIFT) & 0xff);
130   }
getRType3(uint32_t Type)131   uint8_t getRType3(uint32_t Type) const {
132     return (unsigned)((Type >> R_TYPE3_SHIFT) & 0xff);
133   }
getRSsym(uint32_t Type)134   uint8_t getRSsym(uint32_t Type) const {
135     return (unsigned)((Type >> R_SSYM_SHIFT) & 0xff);
136   }
137 
138   // N64 relocation type setting
setRTypes(unsigned Value1,unsigned Value2,unsigned Value3)139   static unsigned setRTypes(unsigned Value1, unsigned Value2, unsigned Value3) {
140     return ((Value1 & 0xff) << R_TYPE_SHIFT) |
141            ((Value2 & 0xff) << R_TYPE2_SHIFT) |
142            ((Value3 & 0xff) << R_TYPE3_SHIFT);
143   }
setRSsym(unsigned Value,unsigned Type)144   unsigned setRSsym(unsigned Value, unsigned Type) const {
145     return (Type & R_SSYM_MASK) | ((Value & 0xff) << R_SSYM_SHIFT);
146   }
147 
148   // On AArch64, return a new section to be added to the ELF object that
149   // contains relocations used to describe every symbol that should have memory
150   // tags applied. Returns nullptr if no such section is necessary (i.e. there's
151   // no tagged globals).
getMemtagRelocsSection(MCContext & Ctx)152   virtual MCSectionELF *getMemtagRelocsSection(MCContext &Ctx) const {
153     return nullptr;
154   }
155 };
156 
157 class ELFObjectWriter : public MCObjectWriter {
158   unsigned ELFHeaderEFlags = 0;
159 
160 public:
161   std::unique_ptr<MCELFObjectTargetWriter> TargetObjectWriter;
162   raw_pwrite_stream &OS;
163   raw_pwrite_stream *DwoOS = nullptr;
164 
165   DenseMap<const MCSectionELF *, std::vector<ELFRelocationEntry>> Relocations;
166   DenseMap<const MCSymbolELF *, const MCSymbolELF *> Renames;
167   bool IsLittleEndian = false;
168   bool SeenGnuAbi = false;
169   std::optional<uint8_t> OverrideABIVersion;
170 
171   struct Symver {
172     SMLoc Loc;
173     const MCSymbol *Sym;
174     StringRef Name;
175     // True if .symver *, *@@@* or .symver *, *, remove.
176     bool KeepOriginalSym;
177   };
178   SmallVector<Symver, 0> Symvers;
179 
180   ELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
181                   raw_pwrite_stream &OS, bool IsLittleEndian);
182   ELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
183                   raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS,
184                   bool IsLittleEndian);
185 
186   void reset() override;
187   void executePostLayoutBinding(MCAssembler &Asm) override;
188   void recordRelocation(MCAssembler &Asm, const MCFragment *Fragment,
189                         const MCFixup &Fixup, MCValue Target,
190                         uint64_t &FixedValue) override;
191   bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
192                                               const MCSymbol &SymA,
193                                               const MCFragment &FB, bool InSet,
194                                               bool IsPCRel) const override;
195   uint64_t writeObject(MCAssembler &Asm) override;
196 
197   bool hasRelocationAddend() const;
198   bool usesRela(const MCTargetOptions *TO, const MCSectionELF &Sec) const;
199 
200   bool shouldRelocateWithSymbol(const MCAssembler &Asm, const MCValue &Val,
201                                 const MCSymbolELF *Sym, uint64_t C,
202                                 unsigned Type) const;
203 
204   bool checkRelocation(MCContext &Ctx, SMLoc Loc, const MCSectionELF *From,
205                        const MCSectionELF *To);
206 
getELFHeaderEFlags()207   unsigned getELFHeaderEFlags() const { return ELFHeaderEFlags; }
setELFHeaderEFlags(unsigned Flags)208   void setELFHeaderEFlags(unsigned Flags) { ELFHeaderEFlags = Flags; }
209 
210   // Mark that we have seen GNU ABI usage (e.g. SHF_GNU_RETAIN, STB_GNU_UNIQUE).
markGnuAbi()211   void markGnuAbi() { SeenGnuAbi = true; }
seenGnuAbi()212   bool seenGnuAbi() const { return SeenGnuAbi; }
213 
214   // Override the default e_ident[EI_ABIVERSION] in the ELF header.
setOverrideABIVersion(uint8_t V)215   void setOverrideABIVersion(uint8_t V) { OverrideABIVersion = V; }
216 };
217 } // end namespace llvm
218 
219 #endif // LLVM_MC_MCELFOBJECTWRITER_H
220