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