1//===- SPARCV9.cpp --------------------------------------------------------===//
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 "RelocScan.h"
10#include "Symbols.h"
11#include "SyntheticSections.h"
12#include "Target.h"
13#include "llvm/Support/Endian.h"
14
15using namespace llvm;
16using namespace llvm::object;
17using namespace llvm::support::endian;
18using namespace llvm::ELF;
19using namespace lld;
20using namespace lld::elf;
21
22namespace {
23class SPARCV9 final : public TargetInfo {
24public:
25 SPARCV9(Ctx &);
26 RelExpr getRelExpr(RelType type, const Symbol &s,
27 const uint8_t *loc) const override;
28 void writePlt(uint8_t *buf, const Symbol &sym,
29 uint64_t pltEntryAddr) const override;
30 template <class ELFT, class RelTy>
31 void scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels,
32 unsigned shard);
33 void scanSection(InputSectionBase &sec, unsigned shard) override {
34 elf::scanSection1<SPARCV9, ELF64BE>(target&: *this, sec, shard);
35 }
36 void relocate(uint8_t *loc, const Relocation &rel,
37 uint64_t val) const override;
38};
39} // namespace
40
41SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(ctx) {
42 copyRel = R_SPARC_COPY;
43 gotRel = R_SPARC_GLOB_DAT;
44 pltRel = R_SPARC_JMP_SLOT;
45 relativeRel = R_SPARC_RELATIVE;
46 symbolicRel = R_SPARC_64;
47 pltEntrySize = 32;
48 pltHeaderSize = 4 * pltEntrySize;
49
50 defaultCommonPageSize = 8192;
51 defaultMaxPageSize = 0x100000;
52 defaultImageBase = 0x100000;
53}
54
55// Only needed to support relocations used by relocateNonAlloc and
56// preprocessRelocs.
57RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s,
58 const uint8_t *loc) const {
59 switch (type) {
60 case R_SPARC_32:
61 case R_SPARC_UA32:
62 case R_SPARC_64:
63 case R_SPARC_UA64:
64 return R_ABS;
65 case R_SPARC_DISP32:
66 return R_PC;
67 case R_SPARC_NONE:
68 return R_NONE;
69 default:
70 Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
71 << ") against symbol " << &s;
72 return R_NONE;
73 }
74}
75
76template <class ELFT, class RelTy>
77void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels,
78 unsigned shard) {
79 RelocScan rs(ctx, &sec, shard);
80 sec.relocations.reserve(N: rels.size());
81 for (auto it = rels.begin(); it != rels.end(); ++it) {
82 const RelTy &rel = *it;
83 uint32_t symIdx = rel.getSymbol(false);
84 Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIdx);
85 uint64_t offset = rel.r_offset;
86 RelType type = rel.getType(false);
87 if (sym.isUndefined() && symIdx != 0 &&
88 rs.maybeReportUndefined(sym&: cast<Undefined>(Val&: sym), offset))
89 continue;
90 int64_t addend = rs.getAddend<ELFT>(rel, type);
91 RelExpr expr;
92 switch (type) {
93 case R_SPARC_NONE:
94 continue;
95
96 // Absolute relocations:
97 case R_SPARC_32:
98 case R_SPARC_UA32:
99 case R_SPARC_64:
100 case R_SPARC_UA64:
101 case R_SPARC_H44:
102 case R_SPARC_M44:
103 case R_SPARC_L44:
104 case R_SPARC_HH22:
105 case R_SPARC_HM10:
106 case R_SPARC_LM22:
107 case R_SPARC_HI22:
108 case R_SPARC_LO10:
109 expr = R_ABS;
110 break;
111
112 // PLT-generating relocations:
113 case R_SPARC_WPLT30:
114 rs.processR_PLT_PC(type, offset, addend, sym);
115 continue;
116
117 // PC-relative relocations:
118 case R_SPARC_PC10:
119 case R_SPARC_PC22:
120 case R_SPARC_DISP32:
121 case R_SPARC_WDISP30:
122 rs.processR_PC(type, offset, addend, sym);
123 continue;
124
125 // GOT relocations:
126 case R_SPARC_GOT10:
127 case R_SPARC_GOT22:
128 expr = R_GOT_OFF;
129 break;
130
131 // TLS LE relocations:
132 case R_SPARC_TLS_LE_HIX22:
133 case R_SPARC_TLS_LE_LOX10:
134 if (rs.checkTlsLe(offset, sym, type))
135 continue;
136 expr = R_TPREL;
137 break;
138
139 default:
140 Err(ctx) << getErrorLoc(ctx, loc: sec.content().data() + offset)
141 << "unknown relocation (" << type.v << ") against symbol "
142 << &sym;
143 continue;
144 }
145 rs.process(expr, type, offset, sym, addend);
146 }
147}
148
149void SPARCV9::relocate(uint8_t *loc, const Relocation &rel,
150 uint64_t val) const {
151 switch (rel.type) {
152 case R_SPARC_32:
153 case R_SPARC_UA32:
154 // V-word32
155 checkUInt(ctx, loc, v: val, n: 32, rel);
156 write32be(P: loc, V: val);
157 break;
158 case R_SPARC_DISP32:
159 // V-disp32
160 checkInt(ctx, loc, v: val, n: 32, rel);
161 write32be(P: loc, V: val);
162 break;
163 case R_SPARC_WDISP30:
164 case R_SPARC_WPLT30:
165 // V-disp30
166 checkInt(ctx, loc, v: val, n: 32, rel);
167 write32be(P: loc, V: (read32be(P: loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff));
168 break;
169 case R_SPARC_22:
170 // V-imm22
171 checkUInt(ctx, loc, v: val, n: 22, rel);
172 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | (val & 0x003fffff));
173 break;
174 case R_SPARC_GOT22:
175 case R_SPARC_PC22:
176 case R_SPARC_LM22:
177 // T-imm22
178 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
179 break;
180 case R_SPARC_HI22:
181 // V-imm22
182 checkUInt(ctx, loc, v: val >> 10, n: 22, rel);
183 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
184 break;
185 case R_SPARC_WDISP19:
186 // V-disp19
187 checkInt(ctx, loc, v: val, n: 21, rel);
188 write32be(P: loc, V: (read32be(P: loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
189 break;
190 case R_SPARC_GOT10:
191 case R_SPARC_PC10:
192 // T-simm10
193 write32be(P: loc, V: (read32be(P: loc) & ~0x000003ff) | (val & 0x000003ff));
194 break;
195 case R_SPARC_LO10:
196 // T-simm13
197 write32be(P: loc, V: (read32be(P: loc) & ~0x00001fff) | (val & 0x000003ff));
198 break;
199 case R_SPARC_64:
200 case R_SPARC_UA64:
201 // V-xword64
202 write64be(P: loc, V: val);
203 break;
204 case R_SPARC_HH22:
205 // V-imm22
206 checkUInt(ctx, loc, v: val >> 42, n: 22, rel);
207 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | ((val >> 42) & 0x003fffff));
208 break;
209 case R_SPARC_HM10:
210 // T-simm13
211 write32be(P: loc, V: (read32be(P: loc) & ~0x00001fff) | ((val >> 32) & 0x000003ff));
212 break;
213 case R_SPARC_H44:
214 // V-imm22
215 checkUInt(ctx, loc, v: val >> 22, n: 22, rel);
216 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | ((val >> 22) & 0x003fffff));
217 break;
218 case R_SPARC_M44:
219 // T-imm10
220 write32be(P: loc, V: (read32be(P: loc) & ~0x000003ff) | ((val >> 12) & 0x000003ff));
221 break;
222 case R_SPARC_L44:
223 // T-imm13
224 write32be(P: loc, V: (read32be(P: loc) & ~0x00001fff) | (val & 0x00000fff));
225 break;
226 case R_SPARC_TLS_LE_HIX22:
227 // T-imm22
228 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff));
229 break;
230 case R_SPARC_TLS_LE_LOX10:
231 // T-simm13
232 write32be(P: loc, V: (read32be(P: loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1C00);
233 break;
234 default:
235 llvm_unreachable("unknown relocation");
236 }
237}
238
239void SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/,
240 uint64_t pltEntryAddr) const {
241 const uint8_t pltData[] = {
242 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1
243 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1
244 0x01, 0x00, 0x00, 0x00, // nop
245 0x01, 0x00, 0x00, 0x00, // nop
246 0x01, 0x00, 0x00, 0x00, // nop
247 0x01, 0x00, 0x00, 0x00, // nop
248 0x01, 0x00, 0x00, 0x00, // nop
249 0x01, 0x00, 0x00, 0x00 // nop
250 };
251 memcpy(dest: buf, src: pltData, n: sizeof(pltData));
252
253 uint64_t off = pltEntryAddr - ctx.in.plt->getVA();
254 relocateNoSym(loc: buf, type: R_SPARC_22, val: off);
255 relocateNoSym(loc: buf + 4, type: R_SPARC_WDISP19, val: -(off + 4 - pltEntrySize));
256}
257
258void elf::setSPARCV9TargetInfo(Ctx &ctx) { ctx.target.reset(p: new SPARCV9(ctx)); }
259