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