]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp
Vendor import of lld trunk r233088:
[FreeBSD/FreeBSD.git] / lib / ReaderWriter / ELF / Hexagon / HexagonRelocationHandler.cpp
1 //===- lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp ---------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "HexagonLinkingContext.h"
11 #include "HexagonRelocationFunctions.h"
12 #include "HexagonTargetHandler.h"
13 #include "HexagonRelocationHandler.h"
14 #include "llvm/Support/Endian.h"
15
16 using namespace lld;
17 using namespace lld::elf;
18 using namespace llvm::ELF;
19 using namespace llvm::support::endian;
20
21 #define APPLY_RELOC(result)                                                    \
22   write32le(location, result | read32le(location));
23
24 static int relocBNPCREL(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
25                         int32_t nBits) {
26   int32_t result = (uint32_t)(((S + A) - P) >> 2);
27   int32_t range = 1 << nBits;
28   if (result < range && result > -range) {
29     result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
30     APPLY_RELOC(result);
31     return 0;
32   }
33   return 1;
34 }
35
36 /// \brief Word32_LO: 0x00c03fff : (S + A) : Truncate
37 static int relocLO16(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
38   uint32_t result = (uint32_t)(S + A);
39   result = lld::scatterBits<int32_t>(result, 0x00c03fff);
40   APPLY_RELOC(result);
41   return 0;
42 }
43
44 /// \brief Word32_LO: 0x00c03fff : (S + A) >> 16 : Truncate
45 static int relocHI16(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
46   uint32_t result = (uint32_t)((S + A) >> 16);
47   result = lld::scatterBits<int32_t>(result, 0x00c03fff);
48   APPLY_RELOC(result);
49   return 0;
50 }
51
52 /// \brief Word32: 0xffffffff : (S + A) : Truncate
53 static int reloc32(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
54   uint32_t result = (uint32_t)(S + A);
55   APPLY_RELOC(result);
56   return 0;
57 }
58
59 static int reloc32_6_X(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
60   int64_t result = ((S + A) >> 6);
61   int64_t range = ((int64_t)1) << 32;
62   if (result > range)
63     return 1;
64   result = lld::scatterBits<int32_t>(result, 0xfff3fff);
65   APPLY_RELOC(result);
66   return 0;
67 }
68
69 // R_HEX_B32_PCREL_X
70 static int relocHexB32PCRELX(uint8_t *location, uint64_t P, uint64_t S,
71                              uint64_t A) {
72   int64_t result = ((S + A - P) >> 6);
73   result = lld::scatterBits<int32_t>(result, 0xfff3fff);
74   APPLY_RELOC(result);
75   return 0;
76 }
77
78 // R_HEX_BN_PCREL_X
79 static int relocHexBNPCRELX(uint8_t *location, uint64_t P, uint64_t S,
80                             uint64_t A, int nbits) {
81   int32_t result = ((S + A - P) & 0x3f);
82   int32_t range = 1 << nbits;
83   if (result < range && result > -range) {
84     result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
85     APPLY_RELOC(result);
86     return 0;
87   }
88   return 1;
89 }
90
91 // R_HEX_6_PCREL_X
92 static int relocHex6PCRELX(uint8_t *location, uint64_t P, uint64_t S,
93                            uint64_t A) {
94   int32_t result = (S + A - P);
95   result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
96   APPLY_RELOC(result);
97   return 0;
98 }
99
100 // R_HEX_N_X : Word32_U6 : (S + A) : Unsigned Truncate
101 static int relocHex_N_X(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
102   uint32_t result = (S + A);
103   result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
104   APPLY_RELOC(result);
105   return 0;
106 }
107
108 // GP REL relocations
109 static int relocHexGPRELN(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
110                           uint64_t GP, int nShiftBits) {
111   int32_t result = (int64_t)((S + A - GP) >> nShiftBits);
112   int32_t range = 1L << 16;
113   if (result <= range) {
114     result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
115     APPLY_RELOC(result);
116     return 0;
117   }
118   return 1;
119 }
120
121 /// \brief Word32_LO: 0x00c03fff : (G) : Truncate
122 static int relocHexGOTLO16(uint8_t *location, uint64_t A, uint64_t GOT) {
123   int32_t result = (int32_t)(A-GOT);
124   result = lld::scatterBits<int32_t>(result, 0x00c03fff);
125   APPLY_RELOC(result);
126   return 0;
127 }
128
129 /// \brief Word32_LO: 0x00c03fff : (G) >> 16 : Truncate
130 static int relocHexGOTHI16(uint8_t *location, uint64_t A, uint64_t GOT) {
131   int32_t result = (int32_t)((A-GOT) >> 16);
132   result = lld::scatterBits<int32_t>(result, 0x00c03fff);
133   APPLY_RELOC(result);
134   return 0;
135 }
136
137 /// \brief Word32: 0xffffffff : (G) : Truncate
138 static int relocHexGOT32(uint8_t *location, uint64_t A, uint64_t GOT) {
139   int32_t result = (int32_t)(GOT - A);
140   APPLY_RELOC(result);
141   return 0;
142 }
143
144 /// \brief Word32_U16 : (G) : Truncate
145 static int relocHexGOT16(uint8_t *location, uint64_t A, uint64_t GOT) {
146   int32_t result = (int32_t)(GOT-A);
147   int32_t range = 1L << 16;
148   if (result <= range) {
149     result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
150     APPLY_RELOC(result);
151     return 0;
152   }
153   return 1;
154 }
155
156 static int relocHexGOT32_6_X(uint8_t *location, uint64_t A, uint64_t GOT) {
157   int32_t result = (int32_t)((A-GOT) >> 6);
158   result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
159   APPLY_RELOC(result);
160   return 0;
161 }
162
163 static int relocHexGOT16_X(uint8_t *location, uint64_t A, uint64_t GOT) {
164   int32_t result = (int32_t)(A-GOT);
165   int32_t range = 1L << 6;
166   if (result <= range) {
167     result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
168     APPLY_RELOC(result);
169     return 0;
170   }
171   return 1;
172 }
173
174 static int relocHexGOT11_X(uint8_t *location, uint64_t A, uint64_t GOT) {
175   uint32_t result = (uint32_t)(A-GOT);
176   result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
177   APPLY_RELOC(result);
178   return 0;
179 }
180
181 static int relocHexGOTRELSigned(uint8_t *location, uint64_t P, uint64_t S,
182                                 uint64_t A, uint64_t GOT, int shiftBits = 0) {
183   int32_t result = (int32_t)((S + A - GOT) >> shiftBits);
184   result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
185   APPLY_RELOC(result);
186   return 0;
187 }
188
189 static int relocHexGOTRELUnsigned(uint8_t *location, uint64_t P, uint64_t S,
190                                   uint64_t A, uint64_t GOT, int shiftBits = 0) {
191   uint32_t result = (uint32_t)((S + A - GOT) >> shiftBits);
192   result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
193   APPLY_RELOC(result);
194   return 0;
195 }
196
197 static int relocHexGOTREL_HILO16(uint8_t *location, uint64_t P, uint64_t S,
198                                  uint64_t A, uint64_t GOT, int shiftBits = 0) {
199   int32_t result = (int32_t)((S + A - GOT) >> shiftBits);
200   result = lld::scatterBits<int32_t>(result, 0x00c03fff);
201   APPLY_RELOC(result);
202   return 0;
203 }
204
205 static int relocHexGOTREL_32(uint8_t *location, uint64_t P, uint64_t S,
206                              uint64_t A, uint64_t GOT) {
207   int32_t result = (int32_t)(S + A - GOT);
208   APPLY_RELOC(result);
209   return 0;
210 }
211
212 std::error_code HexagonTargetRelocationHandler::applyRelocation(
213     ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
214     const Reference &ref) const {
215   uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
216   uint8_t *location = atomContent + ref.offsetInAtom();
217   uint64_t targetVAddress = writer.addressOfAtom(ref.target());
218   uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
219
220   if (ref.kindNamespace() != Reference::KindNamespace::ELF)
221     return std::error_code();
222   assert(ref.kindArch() == Reference::KindArch::Hexagon);
223   switch (ref.kindValue()) {
224   case R_HEX_B22_PCREL:
225     relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 21);
226     break;
227   case R_HEX_B15_PCREL:
228     relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 14);
229     break;
230   case R_HEX_B9_PCREL:
231     relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 8);
232     break;
233   case R_HEX_LO16:
234     relocLO16(location, relocVAddress, targetVAddress, ref.addend());
235     break;
236   case R_HEX_HI16:
237     relocHI16(location, relocVAddress, targetVAddress, ref.addend());
238     break;
239   case R_HEX_32:
240     reloc32(location, relocVAddress, targetVAddress, ref.addend());
241     break;
242   case R_HEX_32_6_X:
243     reloc32_6_X(location, relocVAddress, targetVAddress, ref.addend());
244     break;
245   case R_HEX_B32_PCREL_X:
246     relocHexB32PCRELX(location, relocVAddress, targetVAddress, ref.addend());
247     break;
248   case R_HEX_B22_PCREL_X:
249     relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 21);
250     break;
251   case R_HEX_B15_PCREL_X:
252     relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 14);
253     break;
254   case R_HEX_B13_PCREL_X:
255     relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 12);
256     break;
257   case R_HEX_B9_PCREL_X:
258     relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 8);
259     break;
260   case R_HEX_B7_PCREL_X:
261     relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 6);
262     break;
263   case R_HEX_GPREL16_0:
264     relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
265                    _hexagonTargetLayout.getSDataSection()->virtualAddr(), 0);
266     break;
267   case R_HEX_GPREL16_1:
268     relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
269                    _hexagonTargetLayout.getSDataSection()->virtualAddr(), 1);
270     break;
271   case R_HEX_GPREL16_2:
272     relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
273                    _hexagonTargetLayout.getSDataSection()->virtualAddr(), 2);
274     break;
275   case R_HEX_GPREL16_3:
276     relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
277                    _hexagonTargetLayout.getSDataSection()->virtualAddr(), 3);
278     break;
279   case R_HEX_16_X:
280   case R_HEX_12_X:
281   case R_HEX_11_X:
282   case R_HEX_10_X:
283   case R_HEX_9_X:
284   case R_HEX_8_X:
285   case R_HEX_7_X:
286   case R_HEX_6_X:
287     relocHex_N_X(location, relocVAddress, targetVAddress, ref.addend());
288     break;
289   case R_HEX_6_PCREL_X:
290     relocHex6PCRELX(location, relocVAddress, targetVAddress, ref.addend());
291     break;
292   case R_HEX_JMP_SLOT:
293   case R_HEX_GLOB_DAT:
294     break;
295   case R_HEX_GOTREL_32:
296     relocHexGOTREL_32(location, relocVAddress, targetVAddress, ref.addend(),
297                       _hexagonTargetLayout.getGOTSymAddr());
298     break;
299   case R_HEX_GOTREL_LO16:
300     relocHexGOTREL_HILO16(location, relocVAddress, targetVAddress, ref.addend(),
301                           _hexagonTargetLayout.getGOTSymAddr());
302     break;
303   case R_HEX_GOTREL_HI16:
304     relocHexGOTREL_HILO16(location, relocVAddress, targetVAddress, ref.addend(),
305                           _hexagonTargetLayout.getGOTSymAddr(), 16);
306     break;
307   case R_HEX_GOT_LO16:
308     relocHexGOTLO16(location, targetVAddress,
309                     _hexagonTargetLayout.getGOTSymAddr());
310     break;
311   case R_HEX_GOT_HI16:
312     relocHexGOTHI16(location, targetVAddress,
313                     _hexagonTargetLayout.getGOTSymAddr());
314     break;
315   case R_HEX_GOT_32:
316     relocHexGOT32(location, targetVAddress,
317                   _hexagonTargetLayout.getGOTSymAddr());
318     break;
319   case R_HEX_GOT_16:
320     relocHexGOT16(location, targetVAddress,
321                   _hexagonTargetLayout.getGOTSymAddr());
322     break;
323   case R_HEX_GOT_32_6_X:
324     relocHexGOT32_6_X(location, targetVAddress,
325                       _hexagonTargetLayout.getGOTSymAddr());
326     break;
327   case R_HEX_GOT_16_X:
328     relocHexGOT16_X(location, targetVAddress,
329                     _hexagonTargetLayout.getGOTSymAddr());
330     break;
331   case R_HEX_GOT_11_X:
332     relocHexGOT11_X(location, targetVAddress,
333                     _hexagonTargetLayout.getGOTSymAddr());
334     break;
335   case R_HEX_GOTREL_32_6_X:
336     relocHexGOTRELSigned(location, relocVAddress, targetVAddress, ref.addend(),
337                          _hexagonTargetLayout.getGOTSymAddr(), 6);
338     break;
339   case R_HEX_GOTREL_16_X:
340   case R_HEX_GOTREL_11_X:
341     relocHexGOTRELUnsigned(location, relocVAddress, targetVAddress,
342                            ref.addend(), _hexagonTargetLayout.getGOTSymAddr());
343     break;
344
345   default:
346     return make_unhandled_reloc_error();
347   }
348
349   return std::error_code();
350 }