Skip to content

Commit 5dafba1

Browse files
alexrpLemonBoy
andcommitted
[LLD][SPARC] Implement enough functionality to run non-trivial 64-bit programs.
This allows the Zig test suite to link and run for sparc64-linux, both with glibc and without any libc. This patch incorporates portions of the abandoned https://reviews.llvm.org/D102985 which I came across while working on this. Co-authored-by: LemonBoy <thatlemon@gmail.com>
1 parent f5b7d42 commit 5dafba1

11 files changed

+324
-77
lines changed

lld/ELF/Arch/SPARCV9.cpp

Lines changed: 235 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "OutputSections.h"
910
#include "Symbols.h"
1011
#include "SyntheticSections.h"
1112
#include "Target.h"
@@ -24,10 +25,17 @@ class SPARCV9 final : public TargetInfo {
2425
SPARCV9(Ctx &);
2526
RelExpr getRelExpr(RelType type, const Symbol &s,
2627
const uint8_t *loc) const override;
28+
RelType getDynRel(RelType type) const override;
29+
void writeGotHeader(uint8_t *buf) const override;
2730
void writePlt(uint8_t *buf, const Symbol &sym,
2831
uint64_t pltEntryAddr) const override;
2932
void relocate(uint8_t *loc, const Relocation &rel,
3033
uint64_t val) const override;
34+
RelExpr adjustGotOffExpr(RelType type, const Symbol &sym, int64_t addend,
35+
const uint8_t *loc) const override;
36+
37+
private:
38+
void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const;
3139
};
3240
} // namespace
3341

