1 //===- lib/ReaderWriter/ELF/Hexagon/HexagonRelocationHandler.cpp ---------===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "HexagonLinkingContext.h"
11 #include "HexagonRelocationFunctions.h"
12 #include "HexagonTargetHandler.h"
13 #include "HexagonRelocationHandler.h"
14 #include "llvm/Support/Endian.h"
17 using namespace lld::elf;
18 using namespace llvm::ELF;
19 using namespace llvm::support::endian;
21 #define APPLY_RELOC(result) \
22 write32le(location, result | read32le(location));
24 static int relocBNPCREL(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
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));
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);
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);
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);
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;
64 result = lld::scatterBits<int32_t>(result, 0xfff3fff);
70 static int relocHexB32PCRELX(uint8_t *location, uint64_t P, uint64_t S,
72 int64_t result = ((S + A - P) >> 6);
73 result = lld::scatterBits<int32_t>(result, 0xfff3fff);
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));
92 static int relocHex6PCRELX(uint8_t *location, uint64_t P, uint64_t S,
94 int32_t result = (S + A - P);
95 result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
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));
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));
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);
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);
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);
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));
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));
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));
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));
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));
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));
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);
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);
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();
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);
227 case R_HEX_B15_PCREL:
228 relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 14);
231 relocBNPCREL(location, relocVAddress, targetVAddress, ref.addend(), 8);
234 relocLO16(location, relocVAddress, targetVAddress, ref.addend());
237 relocHI16(location, relocVAddress, targetVAddress, ref.addend());
240 reloc32(location, relocVAddress, targetVAddress, ref.addend());
243 reloc32_6_X(location, relocVAddress, targetVAddress, ref.addend());
245 case R_HEX_B32_PCREL_X:
246 relocHexB32PCRELX(location, relocVAddress, targetVAddress, ref.addend());
248 case R_HEX_B22_PCREL_X:
249 relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 21);
251 case R_HEX_B15_PCREL_X:
252 relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 14);
254 case R_HEX_B13_PCREL_X:
255 relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 12);
257 case R_HEX_B9_PCREL_X:
258 relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 8);
260 case R_HEX_B7_PCREL_X:
261 relocHexBNPCRELX(location, relocVAddress, targetVAddress, ref.addend(), 6);
263 case R_HEX_GPREL16_0:
264 relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
265 _hexagonTargetLayout.getSDataSection()->virtualAddr(), 0);
267 case R_HEX_GPREL16_1:
268 relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
269 _hexagonTargetLayout.getSDataSection()->virtualAddr(), 1);
271 case R_HEX_GPREL16_2:
272 relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
273 _hexagonTargetLayout.getSDataSection()->virtualAddr(), 2);
275 case R_HEX_GPREL16_3:
276 relocHexGPRELN(location, relocVAddress, targetVAddress, ref.addend(),
277 _hexagonTargetLayout.getSDataSection()->virtualAddr(), 3);
287 relocHex_N_X(location, relocVAddress, targetVAddress, ref.addend());
289 case R_HEX_6_PCREL_X:
290 relocHex6PCRELX(location, relocVAddress, targetVAddress, ref.addend());
295 case R_HEX_GOTREL_32:
296 relocHexGOTREL_32(location, relocVAddress, targetVAddress, ref.addend(),
297 _hexagonTargetLayout.getGOTSymAddr());
299 case R_HEX_GOTREL_LO16:
300 relocHexGOTREL_HILO16(location, relocVAddress, targetVAddress, ref.addend(),
301 _hexagonTargetLayout.getGOTSymAddr());
303 case R_HEX_GOTREL_HI16:
304 relocHexGOTREL_HILO16(location, relocVAddress, targetVAddress, ref.addend(),
305 _hexagonTargetLayout.getGOTSymAddr(), 16);
308 relocHexGOTLO16(location, targetVAddress,
309 _hexagonTargetLayout.getGOTSymAddr());
312 relocHexGOTHI16(location, targetVAddress,
313 _hexagonTargetLayout.getGOTSymAddr());
316 relocHexGOT32(location, targetVAddress,
317 _hexagonTargetLayout.getGOTSymAddr());
320 relocHexGOT16(location, targetVAddress,
321 _hexagonTargetLayout.getGOTSymAddr());
323 case R_HEX_GOT_32_6_X:
324 relocHexGOT32_6_X(location, targetVAddress,
325 _hexagonTargetLayout.getGOTSymAddr());
328 relocHexGOT16_X(location, targetVAddress,
329 _hexagonTargetLayout.getGOTSymAddr());
332 relocHexGOT11_X(location, targetVAddress,
333 _hexagonTargetLayout.getGOTSymAddr());
335 case R_HEX_GOTREL_32_6_X:
336 relocHexGOTRELSigned(location, relocVAddress, targetVAddress, ref.addend(),
337 _hexagonTargetLayout.getGOTSymAddr(), 6);
339 case R_HEX_GOTREL_16_X:
340 case R_HEX_GOTREL_11_X:
341 relocHexGOTRELUnsigned(location, relocVAddress, targetVAddress,
342 ref.addend(), _hexagonTargetLayout.getGOTSymAddr());
346 return make_unhandled_reloc_error();
349 return std::error_code();