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