@@ -36,9 +44,16 @@ SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(ctx) {
3644
gotRel = R_SPARC_GLOB_DAT;
3745
pltRel = R_SPARC_JMP_SLOT;
3846
relativeRel = R_SPARC_RELATIVE;
47+
iRelativeRel = R_SPARC_IRELATIVE;
3948
symbolicRel = R_SPARC_64;
49+
tlsGotRel = R_SPARC_TLS_TPOFF64;
50+
tlsModuleIndexRel = R_SPARC_TLS_DTPMOD64;
51+
tlsOffsetRel = R_SPARC_TLS_DTPOFF64;
52+
53+
gotHeaderEntriesNum = 1;
4054
pltEntrySize = 32;
4155
pltHeaderSize = 4 * pltEntrySize;
56+
usesGotPlt = false;
4257

4358
defaultCommonPageSize = 8192;
4459
defaultMaxPageSize = 0x100000;
@@ -48,109 +63,222 @@ SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(ctx) {
4863
RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s,
4964
const uint8_t *loc) const {
5065
switch (type) {
66+
case R_SPARC_NONE:
67+
return R_NONE;
68+
case R_SPARC_8:
69+
case R_SPARC_16:
5170
case R_SPARC_32:
71+
case R_SPARC_HI22:
72+
case R_SPARC_13:
73+
case R_SPARC_LO10:
5274
case R_SPARC_UA32:
5375
case R_SPARC_64:
54-
case R_SPARC_UA64:
55-
case R_SPARC_H44:
56-
case R_SPARC_M44:
57-
case R_SPARC_L44:
5876
case R_SPARC_HH22:
5977
case R_SPARC_HM10:
6078
case R_SPARC_LM22:
61-
case R_SPARC_HI22:
62-
case R_SPARC_LO10:
79+
case R_SPARC_HIX22:
80+
case R_SPARC_LOX10:
81+
case R_SPARC_H44:
82+
case R_SPARC_M44:
83+
case R_SPARC_L44:
84+
case R_SPARC_UA64:
85+
case R_SPARC_UA16:
6386
return R_ABS;
64-
case R_SPARC_PC10:
65-
case R_SPARC_PC22:
87+
case R_SPARC_DISP8:
88+
case R_SPARC_DISP16:
6689
case R_SPARC_DISP32:
6790
case R_SPARC_WDISP30:
91+
case R_SPARC_WDISP22:
92+
case R_SPARC_PC10:
93+
case R_SPARC_PC22:
94+
case R_SPARC_WDISP16:
95+
case R_SPARC_DISP64:
6896
return R_PC;
6997
case R_SPARC_GOT10:
70-
return R_GOT_OFF;
98+
case R_SPARC_GOT13:
7199
case R_SPARC_GOT22:
100+
case R_SPARC_GOTDATA_OP_HIX22:
101+
case R_SPARC_GOTDATA_OP_LOX10:
102+
case R_SPARC_GOTDATA_OP:
72103
return R_GOT_OFF;
73104
case R_SPARC_WPLT30:
105+
case R_SPARC_TLS_GD_CALL:
106+
case R_SPARC_TLS_LDM_CALL:
74107
return R_PLT_PC;
75-
case R_SPARC_NONE:
76-
return R_NONE;
108+
case R_SPARC_TLS_GD_HI22:
109+
case R_SPARC_TLS_GD_LO10:
110+
return R_TLSGD_GOT;
111+
case R_SPARC_TLS_GD_ADD:
112+
case R_SPARC_TLS_LDM_ADD:
113+
case R_SPARC_TLS_LDO_ADD:
114+
case R_SPARC_TLS_IE_LD:
115+
case R_SPARC_TLS_IE_LDX:
116+
case R_SPARC_TLS_IE_ADD:
117+
return R_NONE; // TODO: Relax TLS relocations.
118+
case R_SPARC_TLS_LDM_HI22:
119+
case R_SPARC_TLS_LDM_LO10:
120+
return R_TLSLD_GOT;
121+
case R_SPARC_TLS_LDO_HIX22:
122+
case R_SPARC_TLS_LDO_LOX10:
123+
return R_DTPREL;
124+
case R_SPARC_TLS_IE_HI22:
125+
case R_SPARC_TLS_IE_LO10:
126+
return R_GOT;
77127
case R_SPARC_TLS_LE_HIX22:
78128
case R_SPARC_TLS_LE_LOX10:
79129
return R_TPREL;
130+
case R_SPARC_GOTDATA_HIX22:
131+
case R_SPARC_GOTDATA_LOX10:
132+
return R_GOTREL;
80133
default:
81134
Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
82135
<< ") against symbol " << &s;
83136
return R_NONE;
84137
}
85138
}
86139

140+
RelType SPARCV9::getDynRel(RelType type) const {
141+
if (type == symbolicRel)
142+
return type;
143+
return R_SPARC_NONE;
144+
}
145+
87146
void SPARCV9::relocate(uint8_t *loc, const Relocation &rel,
88147
uint64_t val) const {
148+
switch (rel.expr) {
149+
case R_RELAX_GOT_OFF:
150+
return relaxGot(loc, rel, val);
151+
default:
152+
break;
153+
}
154+
89155
switch (rel.type) {
156+
case R_SPARC_8:
157+
// V-byte8
158+
checkUInt(ctx, loc, val, 8, rel);
159+
*loc = val;
160+
break;
161+
case R_SPARC_16:
162+
case R_SPARC_UA16:
163+
// V-half16
164+
checkUInt(ctx, loc, val, 16, rel);
165+
write16be(loc, val);
166+
break;
90167
case R_SPARC_32:
91168
case R_SPARC_UA32:
92169
// V-word32
93170
checkUInt(ctx, loc, val, 32, rel);
94171
write32be(loc, val);
95172
break;
173+
case R_SPARC_DISP8:
174+
// V-byte8
175+
checkIntUInt(ctx, loc, val, 8, rel);
176+
*loc = val;
177+
break;
178+
case R_SPARC_DISP16:
179+
// V-half16
180+
checkIntUInt(ctx, loc, val, 16, rel);
181+
write16be(loc, val);
182+
break;
96183
case R_SPARC_DISP32:
97184
// V-disp32
98-
checkInt(ctx, loc, val, 32, rel);
185+
checkIntUInt(ctx, loc, val, 32, rel);
99186
write32be(loc, val);
100187
break;
101188
case R_SPARC_WDISP30:
102189
case R_SPARC_WPLT30:
190+
case R_SPARC_TLS_GD_CALL:
191+
case R_SPARC_TLS_LDM_CALL:
103192
// V-disp30
104-
checkInt(ctx, loc, val, 32, rel);
193+
checkIntUInt(ctx, loc, val, 32, rel);
105194
write32be(loc, (read32be(loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff));
106195
break;
107-
case R_SPARC_22:
108-
// V-imm22
109-
checkUInt(ctx, loc, val, 22, rel);
110-
write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
196+
case R_SPARC_WDISP22:
197+
// V-disp22
198+
checkIntUInt(ctx, loc, val, 24, rel);
199+
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 2) & 0x003fffff));
111200
break;
112-
case R_SPARC_GOT22:
113-
case R_SPARC_PC22:
114-
case R_SPARC_LM22:
115-
// T-imm22
201+
case R_SPARC_HI22: // Only T-imm22 on 32-bit, despite binutils behavior.
202+
// V-imm22
203+
checkUInt(ctx, loc, val, 32, rel);
116204
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
117205
break;
118-
case R_SPARC_HI22:
206+
case R_SPARC_22:
119207
// V-imm22
120-
checkUInt(ctx, loc, val >> 10, 22, rel);
121-
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
208+
checkUInt(ctx, loc, val, 22, rel);
209+
write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
122210
break;
123-
case R_SPARC_WDISP19:
124-
// V-disp19
125-
checkInt(ctx, loc, val, 21, rel);
126-
write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
211+
case R_SPARC_13:
212+
case R_SPARC_GOT13:
213+
// V-simm13
214+
checkIntUInt(ctx, loc, val, 13, rel);
215+
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x00001fff));
127216
break;
217+
case R_SPARC_LO10:
128218
case R_SPARC_GOT10:
129219
case R_SPARC_PC10:
130-
// T-simm10
220+
case R_SPARC_TLS_GD_LO10:
221+
case R_SPARC_TLS_LDM_LO10:
222+
case R_SPARC_TLS_IE_LO10:
223+
// T-simm13
131224
write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff));
132225
break;
133-
case R_SPARC_LO10:
226+
case R_SPARC_TLS_LDO_LOX10:
134227
// T-simm13
135228
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff));
136229
break;
230+
case R_SPARC_GOT22:
231+
case R_SPARC_LM22:
232+
case R_SPARC_TLS_GD_HI22:
233+
case R_SPARC_TLS_LDM_HI22:
234+
case R_SPARC_TLS_LDO_HIX22: // Not V-simm22, despite binutils behavior.
235+
case R_SPARC_TLS_IE_HI22:
236+
// T-(s)imm22
237+
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
238+
break;
239+
case R_SPARC_PC22:
240+
// V-disp22
241+
checkIntUInt(ctx, loc, val, 32, rel);
242+
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
243+
break;
137244
case R_SPARC_64:
245+
case R_SPARC_DISP64:
138246
case R_SPARC_UA64:
139247
// V-xword64
140248
write64be(loc, val);
141249
break;
142250
case R_SPARC_HH22:
143251
// V-imm22
144-
checkUInt(ctx, loc, val >> 42, 22, rel);
145252
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 42) & 0x003fffff));
146253
break;
147254
case R_SPARC_HM10:
148255
// T-simm13
149-
write32be(loc, (read32be(loc) & ~0x00001fff) | ((val >> 32) & 0x000003ff));
256+
write32be(loc, (read32be(loc) & ~0x000003ff) | ((val >> 32) & 0x000003ff));
257+
break;
258+
case R_SPARC_WDISP16:
259+
// V-d2/disp14
260+
checkIntUInt(ctx, loc, val, 18, rel);
261+
write32be(loc, (read32be(loc) & ~0x0303fff) | (((val >> 2) & 0xc000) << 6) |
262+
((val >> 2) & 0x00003fff));
263+
break;
264+
case R_SPARC_WDISP19:
265+
// V-disp19
266+
checkIntUInt(ctx, loc, val, 21, rel);
267+
write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
268+
break;
269+
case R_SPARC_HIX22:
270+
// V-imm22
271+
checkUInt(ctx, loc, ~val, 32, rel);
272+
write32be(loc, (read32be(loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff));
273+
break;
274+
case R_SPARC_LOX10:
275+
case R_SPARC_TLS_LE_LOX10:
276+
// T-simm13
277+
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1c00);
150278
break;
151279
case R_SPARC_H44:
152280
// V-imm22
153-
checkUInt(ctx, loc, val >> 22, 22, rel);
281+
checkUInt(ctx, loc, val, 44, rel);
154282
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 22) & 0x003fffff));
155283
break;
156284
case R_SPARC_M44:
@@ -159,21 +287,90 @@ void SPARCV9::relocate(uint8_t *loc, const Relocation &rel,
159287
break;
160288
case R_SPARC_L44:
161289
// T-imm13
162-
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x00000fff));
290+
write32be(loc, (read32be(loc) & ~0x00000fff) | (val & 0x00000fff));
163291
break;
164-
case R_SPARC_TLS_LE_HIX22:
292+
case R_SPARC_TLS_GD_ADD:
293+
case R_SPARC_TLS_LDM_ADD:
294+
case R_SPARC_TLS_LDO_ADD:
295+
case R_SPARC_TLS_IE_LD:
296+
case R_SPARC_TLS_IE_LDX:
297+
case R_SPARC_TLS_IE_ADD:
298+
// None
299+
break;
300+
case R_SPARC_TLS_LE_HIX22: // Not V-imm2, despite binutils behavior.
165301
// T-imm22
166302
write32be(loc, (read32be(loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff));
167303
break;
168-
case R_SPARC_TLS_LE_LOX10:
169-
// T-simm13
170-
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1C00);
304+
case R_SPARC_GOTDATA_HIX22:
305+
// V-imm22
306+
checkUInt(ctx, loc, ((int64_t)val < 0 ? ~val : val), 32, rel);
307+
write32be(loc, (read32be(loc) & ~0x003fffff) |
308+
((((int64_t)val < 0 ? ~val : val) >> 10) & 0x003fffff));
309+
break;
310+
case R_SPARC_GOTDATA_OP_HIX22: // Not V-imm22, despite binutils behavior.
311+
// Non-relaxed case.
312+
// T-imm22
313+
write32be(loc, (read32be(loc) & ~0x003fffff) |
314+
((((int64_t)val < 0 ? ~val : val) >> 10) & 0x003fffff));
315+
break;
316+
case R_SPARC_GOTDATA_LOX10:
317+
case R_SPARC_GOTDATA_OP_LOX10: // Non-relaxed case.
318+
// T-imm13
319+
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) |
320+
((int64_t)val < 0 ? 0x1c00 : 0));
321+
break;
322+
case R_SPARC_GOTDATA_OP: // Non-relaxed case.
323+
// word32
324+
// Nothing needs to be done in the non-relaxed case.
171325
break;
172326
default:
173327
llvm_unreachable("unknown relocation");
174328
}
175329
}
176330

