Skip to content

Commit 4d29903

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 <[email protected]>
1 parent eadf0eb commit 4d29903

File tree

11 files changed

+322
-78
lines changed

11 files changed

+322
-78
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"
@@ -23,10 +24,17 @@ class SPARCV9 final : public TargetInfo {
2324
SPARCV9(Ctx &);
2425
RelExpr getRelExpr(RelType type, const Symbol &s,
2526
const uint8_t *loc) const override;
27+
RelType getDynRel(RelType type) const override;
28+
void writeGotHeader(uint8_t *buf) const override;
2629
void writePlt(uint8_t *buf, const Symbol &sym,
2730
uint64_t pltEntryAddr) const override;
2831
void relocate(uint8_t *loc, const Relocation &rel,
2932
uint64_t val) const override;
33+
RelExpr adjustGotOffExpr(RelType type, const Symbol &sym, int64_t addend,
34+
const uint8_t *loc) const override;
35+
36+
private:
37+
void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const;
3038
};
3139
} // namespace
3240

@@ -35,9 +43,16 @@ SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(ctx) {
3543
gotRel = R_SPARC_GLOB_DAT;
3644
pltRel = R_SPARC_JMP_SLOT;
3745
relativeRel = R_SPARC_RELATIVE;
46+
iRelativeRel = R_SPARC_IRELATIVE;
3847
symbolicRel = R_SPARC_64;
48+
tlsGotRel = R_SPARC_TLS_TPOFF64;
49+
tlsModuleIndexRel = R_SPARC_TLS_DTPMOD64;
50+
tlsOffsetRel = R_SPARC_TLS_DTPOFF64;
51+
52+
gotHeaderEntriesNum = 1;
3953
pltEntrySize = 32;
4054
pltHeaderSize = 4 * pltEntrySize;
55+
usesGotPlt = false;
4156

4257
defaultCommonPageSize = 8192;
4358
defaultMaxPageSize = 0x100000;
@@ -47,109 +62,222 @@ SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(ctx) {
4762
RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s,
4863
const uint8_t *loc) const {
4964
switch (type) {
65+
case R_SPARC_NONE:
66+
return R_NONE;
67+
case R_SPARC_8:
68+
case R_SPARC_16:
5069
case R_SPARC_32:
70+
case R_SPARC_HI22:
71+
case R_SPARC_13:
72+
case R_SPARC_LO10:
5173
case R_SPARC_UA32:
5274
case R_SPARC_64:
53-
case R_SPARC_UA64:
54-
case R_SPARC_H44:
55-
case R_SPARC_M44:
56-
case R_SPARC_L44:
5775
case R_SPARC_HH22:
5876
case R_SPARC_HM10:
5977
case R_SPARC_LM22:
60-
case R_SPARC_HI22:
61-
case R_SPARC_LO10:
78+
case R_SPARC_HIX22:
79+
case R_SPARC_LOX10:
80+
case R_SPARC_H44:
81+
case R_SPARC_M44:
82+
case R_SPARC_L44:
83+
case R_SPARC_UA64:
84+
case R_SPARC_UA16:
6285
return R_ABS;
63-
case R_SPARC_PC10:
64-
case R_SPARC_PC22:
86+
case R_SPARC_DISP8:
87+
case R_SPARC_DISP16:
6588
case R_SPARC_DISP32:
6689
case R_SPARC_WDISP30:
90+
case R_SPARC_WDISP22:
91+
case R_SPARC_PC10:
92+
case R_SPARC_PC22:
93+
case R_SPARC_WDISP16:
94+
case R_SPARC_DISP64:
6795
return R_PC;
6896
case R_SPARC_GOT10:
69-
return R_GOT_OFF;
97+
case R_SPARC_GOT13:
7098
case R_SPARC_GOT22:
99+
case R_SPARC_GOTDATA_OP_HIX22:
100+
case R_SPARC_GOTDATA_OP_LOX10:
101+
case R_SPARC_GOTDATA_OP:
71102
return R_GOT_OFF;
72103
case R_SPARC_WPLT30:
104+
case R_SPARC_TLS_GD_CALL:
105+
case R_SPARC_TLS_LDM_CALL:
73106
return R_PLT_PC;
74-
case R_SPARC_NONE:
75-
return R_NONE;
107+
case R_SPARC_TLS_GD_HI22:
108+
case R_SPARC_TLS_GD_LO10:
109+
return R_TLSGD_GOT;
110+
case R_SPARC_TLS_GD_ADD:
111+
case R_SPARC_TLS_LDM_ADD:
112+
case R_SPARC_TLS_LDO_ADD:
113+
case R_SPARC_TLS_IE_LD:
114+
case R_SPARC_TLS_IE_LDX:
115+
case R_SPARC_TLS_IE_ADD:
116+
return R_NONE; // TODO: Relax TLS relocations.
117+
case R_SPARC_TLS_LDM_HI22:
118+
case R_SPARC_TLS_LDM_LO10:
119+
return R_TLSLD_GOT;
120+
case R_SPARC_TLS_LDO_HIX22:
121+
case R_SPARC_TLS_LDO_LOX10:
122+
return R_DTPREL;
123+
case R_SPARC_TLS_IE_HI22:
124+
case R_SPARC_TLS_IE_LO10:
125+
return R_GOT;
76126
case R_SPARC_TLS_LE_HIX22:
77127
case R_SPARC_TLS_LE_LOX10:
78128
return R_TPREL;
129+
case R_SPARC_GOTDATA_HIX22:
130+
case R_SPARC_GOTDATA_LOX10:
131+
return R_GOTREL;
79132
default:
80133
Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
81134
<< ") against symbol " << &s;
82135
return R_NONE;
83136
}
84137
}
85138

139+
RelType SPARCV9::getDynRel(RelType type) const {
140+
if (type == symbolicRel)
141+
return type;
142+
return R_SPARC_NONE;
143+
}
144+
86145
void SPARCV9::relocate(uint8_t *loc, const Relocation &rel,
87146
uint64_t val) const {
147+
switch (rel.expr) {
148+
case R_RELAX_GOT_OFF:
149+
return relaxGot(loc, rel, val);
150+
default:
151+
break;
152+
}
153+
88154
switch (rel.type) {
155+
case R_SPARC_8:
156+
// V-byte8
157+
checkUInt(ctx, loc, val, 8, rel);
158+
*loc = val;
159+
break;
160+
case R_SPARC_16:
161+
case R_SPARC_UA16:
162+
// V-half16
163+
checkUInt(ctx, loc, val, 16, rel);
164+
write16be(loc, val);
165+
break;
89166
case R_SPARC_32:
90167
case R_SPARC_UA32:
91168
// V-word32
92169
checkUInt(ctx, loc, val, 32, rel);
93170
write32be(loc, val);
94171
break;
172+
case R_SPARC_DISP8:
173+
// V-byte8
174+
checkIntUInt(ctx, loc, val, 8, rel);
175+
*loc = val;
176+
break;
177+
case R_SPARC_DISP16:
178+
// V-half16
179+
checkIntUInt(ctx, loc, val, 16, rel);
180+
write16be(loc, val);
181+
break;
95182
case R_SPARC_DISP32:
96183
// V-disp32
97-
checkInt(ctx, loc, val, 32, rel);
184+
checkIntUInt(ctx, loc, val, 32, rel);
98185
write32be(loc, val);
99186
break;
100187
case R_SPARC_WDISP30:
101188
case R_SPARC_WPLT30:
189+
case R_SPARC_TLS_GD_CALL:
190+
case R_SPARC_TLS_LDM_CALL:
102191
// V-disp30
103-
checkInt(ctx, loc, val, 32, rel);
192+
checkIntUInt(ctx, loc, val, 32, rel);
104193
write32be(loc, (read32be(loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff));
105194
break;
106-
case R_SPARC_22:
107-
// V-imm22
108-
checkUInt(ctx, loc, val, 22, rel);
109-
write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
195+
case R_SPARC_WDISP22:
196+
// V-disp22
197+
checkIntUInt(ctx, loc, val, 24, rel);
198+
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 2) & 0x003fffff));
110199
break;
111-
case R_SPARC_GOT22:
112-
case R_SPARC_PC22:
113-
case R_SPARC_LM22:
114-
// T-imm22
200+
case R_SPARC_HI22: // Only T-imm22 on 32-bit, despite binutils behavior.
201+
// V-imm22
202+
checkUInt(ctx, loc, val, 32, rel);
115203
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
116204
break;
117-
case R_SPARC_HI22:
205+
case R_SPARC_22:
118206
// V-imm22
119-
checkUInt(ctx, loc, val >> 10, 22, rel);
120-
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
207+
checkUInt(ctx, loc, val, 22, rel);
208+
write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
121209
break;
122-
case R_SPARC_WDISP19:
123-
// V-disp19
124-
checkInt(ctx, loc, val, 21, rel);
125-
write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
210+
case R_SPARC_13:
211+
case R_SPARC_GOT13:
212+
// V-simm13
213+
checkIntUInt(ctx, loc, val, 13, rel);
214+
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x00001fff));
126215
break;
216+
case R_SPARC_LO10:
127217
case R_SPARC_GOT10:
128218
case R_SPARC_PC10:
129-
// T-simm10
219+
case R_SPARC_TLS_GD_LO10:
220+
case R_SPARC_TLS_LDM_LO10:
221+
case R_SPARC_TLS_IE_LO10:
222+
// T-simm13
130223
write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff));
131224
break;
132-
case R_SPARC_LO10:
225+
case R_SPARC_TLS_LDO_LOX10:
133226
// T-simm13
134227
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff));
135228
break;
229+
case R_SPARC_GOT22:
230+
case R_SPARC_LM22:
231+
case R_SPARC_TLS_GD_HI22:
232+
case R_SPARC_TLS_LDM_HI22:
233+
case R_SPARC_TLS_LDO_HIX22: // Not V-simm22, despite binutils behavior.
234+
case R_SPARC_TLS_IE_HI22:
235+
// T-(s)imm22
236+
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
237+
break;
238+
case R_SPARC_PC22:
239+
// V-disp22
240+
checkIntUInt(ctx, loc, val, 32, rel);
241+
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
242+
break;
136243
case R_SPARC_64:
244+
case R_SPARC_DISP64:
137245
case R_SPARC_UA64:
138246
// V-xword64
139247
write64be(loc, val);
140248
break;
141249
case R_SPARC_HH22:
142250
// V-imm22
143-
checkUInt(ctx, loc, val >> 42, 22, rel);
144251
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 42) & 0x003fffff));
145252
break;
146253
case R_SPARC_HM10:
147254
// T-simm13
148-
write32be(loc, (read32be(loc) & ~0x00001fff) | ((val >> 32) & 0x000003ff));
255+
write32be(loc, (read32be(loc) & ~0x000003ff) | ((val >> 32) & 0x000003ff));
256+
break;
257+
case R_SPARC_WDISP16:
258+
// V-d2/disp14
259+
checkIntUInt(ctx, loc, val, 18, rel);
260+
write32be(loc, (read32be(loc) & ~0x0303fff) | (((val >> 2) & 0xc000) << 6) |
261+
((val >> 2) & 0x00003fff));
262+
break;
263+
case R_SPARC_WDISP19:
264+
// V-disp19
265+
checkIntUInt(ctx, loc, val, 21, rel);
266+
write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
267+
break;
268+
case R_SPARC_HIX22:
269+
// V-imm22
270+
checkUInt(ctx, loc, ~val, 32, rel);
271+
write32be(loc, (read32be(loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff));
272+
break;
273+
case R_SPARC_LOX10:
274+
case R_SPARC_TLS_LE_LOX10:
275+
// T-simm13
276+
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1c00);
149277
break;
150278
case R_SPARC_H44:
151279
// V-imm22
152-
checkUInt(ctx, loc, val >> 22, 22, rel);
280+
checkUInt(ctx, loc, val, 44, rel);
153281
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 22) & 0x003fffff));
154282
break;
155283
case R_SPARC_M44:
@@ -158,21 +286,90 @@ void SPARCV9::relocate(uint8_t *loc, const Relocation &rel,
158286
break;
159287
case R_SPARC_L44:
160288
// T-imm13
161-
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x00000fff));
289+
write32be(loc, (read32be(loc) & ~0x00000fff) | (val & 0x00000fff));
162290
break;
163-
case R_SPARC_TLS_LE_HIX22:
291+
case R_SPARC_TLS_GD_ADD:
292+
case R_SPARC_TLS_LDM_ADD:
293+
case R_SPARC_TLS_LDO_ADD:
294+
case R_SPARC_TLS_IE_LD:
295+
case R_SPARC_TLS_IE_LDX:
296+
case R_SPARC_TLS_IE_ADD:
297+
// None
298+
break;
299+
case R_SPARC_TLS_LE_HIX22: // Not V-imm2, despite binutils behavior.
164300
// T-imm22
165301
write32be(loc, (read32be(loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff));
166302
break;
167-
case R_SPARC_TLS_LE_LOX10:
168-
// T-simm13
169-
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1C00);
303+
case R_SPARC_GOTDATA_HIX22:
304+
// V-imm22
305+
checkUInt(ctx, loc, ((int64_t)val < 0 ? ~val : val), 32, rel);
306+
write32be(loc, (read32be(loc) & ~0x003fffff) |
307+
((((int64_t)val < 0 ? ~val : val) >> 10) & 0x003fffff));
308+
break;
309+
case R_SPARC_GOTDATA_OP_HIX22: // Not V-imm22, despite binutils behavior.
310+
// Non-relaxed case.
311+
// T-imm22
312+
write32be(loc, (read32be(loc) & ~0x003fffff) |
313+
((((int64_t)val < 0 ? ~val : val) >> 10) & 0x003fffff));
314+
break;
315+
case R_SPARC_GOTDATA_LOX10:
316+
case R_SPARC_GOTDATA_OP_LOX10: // Non-relaxed case.
317+
// T-imm13
318+
write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) |
319+
((int64_t)val < 0 ? 0x1c00 : 0));
320+
break;
321+
case R_SPARC_GOTDATA_OP: // Non-relaxed case.
322+
// word32
323+
// Nothing needs to be done in the non-relaxed case.
170324
break;
171325
default:
172326
llvm_unreachable("unknown relocation");
173327
}
174328
}
175329

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

0 commit comments

Comments
 (0)