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