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 "Symbols.h"
10#include "SyntheticSections.h"
11#include "Target.h"
12#include "llvm/Support/Endian.h"
13
14using namespace llvm;
15using namespace llvm::support::endian;
16using namespace llvm::ELF;
17using namespace lld;
18using namespace lld::elf;
19
20namespace {
21class SPARCV9 final : public TargetInfo {
22public:
23 SPARCV9(Ctx &);
24 RelExpr getRelExpr(RelType type, const Symbol &s,
25 const uint8_t *loc) const override;
26 void writePlt(uint8_t *buf, const Symbol &sym,
27 uint64_t pltEntryAddr) const override;
28 void relocate(uint8_t *loc, const Relocation &rel,
29 uint64_t val) const override;
30};
31} // namespace
32
33SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(ctx) {
34 copyRel = R_SPARC_COPY;
35 gotRel = R_SPARC_GLOB_DAT;
36 pltRel = R_SPARC_JMP_SLOT;
37 relativeRel = R_SPARC_RELATIVE;
38 symbolicRel = R_SPARC_64;
39 pltEntrySize = 32;
40 pltHeaderSize = 4 * pltEntrySize;
41
42 defaultCommonPageSize = 8192;
43 defaultMaxPageSize = 0x100000;
44 defaultImageBase = 0x100000;
45}
46
47RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s,
48 const uint8_t *loc) const {
49 switch (type) {
50 case R_SPARC_32:
51 case R_SPARC_UA32:
52 case R_SPARC_64:
53 case R_SPARC_UA64:
54 case R_SPARC_H44:
55 case R_SPARC_M44:
56 case R_SPARC_L44:
57 case R_SPARC_HH22:
58 case R_SPARC_HM10:
59 case R_SPARC_LM22:
60 case R_SPARC_HI22:
61 case R_SPARC_LO10:
62 return R_ABS;
63 case R_SPARC_PC10:
64 case R_SPARC_PC22:
65 case R_SPARC_DISP32:
66 case R_SPARC_WDISP30:
67 return R_PC;
68 case R_SPARC_GOT10:
69 return R_GOT_OFF;
70 case R_SPARC_GOT22:
71 return R_GOT_OFF;
72 case R_SPARC_WPLT30:
73 return R_PLT_PC;
74 case R_SPARC_NONE:
75 return R_NONE;
76 case R_SPARC_TLS_LE_HIX22:
77 case R_SPARC_TLS_LE_LOX10:
78 return R_TPREL;
79 default:
80 Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
81 << ") against symbol " << &s;
82 return R_NONE;
83 }
84}
85
86void SPARCV9::relocate(uint8_t *loc, const Relocation &rel,
87 uint64_t val) const {
88 switch (rel.type) {
89 case R_SPARC_32:
90 case R_SPARC_UA32:
91 // V-word32
92 checkUInt(ctx, loc, v: val, n: 32, rel);
93 write32be(P: loc, V: val);
94 break;
95 case R_SPARC_DISP32:
96 // V-disp32
97 checkInt(ctx, loc, v: val, n: 32, rel);
98 write32be(P: loc, V: val);
99 break;
100 case R_SPARC_WDISP30:
101 case R_SPARC_WPLT30:
102 // V-disp30
103 checkInt(ctx, loc, v: val, n: 32, rel);
104 write32be(P: loc, V: (read32be(P: loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff));
105 break;
106 case R_SPARC_22:
107 // V-imm22
108 checkUInt(ctx, loc, v: val, n: 22, rel);
109 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | (val & 0x003fffff));
110 break;
111 case R_SPARC_GOT22:
112 case R_SPARC_PC22:
113 case R_SPARC_LM22:
114 // T-imm22
115 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
116 break;
117 case R_SPARC_HI22:
118 // V-imm22
119 checkUInt(ctx, loc, v: val >> 10, n: 22, rel);
120 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
121 break;
122 case R_SPARC_WDISP19:
123 // V-disp19
124 checkInt(ctx, loc, v: val, n: 21, rel);
125 write32be(P: loc, V: (read32be(P: loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
126 break;
127 case R_SPARC_GOT10:
128 case R_SPARC_PC10:
129 // T-simm10
130 write32be(P: loc, V: (read32be(P: loc) & ~0x000003ff) | (val & 0x000003ff));
131 break;
132 case R_SPARC_LO10:
133 // T-simm13
134 write32be(P: loc, V: (read32be(P: loc) & ~0x00001fff) | (val & 0x000003ff));
135 break;
136 case R_SPARC_64:
137 case R_SPARC_UA64:
138 // V-xword64
139 write64be(P: loc, V: val);
140 break;
141 case R_SPARC_HH22:
142 // V-imm22
143 checkUInt(ctx, loc, v: val >> 42, n: 22, rel);
144 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | ((val >> 42) & 0x003fffff));
145 break;
146 case R_SPARC_HM10:
147 // T-simm13
148 write32be(P: loc, V: (read32be(P: loc) & ~0x00001fff) | ((val >> 32) & 0x000003ff));
149 break;
150 case R_SPARC_H44:
151 // V-imm22
152 checkUInt(ctx, loc, v: val >> 22, n: 22, rel);
153 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | ((val >> 22) & 0x003fffff));
154 break;
155 case R_SPARC_M44:
156 // T-imm10
157 write32be(P: loc, V: (read32be(P: loc) & ~0x000003ff) | ((val >> 12) & 0x000003ff));
158 break;
159 case R_SPARC_L44:
160 // T-imm13
161 write32be(P: loc, V: (read32be(P: loc) & ~0x00001fff) | (val & 0x00000fff));
162 break;
163 case R_SPARC_TLS_LE_HIX22:
164 // T-imm22
165 write32be(P: loc, V: (read32be(P: loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff));
166 break;
167 case R_SPARC_TLS_LE_LOX10:
168 // T-simm13
169 write32be(P: loc, V: (read32be(P: loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1C00);
170 break;
171 default:
172 llvm_unreachable("unknown relocation");
173 }
174}
175
176void SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/,
177 uint64_t pltEntryAddr) const {
178 const uint8_t pltData[] = {
179 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1
180 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1
181 0x01, 0x00, 0x00, 0x00, // nop
182 0x01, 0x00, 0x00, 0x00, // nop
183 0x01, 0x00, 0x00, 0x00, // nop
184 0x01, 0x00, 0x00, 0x00, // nop
185 0x01, 0x00, 0x00, 0x00, // nop
186 0x01, 0x00, 0x00, 0x00 // nop
187 };
188 memcpy(dest: buf, src: pltData, n: sizeof(pltData));
189
190 uint64_t off = pltEntryAddr - ctx.in.plt->getVA();
191 relocateNoSym(loc: buf, type: R_SPARC_22, val: off);
192 relocateNoSym(loc: buf + 4, type: R_SPARC_WDISP19, val: -(off + 4 - pltEntrySize));
193}
194
195void elf::setSPARCV9TargetInfo(Ctx &ctx) { ctx.target.reset(p: new SPARCV9(ctx)); }
196