ARMRelocator.cpp revision 6f75755c9204b1d8817ae5a65a2f7e5af0ec3f70
1//===- ARMRelocator.cpp  ----------------------------------------===//
2//
3//                     The MCLinker Project
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 <llvm/ADT/Twine.h>
11#include <llvm/Support/DataTypes.h>
12#include <llvm/Support/ELF.h>
13#include <llvm/Support/Host.h>
14#include <mcld/Support/MsgHandling.h>
15#include "ARMRelocator.h"
16#include "ARMRelocationFunctions.h"
17
18using namespace mcld;
19
20//===--------------------------------------------------------------------===//
21// Relocation Functions and Tables
22//===--------------------------------------------------------------------===//
23DECL_ARM_APPLY_RELOC_FUNCS
24
25/// the prototype of applying function
26typedef Relocator::Result (*ApplyFunctionType)(Relocation& pReloc,
27                                               ARMRelocator& pParent);
28
29// the table entry of applying functions
30struct ApplyFunctionTriple
31{
32  ApplyFunctionType func;
33  unsigned int type;
34  const char* name;
35};
36
37// declare the table of applying functions
38static const ApplyFunctionTriple ApplyFunctions[] = {
39  DECL_ARM_APPLY_RELOC_FUNC_PTRS
40};
41
42//===--------------------------------------------------------------------===//
43// ARMRelocator
44//===--------------------------------------------------------------------===//
45ARMRelocator::ARMRelocator(ARMGNULDBackend& pParent)
46  : Relocator(),
47    m_Target(pParent) {
48}
49
50ARMRelocator::~ARMRelocator()
51{
52}
53
54Relocator::Result
55ARMRelocator::applyRelocation(Relocation& pRelocation)
56{
57  Relocation::Type type = pRelocation.type();
58  if (type > 130) { // 131-255 doesn't noted in ARM spec
59    return Relocator::Unknown;
60  }
61
62  return ApplyFunctions[type].func(pRelocation, *this);
63}
64
65const char* ARMRelocator::getName(Relocator::Type pType) const
66{
67  return ApplyFunctions[pType].name;
68}
69
70Relocator::Size ARMRelocator::getSize(Relocation::Type pType) const
71{
72  return 32;
73}
74
75//===--------------------------------------------------------------------===//
76// non-member functions
77//===--------------------------------------------------------------------===//
78static Relocator::DWord getThumbBit(const Relocation& pReloc)
79{
80  // Set thumb bit if
81  // - symbol has type of STT_FUNC, is defined and with bit 0 of its value set
82  Relocator::DWord thumbBit =
83       ((!pReloc.symInfo()->isUndef() || pReloc.symInfo()->isDyn()) &&
84        (pReloc.symInfo()->type() == ResolveInfo::Function) &&
85        ((pReloc.symValue() & 0x1) != 0))?
86        1:0;
87  return thumbBit;
88}
89
90
91
92
93//=========================================//
94// Relocation helper function              //
95//=========================================//
96
97// Using uint64_t to make sure those complicate operations won't cause
98// undefined behavior.
99static
100uint64_t helper_sign_extend(uint64_t pVal, uint64_t pOri_width)
101{
102  assert(pOri_width <= 64);
103  uint64_t sign_bit = 1 << (pOri_width - 1);
104  return (pVal ^ sign_bit) - sign_bit;
105  // Reverse sign bit, then subtract sign bit.
106}
107
108static
109uint64_t helper_bit_select(uint64_t pA, uint64_t pB, uint64_t pMask)
110{
111  return (pA & ~pMask) | (pB & pMask) ;
112}
113
114// Check if symbol can use relocation R_ARM_RELATIVE
115static bool
116helper_use_relative_reloc(const ResolveInfo& pSym,
117                          const ARMRelocator& pFactory)
118{
119  // if symbol is dynamic or undefine or preemptible
120  if (pSym.isDyn() ||
121      pSym.isUndef() ||
122      pFactory.getTarget().isSymbolPreemptible(pSym))
123    return false;
124  return true;
125}
126
127static
128ARMGOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
129                                     ARMRelocator& pParent)
130{
131  // rsym - The relocation target symbol
132  ResolveInfo* rsym = pReloc.symInfo();
133  ARMGNULDBackend& ld_backend = pParent.getTarget();
134
135  ARMGOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
136  if (NULL == got_entry) {
137    got_entry = ld_backend.getGOT().consumeGOT();
138    pParent.getSymGOTMap().record(*rsym, *got_entry);
139    // If we first get this GOT entry, we should initialize it.
140    if (rsym->reserved() & ARMGNULDBackend::ReserveGOT) {
141      // No corresponding dynamic relocation, initialize to the symbol value.
142      got_entry->setValue(pReloc.symValue());
143    }
144    else if (rsym->reserved() & ARMGNULDBackend::GOTRel) {
145
146      // Initialize corresponding dynamic relocation.
147      Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
148      if ( rsym->isLocal() ||
149          helper_use_relative_reloc(*rsym, pParent)) {
150        // Initialize got entry to target symbol address
151        got_entry->setValue(pReloc.symValue());
152        rel_entry.setType(llvm::ELF::R_ARM_RELATIVE);
153        rel_entry.setSymInfo(0);
154      }
155      else {
156        // Initialize got entry to 0 for corresponding dynamic relocation.
157        got_entry->setValue(0);
158        rel_entry.setType(llvm::ELF::R_ARM_GLOB_DAT);
159        rel_entry.setSymInfo(rsym);
160      }
161      rel_entry.targetRef().assign(*got_entry);
162    }
163    else {
164      fatal(diag::reserve_entry_number_mismatch_got);
165    }
166  }
167  return *got_entry;
168}
169
170static
171ARMRelocator::Address helper_GOT_ORG(ARMRelocator& pParent)
172{
173  return pParent.getTarget().getGOT().addr();
174}
175
176
177static
178ARMRelocator::Address helper_GOT(Relocation& pReloc, ARMRelocator& pParent)
179{
180  ARMGOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
181  return helper_GOT_ORG(pParent) + got_entry.getOffset();
182}
183
184
185static
186ARMPLT1& helper_get_PLT_and_init(Relocation& pReloc, ARMRelocator& pParent)
187{
188  // rsym - The relocation target symbol
189  ResolveInfo* rsym = pReloc.symInfo();
190  ARMGNULDBackend& ld_backend = pParent.getTarget();
191
192  ARMPLT1* plt_entry = pParent.getSymPLTMap().lookUp(*rsym);
193  if (NULL != plt_entry)
194    return *plt_entry;
195
196  plt_entry = ld_backend.getPLT().consume();
197  pParent.getSymPLTMap().record(*rsym, *plt_entry);
198
199  // If we first get this PLT entry, we should initialize it.
200  if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
201    ARMGOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
202    assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!");
203    gotplt_entry = ld_backend.getGOT().consumeGOTPLT();
204    pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
205
206    // Initialize corresponding dynamic relocation.
207    Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry();
208    rel_entry.setType(llvm::ELF::R_ARM_JUMP_SLOT);
209    rel_entry.targetRef().assign(*gotplt_entry);
210    rel_entry.setSymInfo(rsym);
211  }
212  else {
213    fatal(diag::reserve_entry_number_mismatch_plt);
214  }
215
216  return *plt_entry;
217}
218
219static
220ARMRelocator::Address helper_PLT_ORG(ARMRelocator& pParent)
221{
222  return pParent.getTarget().getPLT().addr();
223}
224
225
226static
227ARMRelocator::Address helper_PLT(Relocation& pReloc, ARMRelocator& pParent)
228{
229  ARMPLT1& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
230  return helper_PLT_ORG(pParent) + plt_entry.getOffset();
231}
232
233// Get an relocation entry in .rel.dyn and set its type to pType,
234// its FragmentRef to pReloc->targetFrag() and its ResolveInfo to
235// pReloc->symInfo()
236static
237void helper_DynRel(Relocation& pReloc,
238                   ARMRelocator::Type pType,
239                   ARMRelocator& pParent)
240{
241  // rsym - The relocation target symbol
242  ResolveInfo* rsym = pReloc.symInfo();
243  ARMGNULDBackend& ld_backend = pParent.getTarget();
244
245  Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
246  rel_entry.setType(pType);
247  rel_entry.targetRef() = pReloc.targetRef();
248
249  if (pType == llvm::ELF::R_ARM_RELATIVE)
250    rel_entry.setSymInfo(0);
251  else
252    rel_entry.setSymInfo(rsym);
253}
254
255static ARMRelocator::DWord
256helper_extract_movw_movt_addend(ARMRelocator::DWord pTarget)
257{
258  // imm16: [19-16][11-0]
259  return helper_sign_extend((((pTarget >> 4)) & 0xf000U) | (pTarget & 0xfffU),
260                            16);
261}
262
263static ARMRelocator::DWord
264helper_insert_val_movw_movt_inst(ARMRelocator::DWord pTarget,
265                                 ARMRelocator::DWord pImm)
266{
267  // imm16: [19-16][11-0]
268  pTarget &= 0xfff0f000U;
269  pTarget |= pImm & 0x0fffU;
270  pTarget |= (pImm & 0xf000U) << 4;
271  return pTarget;
272}
273
274static ARMRelocator::DWord
275helper_extract_thumb_movw_movt_addend(ARMRelocator::DWord pValue)
276{
277  // imm16: [19-16][26][14-12][7-0]
278  return helper_sign_extend((((pValue >> 4) & 0xf000U) |
279                             ((pValue >> 15) & 0x0800U) |
280                             ((pValue >> 4) & 0x0700U) |
281                             (pValue& 0x00ffU)),
282                            16);
283}
284
285static ARMRelocator::DWord
286helper_insert_val_thumb_movw_movt_inst(ARMRelocator::DWord pValue,
287                                       ARMRelocator::DWord pImm)
288{
289  // imm16: [19-16][26][14-12][7-0]
290  pValue &= 0xfbf08f00U;
291  pValue |= (pImm & 0xf000U) << 4;
292  pValue |= (pImm & 0x0800U) << 15;
293  pValue |= (pImm & 0x0700U) << 4;
294  pValue |= (pImm & 0x00ffU);
295  return pValue;
296}
297
298static ARMRelocator::DWord
299helper_thumb32_branch_offset(ARMRelocator::DWord pUpper16,
300                             ARMRelocator::DWord pLower16)
301{
302  ARMRelocator::DWord s = (pUpper16 & (1U << 10)) >> 10,        // 26 bit
303                           u  = pUpper16 & 0x3ffU,              // 25-16
304                           l  = pLower16 & 0x7ffU,              // 10-0
305                           j1 = (pLower16 & (1U << 13)) >> 13,  // 13
306                           j2 = (pLower16 & (1U << 11)) >> 11;  // 11
307  ARMRelocator::DWord i1 = j1 ^ s? 0: 1,
308                              i2 = j2 ^ s? 0: 1;
309
310  // [31-25][24][23][22][21-12][11-1][0]
311  //      0   s  i1  i2      u     l  0
312  return helper_sign_extend((s << 24) | (i1 << 23) | (i2 << 22) |
313                            (u << 12) | (l << 1),
314                            25);
315}
316
317static ARMRelocator::DWord
318helper_thumb32_branch_upper(ARMRelocator::DWord pUpper16,
319                            ARMRelocator::DWord pOffset)
320{
321  uint32_t sign = ((pOffset & 0x80000000U) >> 31);
322  return (pUpper16 & ~0x7ffU) | ((pOffset >> 12) & 0x3ffU) | (sign << 10);
323}
324
325static ARMRelocator::DWord
326helper_thumb32_branch_lower(ARMRelocator::DWord pLower16,
327                            ARMRelocator::DWord pOffset)
328{
329  uint32_t sign = ((pOffset & 0x80000000U) >> 31);
330  return ((pLower16 & ~0x2fffU) |
331          ((((pOffset >> 23) & 1) ^ !sign) << 13) |
332          ((((pOffset >> 22) & 1) ^ !sign) << 11) |
333          ((pOffset >> 1) & 0x7ffU));
334}
335
336// Return true if overflow
337static bool
338helper_check_signed_overflow(ARMRelocator::DWord pValue,
339                             unsigned bits)
340{
341  int32_t signed_val = static_cast<int32_t>(pValue);
342  int32_t max = (1 << (bits - 1)) - 1;
343  int32_t min = -(1 << (bits - 1));
344  if (signed_val > max || signed_val < min) {
345    return true;
346  } else {
347    return false;
348  }
349}
350
351
352//=========================================//
353// Each relocation function implementation //
354//=========================================//
355
356// R_ARM_NONE
357ARMRelocator::Result none(Relocation& pReloc, ARMRelocator& pParent)
358{
359  return ARMRelocator::OK;
360}
361
362// R_ARM_ABS32: (S + A) | T
363ARMRelocator::Result abs32(Relocation& pReloc, ARMRelocator& pParent)
364{
365  ResolveInfo* rsym = pReloc.symInfo();
366  ARMRelocator::DWord T = getThumbBit(pReloc);
367  ARMRelocator::DWord A = pReloc.target() + pReloc.addend();
368  ARMRelocator::DWord S = pReloc.symValue();
369
370  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
371
372  // If the flag of target section is not ALLOC, we will not scan this relocation
373  // but perform static relocation. (e.g., applying .debug section)
374  if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
375    pReloc.target() = (S + A) | T;
376    return ARMRelocator::OK;
377  }
378
379  // A local symbol may need REL Type dynamic relocation
380  if (rsym->isLocal() && (rsym->reserved() & ARMGNULDBackend::ReserveRel)) {
381    helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
382    pReloc.target() = (S + A) | T ;
383    return ARMRelocator::OK;
384  }
385
386  // An external symbol may need PLT and dynamic relocation
387  if (!rsym->isLocal()) {
388    if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
389      S = helper_PLT(pReloc, pParent);
390      T = 0 ; // PLT is not thumb
391    }
392    // If we generate a dynamic relocation (except R_ARM_RELATIVE)
393    // for a place, we should not perform static relocation on it
394    // in order to keep the addend store in the place correct.
395    if (rsym->reserved() & ARMGNULDBackend::ReserveRel) {
396      if (helper_use_relative_reloc(*rsym, pParent)) {
397        helper_DynRel(pReloc, llvm::ELF::R_ARM_RELATIVE, pParent);
398      }
399      else {
400        helper_DynRel(pReloc, pReloc.type(), pParent);
401        return ARMRelocator::OK;
402      }
403    }
404  }
405
406
407  // perform static relocation
408  pReloc.target() = (S + A) | T;
409  return ARMRelocator::OK;
410}
411
412// R_ARM_REL32: ((S + A) | T) - P
413ARMRelocator::Result rel32(Relocation& pReloc, ARMRelocator& pParent)
414{
415  // perform static relocation
416  ARMRelocator::Address S = pReloc.symValue();
417  ARMRelocator::DWord   T = getThumbBit(pReloc);
418  ARMRelocator::DWord   A = pReloc.target() + pReloc.addend();
419
420  // An external symbol may need PLT (this reloc is from stub)
421  if (!pReloc.symInfo()->isLocal()) {
422    if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
423      S = helper_PLT(pReloc, pParent);
424      T = 0;  // PLT is not thumb.
425    }
426  }
427
428  // perform relocation
429  pReloc.target() = ((S + A) | T) - pReloc.place();
430
431  return ARMRelocator::OK;
432}
433
434// R_ARM_BASE_PREL: B(S) + A - P
435ARMRelocator::Result base_prel(Relocation& pReloc, ARMRelocator& pParent)
436{
437  // perform static relocation
438  ARMRelocator::DWord A = pReloc.target() + pReloc.addend();
439  pReloc.target() = pReloc.symValue() + A - pReloc.place();
440  return ARMRelocator::OK;
441}
442
443// R_ARM_GOTOFF32: ((S + A) | T) - GOT_ORG
444ARMRelocator::Result gotoff32(Relocation& pReloc, ARMRelocator& pParent)
445{
446  ARMRelocator::DWord T = getThumbBit(pReloc);
447  ARMRelocator::DWord A = pReloc.target() + pReloc.addend();
448  ARMRelocator::Address GOT_ORG = helper_GOT_ORG(pParent);
449  ARMRelocator::Address S = pReloc.symValue();
450
451  pReloc.target() = ((S + A) | T) - GOT_ORG;
452  return ARMRelocator::OK;
453}
454
455// R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG
456ARMRelocator::Result got_brel(Relocation& pReloc, ARMRelocator& pParent)
457{
458  if (!(pReloc.symInfo()->reserved() &
459      (ARMGNULDBackend::ReserveGOT | ARMGNULDBackend::GOTRel))) {
460    return ARMRelocator::BadReloc;
461  }
462  ARMRelocator::Address GOT_S   = helper_GOT(pReloc, pParent);
463  ARMRelocator::DWord   A       = pReloc.target() + pReloc.addend();
464  ARMRelocator::Address GOT_ORG = helper_GOT_ORG(pParent);
465  // Apply relocation.
466  pReloc.target() = GOT_S + A - GOT_ORG;
467  return ARMRelocator::OK;
468}
469
470// R_ARM_GOT_PREL: GOT(S) + A - P
471ARMRelocator::Result got_prel(Relocation& pReloc, ARMRelocator& pParent)
472{
473  if (!(pReloc.symInfo()->reserved() &
474      (ARMGNULDBackend::ReserveGOT | ARMGNULDBackend::GOTRel))) {
475    return ARMRelocator::BadReloc;
476  }
477  ARMRelocator::Address GOT_S   = helper_GOT(pReloc, pParent);
478  ARMRelocator::DWord   A       = pReloc.target() + pReloc.addend();
479  ARMRelocator::Address P = pReloc.place();
480
481  // Apply relocation.
482  pReloc.target() = GOT_S + A - P;
483  return ARMRelocator::OK;
484}
485
486// R_ARM_PLT32: ((S + A) | T) - P
487// R_ARM_JUMP24: ((S + A) | T) - P
488// R_ARM_CALL: ((S + A) | T) - P
489ARMRelocator::Result call(Relocation& pReloc, ARMRelocator& pParent)
490{
491  // If target is undefined weak symbol, we only need to jump to the
492  // next instruction unless it has PLT entry. Rewrite instruction
493  // to NOP.
494  if (pReloc.symInfo()->isWeak() &&
495      pReloc.symInfo()->isUndef() &&
496      !pReloc.symInfo()->isDyn() &&
497      !(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
498    // change target to NOP : mov r0, r0
499    pReloc.target() = (pReloc.target() & 0xf0000000U) | 0x01a00000;
500    return ARMRelocator::OK;
501  }
502
503  ARMRelocator::Address S; // S depends on PLT exists or not.
504  ARMRelocator::DWord   T = getThumbBit(pReloc);
505  ARMRelocator::DWord   A =
506    helper_sign_extend((pReloc.target() & 0x00FFFFFFu) << 2, 26)
507    + pReloc.addend();
508  ARMRelocator::Address P = pReloc.place();
509
510  S = pReloc.symValue();
511  if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
512    S = helper_PLT(pReloc, pParent);
513    T = 0;  // PLT is not thumb.
514  }
515
516  // At this moment (after relaxation), if the jump target is thumb instruction,
517  // switch mode is needed, rewrite the instruction to BLX
518  // FIXME: check if we can use BLX instruction (check from .ARM.attribute
519  // CPU ARCH TAG, which should be ARMv5 or above)
520  if (T != 0) {
521    // cannot rewrite to blx for R_ARM_JUMP24
522    if (pReloc.type() == llvm::ELF::R_ARM_JUMP24)
523      return ARMRelocator::BadReloc;
524
525    pReloc.target() = (pReloc.target() & 0xffffff) |
526                      0xfa000000 |
527                      (((S + A - P) & 2) << 23);
528  }
529
530  ARMRelocator::DWord X = ((S + A) | T) - P;
531  // Check X is 24bit sign int. If not, we should use stub or PLT before apply.
532  if (helper_check_signed_overflow(X, 26))
533    return ARMRelocator::Overflow;
534  //                    Make sure the Imm is 0.          Result Mask.
535  pReloc.target() = (pReloc.target() & 0xFF000000u) | ((X & 0x03FFFFFEu) >> 2);
536  return ARMRelocator::OK;
537}
538
539// R_ARM_THM_CALL: ((S + A) | T) - P
540// R_ARM_THM_JUMP24: (((S + A) | T) - P)
541ARMRelocator::Result thm_call(Relocation& pReloc, ARMRelocator& pParent)
542{
543  // If target is undefined weak symbol, we only need to jump to the
544  // next instruction unless it has PLT entry. Rewrite instruction
545  // to NOP.
546  if (pReloc.symInfo()->isWeak() &&
547      pReloc.symInfo()->isUndef() &&
548      !pReloc.symInfo()->isDyn() &&
549      !(pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT)) {
550    pReloc.target() = (0xe000U << 16) | 0xbf00U;
551    return ARMRelocator::OK;
552  }
553
554  // get lower and upper 16 bit instructions from relocation targetData
555  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
556  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
557
558  ARMRelocator::DWord T = getThumbBit(pReloc);
559  ARMRelocator::DWord A = helper_thumb32_branch_offset(upper_inst,
560                                                               lower_inst);
561  ARMRelocator::Address P = pReloc.place();
562  ARMRelocator::Address S;
563
564  // if symbol has plt
565  if (pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
566    S = helper_PLT(pReloc, pParent);
567    T = 0;  // PLT is not thumb.
568  }
569  else {
570    S = pReloc.symValue();
571  }
572
573  S = S + A;
574
575  // At this moment (after relaxation), if the jump target is arm
576  // instruction, switch mode is needed, rewrite the instruction to BLX
577  // FIXME: check if we can use BLX instruction (check from .ARM.attribute
578  // CPU ARCH TAG, which should be ARMv5 or above)
579  if (T == 0) {
580    // cannot rewrite to blx for R_ARM_THM_JUMP24
581    if (pReloc.type() == llvm::ELF::R_ARM_THM_JUMP24)
582      return ARMRelocator::BadReloc;
583
584    // for BLX, select bit 1 from relocation base address to jump target
585    // address
586    S = helper_bit_select(S, P, 0x2);
587    // rewrite instruction to BLX
588    lower_inst &= ~0x1000U;
589  }
590  else {
591    // otherwise, the instruction should be BL
592    lower_inst |= 0x1000U;
593  }
594
595  ARMRelocator::DWord X = (S | T) - P;
596
597  // FIXME: Check bit size is 24(thumb2) or 22?
598  if (helper_check_signed_overflow(X, 25)) {
599    return ARMRelocator::Overflow;
600  }
601
602  upper_inst = helper_thumb32_branch_upper(upper_inst, X);
603  lower_inst = helper_thumb32_branch_lower(lower_inst, X);
604
605  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
606  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
607
608  return ARMRelocator::OK;
609}
610
611// R_ARM_MOVW_ABS_NC: (S + A) | T
612ARMRelocator::Result movw_abs_nc(Relocation& pReloc, ARMRelocator& pParent)
613{
614  ResolveInfo* rsym = pReloc.symInfo();
615  ARMRelocator::Address S = pReloc.symValue();
616  ARMRelocator::DWord T = getThumbBit(pReloc);
617  ARMRelocator::DWord A =
618      helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
619  ARMRelocator::DWord X;
620
621  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
622
623  // If the flag of target section is not ALLOC, we will not scan this
624  // relocation but perform static relocation. (e.g., applying .debug section)
625  if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
626    // use plt
627    if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
628      S = helper_PLT(pReloc, pParent);
629      T = 0 ; // PLT is not thumb
630    }
631  }
632
633  // perform static relocation
634  X = (S + A) | T;
635  pReloc.target() = helper_insert_val_movw_movt_inst(
636                                         pReloc.target() + pReloc.addend(), X);
637  return ARMRelocator::OK;
638}
639
640// R_ARM_MOVW_PREL_NC: ((S + A) | T) - P
641ARMRelocator::Result movw_prel_nc(Relocation& pReloc, ARMRelocator& pParent)
642{
643  ARMRelocator::Address S = pReloc.symValue();
644  ARMRelocator::DWord T = getThumbBit(pReloc);
645  ARMRelocator::DWord P = pReloc.place();
646  ARMRelocator::DWord A =
647      helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
648  ARMRelocator::DWord X;
649
650  X = ((S + A) | T) - P;
651
652  if (helper_check_signed_overflow(X, 16)) {
653    return ARMRelocator::Overflow;
654  } else {
655    pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
656    return ARMRelocator::OK;
657  }
658}
659
660// R_ARM_MOVT_ABS: S + A
661ARMRelocator::Result movt_abs(Relocation& pReloc, ARMRelocator& pParent)
662{
663  ResolveInfo* rsym = pReloc.symInfo();
664  ARMRelocator::Address S = pReloc.symValue();
665  ARMRelocator::DWord A =
666    helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
667  ARMRelocator::DWord X;
668
669  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
670
671  // If the flag of target section is not ALLOC, we will not scan this relocation
672  // but perform static relocation. (e.g., applying .debug section)
673  if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
674    // use plt
675    if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
676      S = helper_PLT(pReloc, pParent);
677    }
678  }
679
680  X = S + A;
681  X >>= 16;
682  // perform static relocation
683  pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
684  return ARMRelocator::OK;
685}
686
687// R_ARM_MOVT_PREL: S + A - P
688ARMRelocator::Result movt_prel(Relocation& pReloc, ARMRelocator& pParent)
689{
690  ARMRelocator::Address S = pReloc.symValue();
691  ARMRelocator::DWord P = pReloc.place();
692  ARMRelocator::DWord A =
693            helper_extract_movw_movt_addend(pReloc.target()) + pReloc.addend();
694  ARMRelocator::DWord X;
695
696  X = S + A - P;
697  X >>= 16;
698
699  pReloc.target() = helper_insert_val_movw_movt_inst(pReloc.target(), X);
700  return ARMRelocator::OK;
701}
702
703// R_ARM_THM_MOVW_ABS_NC: (S + A) | T
704ARMRelocator::Result thm_movw_abs_nc(Relocation& pReloc, ARMRelocator& pParent)
705{
706  ResolveInfo* rsym = pReloc.symInfo();
707  ARMRelocator::Address S = pReloc.symValue();
708  ARMRelocator::DWord T = getThumbBit(pReloc);
709
710  // get lower and upper 16 bit instructions from relocation targetData
711  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
712  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
713  ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst);
714  ARMRelocator::DWord A =
715      helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
716  ARMRelocator::DWord X;
717
718  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
719  // If the flag of target section is not ALLOC, we will not scan this relocation
720  // but perform static relocation. (e.g., applying .debug section)
721  if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
722    // use plt
723    if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
724      S = helper_PLT(pReloc, pParent);
725      T = 0; // PLT is not thumb
726    }
727  }
728  X = (S + A) | T;
729
730  val = helper_insert_val_thumb_movw_movt_inst(val, X);
731  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
732  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
733
734  return ARMRelocator::OK;
735}
736
737// R_ARM_THM_MOVW_PREL_NC: ((S + A) | T) - P
738ARMRelocator::Result thm_movw_prel_nc(Relocation& pReloc, ARMRelocator& pParent)
739{
740  ARMRelocator::Address S = pReloc.symValue();
741  ARMRelocator::DWord T = getThumbBit(pReloc);
742  ARMRelocator::DWord P = pReloc.place();
743
744  // get lower and upper 16 bit instructions from relocation targetData
745  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
746  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
747  ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst);
748  ARMRelocator::DWord A =
749      helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
750  ARMRelocator::DWord X;
751
752  X = ((S + A) | T) - P;
753
754  val = helper_insert_val_thumb_movw_movt_inst(val, X);
755  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
756  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
757
758  return ARMRelocator::OK;
759}
760
761// R_ARM_THM_MOVW_BREL_NC: ((S + A) | T) - B(S)
762// R_ARM_THM_MOVW_BREL: ((S + A) | T) - B(S)
763ARMRelocator::Result thm_movw_brel(Relocation& pReloc, ARMRelocator& pParent)
764{
765  ARMRelocator::Address S = pReloc.symValue();
766  ARMRelocator::DWord T = getThumbBit(pReloc);
767  ARMRelocator::DWord P = pReloc.place();
768
769  // get lower and upper 16 bit instructions from relocation targetData
770  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
771  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
772  ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst);
773  ARMRelocator::DWord A =
774      helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
775  ARMRelocator::DWord X;
776
777  X = ((S + A) | T) - P;
778
779  val = helper_insert_val_thumb_movw_movt_inst(val, X);
780  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
781  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
782
783  return ARMRelocator::OK;
784}
785
786// R_ARM_THM_MOVT_ABS: S + A
787ARMRelocator::Result thm_movt_abs(Relocation& pReloc, ARMRelocator& pParent)
788{
789  ResolveInfo* rsym = pReloc.symInfo();
790  ARMRelocator::Address S = pReloc.symValue();
791
792  // get lower and upper 16 bit instructions from relocation targetData
793  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
794  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
795  ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst);
796  ARMRelocator::DWord A =
797      helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
798  ARMRelocator::DWord X;
799
800  LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
801  // If the flag of target section is not ALLOC, we will not scan this relocation
802  // but perform static relocation. (e.g., applying .debug section)
803  if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
804    // use plt
805    if (rsym->reserved() & ARMGNULDBackend::ReservePLT) {
806      S = helper_PLT(pReloc, pParent);
807    }
808  }
809
810  X = S + A;
811  X >>= 16;
812
813  // check 16-bit overflow
814  if (helper_check_signed_overflow(X, 16)) {
815    return ARMRelocator::Overflow;
816  } else {
817    val = helper_insert_val_thumb_movw_movt_inst(val, X);
818    *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
819    *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
820    return ARMRelocator::OK;
821  }
822}
823
824// R_ARM_THM_MOVT_PREL: S + A - P
825// R_ARM_THM_MOVT_BREL: S + A - B(S)
826ARMRelocator::Result thm_movt_prel(Relocation& pReloc, ARMRelocator& pParent)
827{
828  ARMRelocator::Address S = pReloc.symValue();
829  ARMRelocator::DWord P = pReloc.place();
830
831  // get lower and upper 16 bit instructions from relocation targetData
832  uint16_t upper_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()));
833  uint16_t lower_inst = *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1);
834  ARMRelocator::DWord val = ((upper_inst) << 16) | (lower_inst);
835  ARMRelocator::DWord A =
836      helper_extract_thumb_movw_movt_addend(val) + pReloc.addend();
837  ARMRelocator::DWord X;
838
839  X = S + A - P;
840  X >>= 16;
841
842  val = helper_insert_val_thumb_movw_movt_inst(val, X);
843  *(reinterpret_cast<uint16_t*>(&pReloc.target())) = upper_inst;
844  *(reinterpret_cast<uint16_t*>(&pReloc.target()) + 1) = lower_inst;
845
846  return ARMRelocator::OK;
847}
848
849// R_ARM_PREL31: ((S + A) | T) - P
850ARMRelocator::Result prel31(Relocation& pReloc, ARMRelocator& pParent)
851{
852  ARMRelocator::DWord target = pReloc.target();
853  ARMRelocator::DWord T = getThumbBit(pReloc);
854  ARMRelocator::DWord A = helper_sign_extend(target, 31) +
855                                  pReloc.addend();
856  ARMRelocator::DWord P = pReloc.place();
857  ARMRelocator::Address S;
858
859  S = pReloc.symValue();
860  // if symbol has plt
861  if ( pReloc.symInfo()->reserved() & ARMGNULDBackend::ReservePLT) {
862    S = helper_PLT(pReloc, pParent);
863    T = 0;  // PLT is not thumb.
864  }
865
866  ARMRelocator::DWord X = ((S + A) | T) - P;
867  pReloc.target() = helper_bit_select(target, X, 0x7fffffffU);
868  if (helper_check_signed_overflow(X, 31))
869    return ARMRelocator::Overflow;
870  return ARMRelocator::OK;
871}
872
873// R_ARM_TLS_GD32: GOT(S) + A - P
874// R_ARM_TLS_IE32: GOT(S) + A - P
875// R_ARM_TLS_LE32: S + A - tp
876ARMRelocator::Result tls(Relocation& pReloc, ARMRelocator& pParent)
877{
878  return ARMRelocator::Unsupport;
879}
880
881ARMRelocator::Result unsupport(Relocation& pReloc, ARMRelocator& pParent)
882{
883  return ARMRelocator::Unsupport;
884}
885