331+
RelExpr SPARCV9::adjustGotOffExpr(RelType type, const Symbol &sym,
332+
int64_t addend, const uint8_t *loc) const {
333+
switch (type) {
334+
case R_SPARC_GOTDATA_OP_HIX22:
335+
case R_SPARC_GOTDATA_OP_LOX10:
336+
case R_SPARC_GOTDATA_OP:
337+
if (sym.isLocal())
338+
return R_RELAX_GOT_OFF;
339+
340+
[[fallthrough]];
341+
default:
342+
return R_GOT_OFF;
343+
}
344+
}
345+
346+
void SPARCV9::relaxGot(uint8_t *loc, const Relocation &rel,
347+
uint64_t val) const {
348+
switch (rel.type) {
349+
case R_SPARC_GOTDATA_OP_HIX22: // Not V-imm22, despite binutils behavior.
350+
// T-imm22
351+
write32be(loc, (read32be(loc) & ~0x003fffff) |
352+
((((int64_t)val < 0 ? ~val : val) >> 10) & 0x003fffff));
353+
break;
354+
case R_SPARC_GOTDATA_OP_LOX10:
355+
// T-imm13
356+
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) |
357+
((int64_t)val < 0 ? 0x1c00 : 0));
358+
break;
359+
case R_SPARC_GOTDATA_OP:
360+
// word32
361+
// ldx [%rs1 + %rs2], %rd -> add %rs1, %rs2, %rd
362+
write32be(loc, (read32be(loc) & 0x3e07c01f) | 0x80000000);
363+
break;
364+
default:
365+
llvm_unreachable("unknown relocation");
366+
}
367+
}
368+
369+
void SPARCV9::writeGotHeader(uint8_t *buf) const {
370+
// _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC
371+
write32(ctx, buf, ctx.mainPart->dynamic->getVA());
372+
}
373+
177374
void SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/,
178375
uint64_t pltEntryAddr) const {
179376
const uint8_t pltData[] = {

0 commit comments

Comments
 (0)