xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- SparcELFObjectWriter.cpp - Sparc ELF Writer -----------------------===//
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/SparcFixupKinds.h"
10 #include "MCTargetDesc/SparcMCAsmInfo.h"
11 #include "MCTargetDesc/SparcMCTargetDesc.h"
12 #include "llvm/MC/MCContext.h"
13 #include "llvm/MC/MCELFObjectWriter.h"
14 #include "llvm/MC/MCExpr.h"
15 #include "llvm/MC/MCObjectFileInfo.h"
16 #include "llvm/MC/MCObjectWriter.h"
17 #include "llvm/MC/MCValue.h"
18 #include "llvm/Support/ErrorHandling.h"
19 
20 using namespace llvm;
21 
22 namespace {
23   class SparcELFObjectWriter : public MCELFObjectTargetWriter {
24   public:
SparcELFObjectWriter(bool Is64Bit,bool IsV8Plus,uint8_t OSABI)25     SparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, uint8_t OSABI)
26         : MCELFObjectTargetWriter(
27               Is64Bit, OSABI,
28               Is64Bit ? ELF::EM_SPARCV9
29                       : (IsV8Plus ? ELF::EM_SPARC32PLUS : ELF::EM_SPARC),
30               /*HasRelocationAddend*/ true) {}
31 
32     ~SparcELFObjectWriter() override = default;
33 
34   protected:
35     unsigned getRelocType(const MCFixup &Fixup, const MCValue &Target,
36                           bool IsPCRel) const override;
37 
38     bool needsRelocateWithSymbol(const MCValue &, unsigned Type) const override;
39   };
40 }
41 
getRelocType(const MCFixup & Fixup,const MCValue & Target,bool IsPCRel) const42 unsigned SparcELFObjectWriter::getRelocType(const MCFixup &Fixup,
43                                             const MCValue &Target,
44                                             bool IsPCRel) const {
45   switch (Target.getSpecifier()) {
46   case ELF::R_SPARC_TLS_GD_HI22:
47   case ELF::R_SPARC_TLS_GD_LO10:
48   case ELF::R_SPARC_TLS_GD_ADD:
49   case ELF::R_SPARC_TLS_LDM_HI22:
50   case ELF::R_SPARC_TLS_LDM_LO10:
51   case ELF::R_SPARC_TLS_LDM_ADD:
52   case ELF::R_SPARC_TLS_LDO_HIX22:
53   case ELF::R_SPARC_TLS_LDO_LOX10:
54   case ELF::R_SPARC_TLS_LDO_ADD:
55   case ELF::R_SPARC_TLS_IE_HI22:
56   case ELF::R_SPARC_TLS_IE_LO10:
57   case ELF::R_SPARC_TLS_IE_LD:
58   case ELF::R_SPARC_TLS_IE_LDX:
59   case ELF::R_SPARC_TLS_IE_ADD:
60   case ELF::R_SPARC_TLS_LE_HIX22:
61   case ELF::R_SPARC_TLS_LE_LOX10:
62     if (auto *SA = Target.getAddSym())
63       cast<MCSymbolELF>(SA)->setType(ELF::STT_TLS);
64     break;
65   default:
66     break;
67   }
68 
69   // Extract the relocation type from the fixup kind, after applying STT_TLS as
70   // needed.
71   auto Kind = Fixup.getKind();
72   if (mc::isRelocation(Fixup.getKind()))
73     return Kind;
74 
75   if (const auto *SExpr = dyn_cast<MCSpecifierExpr>(Fixup.getValue())) {
76     if (SExpr->getSpecifier() == ELF::R_SPARC_DISP32)
77       return ELF::R_SPARC_DISP32;
78   }
79 
80   if (IsPCRel) {
81     switch (Kind) {
82     default:
83       llvm_unreachable("Unimplemented fixup -> relocation");
84     case FK_Data_1:                  return ELF::R_SPARC_DISP8;
85     case FK_Data_2:                  return ELF::R_SPARC_DISP16;
86     case FK_Data_4:                  return ELF::R_SPARC_DISP32;
87     case FK_Data_8:                  return ELF::R_SPARC_DISP64;
88     case Sparc::fixup_sparc_call30:
89       if (getContext().getObjectFileInfo()->isPositionIndependent())
90         return ELF::R_SPARC_WPLT30;
91       return ELF::R_SPARC_WDISP30;
92     }
93   }
94 
95   // clang-format off
96   switch(Fixup.getKind()) {
97   default:
98     llvm_unreachable("Unimplemented fixup -> relocation");
99   case FK_NONE:                  return ELF::R_SPARC_NONE;
100   case FK_Data_1:                return ELF::R_SPARC_8;
101   case FK_Data_2:                return ((Fixup.getOffset() % 2)
102                                          ? ELF::R_SPARC_UA16
103                                          : ELF::R_SPARC_16);
104   case FK_Data_4:                return ((Fixup.getOffset() % 4)
105                                          ? ELF::R_SPARC_UA32
106                                          : ELF::R_SPARC_32);
107   case FK_Data_8:                return ((Fixup.getOffset() % 8)
108                                          ? ELF::R_SPARC_UA64
109                                          : ELF::R_SPARC_64);
110   case Sparc::fixup_sparc_13:
111     if (getContext().getObjectFileInfo()->isPositionIndependent())
112       return ELF::R_SPARC_GOT13;
113     return ELF::R_SPARC_13;
114   }
115   // clang-format on
116 
117   return ELF::R_SPARC_NONE;
118 }
119 
needsRelocateWithSymbol(const MCValue &,unsigned Type) const120 bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
121                                                    unsigned Type) const {
122   switch (Type) {
123     default:
124       return false;
125 
126     // All relocations that use a GOT need a symbol, not an offset, as
127     // the offset of the symbol within the section is irrelevant to
128     // where the GOT entry is. Don't need to list all the TLS entries,
129     // as they're all marked as requiring a symbol anyways.
130     case ELF::R_SPARC_GOT10:
131     case ELF::R_SPARC_GOT13:
132     case ELF::R_SPARC_GOT22:
133     case ELF::R_SPARC_GOTDATA_HIX22:
134     case ELF::R_SPARC_GOTDATA_LOX10:
135     case ELF::R_SPARC_GOTDATA_OP_HIX22:
136     case ELF::R_SPARC_GOTDATA_OP_LOX10:
137       return true;
138   }
139 }
140 
141 std::unique_ptr<MCObjectTargetWriter>
createSparcELFObjectWriter(bool Is64Bit,bool IsV8Plus,uint8_t OSABI)142 llvm::createSparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, uint8_t OSABI) {
143   return std::make_unique<SparcELFObjectWriter>(Is64Bit, IsV8Plus, OSABI);
144 }
145