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 | |
14 | using namespace llvm; |
15 | using namespace llvm::support::endian; |
16 | using namespace llvm::ELF; |
17 | using namespace lld; |
18 | using namespace lld::elf; |
19 | |
20 | namespace { |
21 | class SPARCV9 final : public TargetInfo { |
22 | public: |
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 | |
33 | SPARCV9::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 | |
47 | RelExpr 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 | |
86 | void 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 | |
176 | void 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 | |
195 | void elf::setSPARCV9TargetInfo(Ctx &ctx) { ctx.target.reset(p: new SPARCV9(ctx)); } |
196 | |