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
20using namespace llvm;
21
22namespace {
23 class SparcELFObjectWriter : public MCELFObjectTargetWriter {
24 public:
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
42unsigned 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>(Val: 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 unsigned Kind = Fixup.getTargetKind();
72 if (mc::isRelocation(FixupKind: Fixup.getKind()))
73 return Kind;
74
75 if (const auto *SExpr = dyn_cast<MCSpecifierExpr>(Val: 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.getTargetKind()) {
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
120bool 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
141std::unique_ptr<MCObjectTargetWriter>
142llvm::createSparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, uint8_t OSABI) {
143 return std::make_unique<SparcELFObjectWriter>(args&: Is64Bit, args&: IsV8Plus, args&: OSABI);
144}
145