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