• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- X86Relocator.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 #include "X86Relocator.h"
10 #include "X86RelocationFunctions.h"
11 
12 #include <mcld/Support/MsgHandling.h>
13 #include <mcld/LD/LDSymbol.h>
14 
15 #include <llvm/ADT/Twine.h>
16 #include <llvm/Support/DataTypes.h>
17 #include <llvm/Support/ELF.h>
18 
19 using namespace mcld;
20 
21 //===--------------------------------------------------------------------===//
22 // Relocation Functions and Tables
23 //===--------------------------------------------------------------------===//
24 DECL_X86_32_APPLY_RELOC_FUNCS
25 
26 /// the prototype of applying function
27 typedef Relocator::Result (*X86_32ApplyFunctionType)(Relocation& pReloc,
28 						     X86_32Relocator& pParent);
29 
30 // the table entry of applying functions
31 struct X86_32ApplyFunctionTriple
32 {
33   X86_32ApplyFunctionType func;
34   unsigned int type;
35   const char* name;
36   unsigned int size;
37 };
38 
39 // declare the table of applying functions
40 static const X86_32ApplyFunctionTriple X86_32ApplyFunctions[] = {
41   DECL_X86_32_APPLY_RELOC_FUNC_PTRS
42 };
43 
44 //===--------------------------------------------------------------------===//
45 // X86Relocator
46 //===--------------------------------------------------------------------===//
X86Relocator()47 X86Relocator::X86Relocator()
48   : Relocator() {
49 }
50 
~X86Relocator()51 X86Relocator::~X86Relocator()
52 {
53 }
54 
55 //===--------------------------------------------------------------------===//
56 // X86_32Relocator
57 //===--------------------------------------------------------------------===//
X86_32Relocator(X86_32GNULDBackend & pParent)58 X86_32Relocator::X86_32Relocator(X86_32GNULDBackend& pParent)
59   : X86Relocator(), m_Target(pParent) {
60 }
61 
62 Relocator::Result
applyRelocation(Relocation & pRelocation)63 X86_32Relocator::applyRelocation(Relocation& pRelocation)
64 {
65   Relocation::Type type = pRelocation.type();
66 
67   if (type >= sizeof (X86_32ApplyFunctions) / sizeof (X86_32ApplyFunctions[0]) ) {
68     return Unknown;
69   }
70 
71   // apply the relocation
72   return X86_32ApplyFunctions[type].func(pRelocation, *this);
73 }
74 
getName(Relocation::Type pType) const75 const char* X86_32Relocator::getName(Relocation::Type pType) const
76 {
77   return X86_32ApplyFunctions[pType].name;
78 }
79 
getSize(Relocation::Type pType) const80 Relocator::Size X86_32Relocator::getSize(Relocation::Type pType) const
81 {
82   return X86_32ApplyFunctions[pType].size;;
83 }
84 
85 //===--------------------------------------------------------------------===//
86 // Relocation helper function
87 //===--------------------------------------------------------------------===//
88 
89 /// helper_DynRel - Get an relocation entry in .rel.dyn
90 static
helper_DynRel(ResolveInfo * pSym,Fragment & pFrag,uint64_t pOffset,X86Relocator::Type pType,X86_32Relocator & pParent)91 Relocation& helper_DynRel(ResolveInfo* pSym,
92                           Fragment& pFrag,
93                           uint64_t pOffset,
94                           X86Relocator::Type pType,
95                           X86_32Relocator& pParent)
96 {
97   X86_32GNULDBackend& ld_backend = pParent.getTarget();
98   Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
99   rel_entry.setType(pType);
100   rel_entry.targetRef().assign(pFrag, pOffset);
101   if (pType == llvm::ELF::R_386_RELATIVE || NULL == pSym)
102     rel_entry.setSymInfo(0);
103   else
104     rel_entry.setSymInfo(pSym);
105 
106   return rel_entry;
107 }
108 
109 
110 /// helper_use_relative_reloc - Check if symbol can use relocation
111 /// R_386_RELATIVE
112 static bool
helper_use_relative_reloc(const ResolveInfo & pSym,const X86_32Relocator & pFactory)113 helper_use_relative_reloc(const ResolveInfo& pSym,
114                           const X86_32Relocator& pFactory)
115 
116 {
117   // if symbol is dynamic or undefine or preemptible
118   if (pSym.isDyn() ||
119       pSym.isUndef() ||
120       pFactory.getTarget().isSymbolPreemptible(pSym))
121     return false;
122   return true;
123 }
124 
125 static
helper_get_GOT_and_init(Relocation & pReloc,X86_32Relocator & pParent)126 X86_32GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
127 					X86_32Relocator& pParent)
128 {
129   // rsym - The relocation target symbol
130   ResolveInfo* rsym = pReloc.symInfo();
131   X86_32GNULDBackend& ld_backend = pParent.getTarget();
132 
133   X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
134   if (NULL != got_entry)
135     return *got_entry;
136 
137   // not found
138   got_entry = ld_backend.getGOT().consume();
139   pParent.getSymGOTMap().record(*rsym, *got_entry);
140 
141   // If we first get this GOT entry, we should initialize it.
142   if (rsym->reserved() & X86GNULDBackend::ReserveGOT) {
143     // No corresponding dynamic relocation, initialize to the symbol value.
144     got_entry->setValue(pReloc.symValue());
145   }
146   else if (rsym->reserved() & X86GNULDBackend::GOTRel) {
147     // Initialize got_entry content and the corresponding dynamic relocation.
148     if (helper_use_relative_reloc(*rsym, pParent)) {
149       helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_386_RELATIVE, pParent);
150       got_entry->setValue(pReloc.symValue());
151     }
152     else {
153       helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_386_GLOB_DAT, pParent);
154       got_entry->setValue(0);
155     }
156   }
157   else {
158     fatal(diag::reserve_entry_number_mismatch_got);
159   }
160   return *got_entry;
161 }
162 
163 
164 static
helper_GOT_ORG(X86_32Relocator & pParent)165 X86Relocator::Address helper_GOT_ORG(X86_32Relocator& pParent)
166 {
167   return pParent.getTarget().getGOTPLT().addr();
168 }
169 
170 
171 static
helper_GOT(Relocation & pReloc,X86_32Relocator & pParent)172 X86Relocator::Address helper_GOT(Relocation& pReloc, X86_32Relocator& pParent)
173 {
174   X86_32GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
175   X86Relocator::Address got_addr = pParent.getTarget().getGOT().addr();
176   return got_addr + got_entry.getOffset();
177 }
178 
179 
180 static
helper_get_PLT_and_init(Relocation & pReloc,X86_32Relocator & pParent)181 PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc,
182 				      X86_32Relocator& pParent)
183 {
184   // rsym - The relocation target symbol
185   ResolveInfo* rsym = pReloc.symInfo();
186   X86_32GNULDBackend& ld_backend = pParent.getTarget();
187 
188   PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(*rsym);
189   if (NULL != plt_entry)
190     return *plt_entry;
191 
192   // not found
193   plt_entry = ld_backend.getPLT().consume();
194   pParent.getSymPLTMap().record(*rsym, *plt_entry);
195   // If we first get this PLT entry, we should initialize it.
196   if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
197     X86_32GOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
198     assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!");
199     gotplt_entry = ld_backend.getGOTPLT().consume();
200     pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
201     // init the corresponding rel entry in .rel.plt
202     Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry();
203     rel_entry.setType(llvm::ELF::R_386_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 
214 
215 static
helper_PLT_ORG(X86_32Relocator & pParent)216 X86Relocator::Address helper_PLT_ORG(X86_32Relocator& pParent)
217 {
218   return pParent.getTarget().getPLT().addr();
219 }
220 
221 
222 static
helper_PLT(Relocation & pReloc,X86_32Relocator & pParent)223 X86Relocator::Address helper_PLT(Relocation& pReloc, X86_32Relocator& pParent)
224 {
225   PLTEntryBase& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
226   return helper_PLT_ORG(pParent) + plt_entry.getOffset();
227 }
228 
229 
230 //=========================================//
231 // Each relocation function implementation //
232 //=========================================//
233 
234 // R_386_NONE
none(Relocation & pReloc,X86_32Relocator & pParent)235 X86Relocator::Result none(Relocation& pReloc, X86_32Relocator& pParent)
236 {
237   return X86Relocator::OK;
238 }
239 
240 // R_386_32: S + A
241 // R_386_16
242 // R_386_8
abs(Relocation & pReloc,X86_32Relocator & pParent)243 X86Relocator::Result abs(Relocation& pReloc, X86_32Relocator& pParent)
244 {
245   ResolveInfo* rsym = pReloc.symInfo();
246   Relocator::DWord A = pReloc.target() + pReloc.addend();
247   Relocator::DWord S = pReloc.symValue();
248   bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
249                               *rsym,
250                               (rsym->reserved() & X86GNULDBackend::ReservePLT),
251                               true);
252 
253   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
254   // If the flag of target section is not ALLOC, we will not scan this relocation
255   // but perform static relocation. (e.g., applying .debug section)
256   if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
257     pReloc.target() = S + A;
258     return X86Relocator::OK;
259   }
260 
261   // A local symbol may need REL Type dynamic relocation
262   if (rsym->isLocal() && has_dyn_rel) {
263     if (llvm::ELF::R_386_32 == pReloc.type()) {
264       helper_DynRel(rsym, *pReloc.targetRef().frag(),
265                     pReloc.targetRef().offset(), llvm::ELF::R_386_RELATIVE,
266                     pParent);
267     }
268     else {
269       // FIXME: check Section symbol
270       helper_DynRel(rsym, *pReloc.targetRef().frag(),
271                     pReloc.targetRef().offset(), pReloc.type(), pParent);
272     }
273     pReloc.target() = S + A;
274     return X86Relocator::OK;
275   }
276 
277   // An external symbol may need PLT and dynamic relocation
278   if (!rsym->isLocal()) {
279     if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
280       S = helper_PLT(pReloc, pParent);
281     }
282     // If we generate a dynamic relocation (except R_386_RELATIVE)
283     // for a place, we should not perform static relocation on it
284     // in order to keep the addend store in the place correct.
285     if (has_dyn_rel) {
286       if (llvm::ELF::R_386_32 == pReloc.type() &&
287           helper_use_relative_reloc(*rsym, pParent)) {
288         helper_DynRel(rsym, *pReloc.targetRef().frag(),
289               pReloc.targetRef().offset(), llvm::ELF::R_386_RELATIVE, pParent);
290       }
291       else {
292         helper_DynRel(rsym, *pReloc.targetRef().frag(),
293                           pReloc.targetRef().offset(), pReloc.type(), pParent);
294         return X86Relocator::OK;
295       }
296     }
297   }
298 
299   // perform static relocation
300   pReloc.target() = S + A;
301   return X86Relocator::OK;
302 }
303 
304 // R_386_PC32: S + A - P
305 // R_386_PC16
306 // R_386_PC8
rel(Relocation & pReloc,X86_32Relocator & pParent)307 X86Relocator::Result rel(Relocation& pReloc, X86_32Relocator& pParent)
308 {
309   ResolveInfo* rsym = pReloc.symInfo();
310   Relocator::DWord A = pReloc.target() + pReloc.addend();
311   Relocator::DWord S = pReloc.symValue();
312   Relocator::DWord P = pReloc.place();
313 
314   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
315   // If the flag of target section is not ALLOC, we will not scan this relocation
316   // but perform static relocation. (e.g., applying .debug section)
317   if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
318     pReloc.target() = S + A - P;
319     return X86Relocator::OK;
320   }
321 
322   // An external symbol may need PLT and dynamic relocation
323   if (!rsym->isLocal()) {
324     if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
325        S = helper_PLT(pReloc, pParent);
326        pReloc.target() = S + A - P;
327     }
328     if (pParent.getTarget().symbolNeedsDynRel(
329                               *rsym,
330                               (rsym->reserved() & X86GNULDBackend::ReservePLT),
331                               false)) {
332       if (helper_use_relative_reloc(*rsym, pParent) ) {
333         helper_DynRel(rsym, *pReloc.targetRef().frag(),
334               pReloc.targetRef().offset(), llvm::ELF::R_386_RELATIVE, pParent);
335       }
336       else {
337         helper_DynRel(rsym, *pReloc.targetRef().frag(),
338                           pReloc.targetRef().offset(), pReloc.type(), pParent);
339           return X86Relocator::OK;
340       }
341     }
342   }
343 
344    // perform static relocation
345   pReloc.target() = S + A - P;
346   return X86Relocator::OK;
347 }
348 
349 // R_386_GOTOFF: S + A - GOT_ORG
gotoff32(Relocation & pReloc,X86_32Relocator & pParent)350 X86Relocator::Result gotoff32(Relocation& pReloc, X86_32Relocator& pParent)
351 {
352   Relocator::DWord      A = pReloc.target() + pReloc.addend();
353   X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
354   X86Relocator::Address S = pReloc.symValue();
355 
356   pReloc.target() = S + A - GOT_ORG;
357   return X86Relocator::OK;
358 }
359 
360 // R_386_GOTPC: GOT_ORG + A - P
gotpc32(Relocation & pReloc,X86_32Relocator & pParent)361 X86Relocator::Result gotpc32(Relocation& pReloc, X86_32Relocator& pParent)
362 {
363   Relocator::DWord      A       = pReloc.target() + pReloc.addend();
364   X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
365   // Apply relocation.
366   pReloc.target() = GOT_ORG + A - pReloc.place();
367   return X86Relocator::OK;
368 }
369 
370 // R_386_GOT32: GOT(S) + A - GOT_ORG
got32(Relocation & pReloc,X86_32Relocator & pParent)371 X86Relocator::Result got32(Relocation& pReloc, X86_32Relocator& pParent)
372 {
373   if (!(pReloc.symInfo()->reserved()
374        & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
375     return X86Relocator::BadReloc;
376   }
377   X86Relocator::Address GOT_S   = helper_GOT(pReloc, pParent);
378   Relocator::DWord      A       = pReloc.target() + pReloc.addend();
379   X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
380   // Apply relocation.
381   pReloc.target() = GOT_S + A - GOT_ORG;
382   return X86Relocator::OK;
383 }
384 
385 // R_386_PLT32: PLT(S) + A - P
plt32(Relocation & pReloc,X86_32Relocator & pParent)386 X86Relocator::Result plt32(Relocation& pReloc, X86_32Relocator& pParent)
387 {
388   // PLT_S depends on if there is a PLT entry.
389   X86Relocator::Address PLT_S;
390   if ((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
391     PLT_S = helper_PLT(pReloc, pParent);
392   else
393     PLT_S = pReloc.symValue();
394   Relocator::DWord      A = pReloc.target() + pReloc.addend();
395   X86Relocator::Address P = pReloc.place();
396   pReloc.target() = PLT_S + A - P;
397   return X86Relocator::OK;
398 }
399 
400 // R_386_TLS_GD:
tls_gd(Relocation & pReloc,X86_32Relocator & pParent)401 X86Relocator::Result tls_gd(Relocation& pReloc, X86_32Relocator& pParent)
402 {
403   // global-dynamic
404   ResolveInfo* rsym = pReloc.symInfo();
405   // must reserve two pairs of got and dynamic relocation
406   if (!(rsym->reserved() & X86GNULDBackend::GOTRel)) {
407      return X86Relocator::BadReloc;
408   }
409 
410   X86_32GNULDBackend& ld_backend = pParent.getTarget();
411   ELFFileFormat* file_format = pParent.getTarget().getOutputFormat();
412   // setup corresponding got and dynamic relocatio entries:
413   // get first got entry, if there is already a got entry for rsym, then apply
414   // this relocation to the got entry directly. If not, setup the corresponding
415   // got and dyn relocation entries
416   X86_32GOTEntry* got_entry1 = pParent.getSymGOTMap().lookUp(*rsym);
417 
418   if (NULL == got_entry1) {
419     // get and init two got entries if not exist
420     got_entry1 = ld_backend.getGOT().consume();
421     pParent.getSymGOTMap().record(*rsym, *got_entry1);
422     X86_32GOTEntry* got_entry2 = ld_backend.getGOT().consume();
423     got_entry1->setValue(0x0);
424     got_entry2->setValue(0x0);
425     // setup dyn rel for get_entry1
426     Relocation& rel_entry1 = helper_DynRel(rsym, *got_entry1, 0x0,
427                                         llvm::ELF::R_386_TLS_DTPMOD32, pParent);
428     if (rsym->isLocal()) {
429       // for local symbol, set got_entry2 to symbol value
430       got_entry2->setValue(pReloc.symValue());
431 
432       // for local tls symbol, add rel entry against the section symbol this
433       // symbol belong to (.tdata or .tbss)
434       const LDSection* sym_sect =
435          &rsym->outSymbol()->fragRef()->frag()->getParent()->getSection();
436       ResolveInfo* sect_sym = NULL;
437       if (&file_format->getTData() == sym_sect)
438         sect_sym = pParent.getTarget().getTDATASymbol().resolveInfo();
439       else
440         sect_sym = pParent.getTarget().getTBSSSymbol().resolveInfo();
441       rel_entry1.setSymInfo(sect_sym);
442     }
443     else {
444       // for non-local symbol, add a pair of rel entries against this symbol
445       // for those two got entries
446       helper_DynRel(rsym, *got_entry2, 0x0,
447                                         llvm::ELF::R_386_TLS_DTPOFF32, pParent);
448     }
449   }
450 
451   // perform relocation to the first got entry
452   Relocator::DWord A = pReloc.target() + pReloc.addend();
453   // GOT_OFF - the offset between the got_entry1 and _GLOBAL_OFFSET_TABLE (the
454   // .got.plt section)
455   X86Relocator::Address GOT_OFF =
456      file_format->getGOT().addr() +
457      got_entry1->getOffset() -
458      file_format->getGOTPLT().addr();
459   pReloc.target() = GOT_OFF + A;
460   return X86Relocator::OK;
461 }
462 
463 // R_386_TLS_LDM
tls_ldm(Relocation & pReloc,X86_32Relocator & pParent)464 X86Relocator::Result tls_ldm(Relocation& pReloc, X86_32Relocator& pParent)
465 {
466   // FIXME: no linker optimization for TLS relocation
467   const X86_32GOTEntry& got_entry = pParent.getTarget().getTLSModuleID();
468 
469   // All GOT offsets are relative to the end of the GOT.
470   X86Relocator::SWord GOT_S = got_entry.getOffset() -
471                                       (pParent.getTarget().getGOTPLT().addr() -
472                                        pParent.getTarget().getGOT().addr());
473   Relocator::DWord A = pReloc.target() + pReloc.addend();
474   pReloc.target() = GOT_S + A;
475 
476   return X86Relocator::OK;
477 }
478 
479 // R_386_TLS_LDO_32
tls_ldo_32(Relocation & pReloc,X86_32Relocator & pParent)480 X86Relocator::Result tls_ldo_32(Relocation& pReloc, X86_32Relocator& pParent)
481 {
482   // FIXME: no linker optimization for TLS relocation
483   Relocator::DWord A = pReloc.target() + pReloc.addend();
484   X86Relocator::Address S = pReloc.symValue();
485   pReloc.target() = S + A;
486   return X86Relocator::OK;
487 }
488 
489 // R_X86_TLS_IE
tls_ie(Relocation & pReloc,X86_32Relocator & pParent)490 X86Relocator::Result tls_ie(Relocation& pReloc, X86_32Relocator& pParent)
491 {
492   ResolveInfo* rsym = pReloc.symInfo();
493   if (!(rsym->reserved() & X86GNULDBackend::GOTRel)) {
494      return X86Relocator::BadReloc;
495   }
496 
497   if (rsym->reserved() & X86GNULDBackend::ReserveRel) {
498     // when building shared object, set up a RELATIVE dynamic relocation
499     helper_DynRel(rsym, *pReloc.targetRef().frag(), pReloc.targetRef().offset(),
500                                             llvm::ELF::R_386_RELATIVE, pParent);
501   }
502 
503   // set up the got and dynamic relocation entries if not exist
504   X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
505   if (NULL == got_entry) {
506     // set got entry
507     X86_32GNULDBackend& ld_backend = pParent.getTarget();
508     got_entry = ld_backend.getGOT().consume();
509     pParent.getSymGOTMap().record(*rsym, *got_entry);
510     got_entry->setValue(0x0);
511     // set relocation entry
512     Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
513     rel_entry.setType(llvm::ELF::R_386_TLS_TPOFF);
514     rel_entry.setSymInfo(rsym);
515     rel_entry.targetRef().assign(*got_entry);
516   }
517 
518   // perform relocation to the absolute address of got_entry
519   X86Relocator::Address GOT_S =
520                  pParent.getTarget().getGOT().addr() + got_entry->getOffset();
521 
522   Relocator::DWord A = pReloc.target() + pReloc.addend();
523   pReloc.target() = GOT_S + A;
524 
525   return X86Relocator::OK;
526 }
527 
528 // R_386_TLS_GOTIE
tls_gotie(Relocation & pReloc,X86_32Relocator & pParent)529 X86Relocator::Result tls_gotie(Relocation& pReloc, X86_32Relocator& pParent)
530 {
531   ResolveInfo* rsym = pReloc.symInfo();
532   if (!(rsym->reserved() & X86GNULDBackend::GOTRel)) {
533      return X86Relocator::BadReloc;
534   }
535 
536   // set up the got and dynamic relocation entries if not exist
537   X86_32GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
538   if (NULL == got_entry) {
539     // set got entry
540     X86_32GNULDBackend& ld_backend = pParent.getTarget();
541     got_entry = ld_backend.getGOT().consume();
542     pParent.getSymGOTMap().record(*rsym, *got_entry);
543     got_entry->setValue(0x0);
544     // set relocation entry
545     Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
546     rel_entry.setType(llvm::ELF::R_386_TLS_TPOFF);
547     rel_entry.setSymInfo(rsym);
548     rel_entry.targetRef().assign(*got_entry);
549   }
550 
551   // All GOT offsets are relative to the end of the GOT.
552   X86Relocator::SWord GOT_S = got_entry->getOffset() -
553     (pParent.getTarget().getGOTPLT().addr() - pParent.getTarget().getGOT().addr());
554   Relocator::DWord A = pReloc.target() + pReloc.addend();
555   pReloc.target() = GOT_S + A;
556 
557   return X86Relocator::OK;
558 }
559 
560 // R_X86_TLS_LE
tls_le(Relocation & pReloc,X86_32Relocator & pParent)561 X86Relocator::Result tls_le(Relocation& pReloc, X86_32Relocator& pParent)
562 {
563   ResolveInfo* rsym = pReloc.symInfo();
564   if (pReloc.symInfo()->reserved() & X86GNULDBackend::ReserveRel) {
565     helper_DynRel(rsym,
566                   *pReloc.targetRef().frag(),
567                   pReloc.targetRef().offset(),
568                   llvm::ELF::R_386_TLS_TPOFF,
569                   pParent);
570     return X86Relocator::OK;
571   }
572 
573   // perform static relocation
574   // get TLS segment
575   ELFSegment* tls_seg = pParent.getTarget().elfSegmentTable().find(
576                                        llvm::ELF::PT_TLS, llvm::ELF::PF_R, 0x0);
577   Relocator::DWord A = pReloc.target() + pReloc.addend();
578   X86Relocator::Address S = pReloc.symValue();
579   pReloc.target() = S + A - tls_seg->memsz();
580   return X86Relocator::OK;
581 }
582 
unsupport(Relocation & pReloc,X86_32Relocator & pParent)583 X86Relocator::Result unsupport(Relocation& pReloc, X86_32Relocator& pParent)
584 {
585   return X86Relocator::Unsupport;
586 }
587 
588 //===--------------------------------------------------------------------===//
589 // Relocation Functions and Tables
590 //===--------------------------------------------------------------------===//
591 DECL_X86_64_APPLY_RELOC_FUNCS
592 
593 /// the prototype of applying function
594 typedef Relocator::Result (*X86_64ApplyFunctionType)(Relocation& pReloc,
595 						     X86_64Relocator& pParent);
596 
597 // the table entry of applying functions
598 struct X86_64ApplyFunctionTriple
599 {
600   X86_64ApplyFunctionType func;
601   unsigned int type;
602   const char* name;
603   unsigned int size;
604 };
605 
606 // declare the table of applying functions
607 static const X86_64ApplyFunctionTriple X86_64ApplyFunctions[] = {
608   DECL_X86_64_APPLY_RELOC_FUNC_PTRS
609 };
610 
611 //===--------------------------------------------------------------------===//
612 // X86_64Relocator
613 //===--------------------------------------------------------------------===//
X86_64Relocator(X86_64GNULDBackend & pParent)614 X86_64Relocator::X86_64Relocator(X86_64GNULDBackend& pParent)
615   : X86Relocator(), m_Target(pParent) {
616 }
617 
618 Relocator::Result
applyRelocation(Relocation & pRelocation)619 X86_64Relocator::applyRelocation(Relocation& pRelocation)
620 {
621   Relocation::Type type = pRelocation.type();
622 
623   if (type >= sizeof (X86_64ApplyFunctions) / sizeof (X86_64ApplyFunctions[0]) ) {
624     return Unknown;
625   }
626 
627   // apply the relocation
628   return X86_64ApplyFunctions[type].func(pRelocation, *this);
629 }
630 
getName(Relocation::Type pType) const631 const char* X86_64Relocator::getName(Relocation::Type pType) const
632 {
633   return X86_64ApplyFunctions[pType].name;
634 }
635 
getSize(Relocation::Type pType) const636 Relocator::Size X86_64Relocator::getSize(Relocation::Type pType) const
637 {
638   return X86_64ApplyFunctions[pType].size;
639 }
640 
641 /// helper_DynRel - Get an relocation entry in .rela.dyn
642 static
helper_DynRel(ResolveInfo * pSym,Fragment & pFrag,uint64_t pOffset,X86Relocator::Type pType,X86_64Relocator & pParent)643 Relocation& helper_DynRel(ResolveInfo* pSym,
644                           Fragment& pFrag,
645                           uint64_t pOffset,
646                           X86Relocator::Type pType,
647                           X86_64Relocator& pParent)
648 {
649   X86_64GNULDBackend& ld_backend = pParent.getTarget();
650   Relocation& rel_entry = *ld_backend.getRelDyn().consumeEntry();
651   rel_entry.setType(pType);
652   rel_entry.targetRef().assign(pFrag, pOffset);
653   if (pType == llvm::ELF::R_X86_64_RELATIVE || NULL == pSym)
654     rel_entry.setSymInfo(0);
655   else
656     rel_entry.setSymInfo(pSym);
657 
658   return rel_entry;
659 }
660 
661 
662 /// helper_use_relative_reloc - Check if symbol can use relocation
663 /// R_X86_64_RELATIVE
664 static bool
helper_use_relative_reloc(const ResolveInfo & pSym,const X86_64Relocator & pFactory)665 helper_use_relative_reloc(const ResolveInfo& pSym,
666                           const X86_64Relocator& pFactory)
667 
668 {
669   // if symbol is dynamic or undefine or preemptible
670   if (pSym.isDyn() ||
671       pSym.isUndef() ||
672       pFactory.getTarget().isSymbolPreemptible(pSym))
673     return false;
674   return true;
675 }
676 
677 static
helper_get_GOT_and_init(Relocation & pReloc,X86_64Relocator & pParent)678 X86_64GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
679 					X86_64Relocator& pParent)
680 {
681   // rsym - The relocation target symbol
682   ResolveInfo* rsym = pReloc.symInfo();
683   X86_64GNULDBackend& ld_backend = pParent.getTarget();
684 
685   X86_64GOTEntry* got_entry = pParent.getSymGOTMap().lookUp(*rsym);
686   if (NULL != got_entry)
687     return *got_entry;
688 
689   // not found
690   got_entry = ld_backend.getGOT().consume();
691   pParent.getSymGOTMap().record(*rsym, *got_entry);
692 
693   // If we first get this GOT entry, we should initialize it.
694   if (rsym->reserved() & X86GNULDBackend::ReserveGOT) {
695     // No corresponding dynamic relocation, initialize to the symbol value.
696     got_entry->setValue(pReloc.symValue());
697   }
698   else if (rsym->reserved() & X86GNULDBackend::GOTRel) {
699     // Initialize got_entry content and the corresponding dynamic relocation.
700     if (helper_use_relative_reloc(*rsym, pParent)) {
701       Relocation& rel_entry = helper_DynRel(rsym, *got_entry, 0x0,
702 					    llvm::ELF::R_X86_64_RELATIVE,
703 					    pParent);
704       rel_entry.setAddend(pReloc.symValue());
705     }
706     else {
707       helper_DynRel(rsym, *got_entry, 0x0, llvm::ELF::R_X86_64_GLOB_DAT,
708 		    pParent);
709     }
710     got_entry->setValue(0);
711   }
712   else {
713     fatal(diag::reserve_entry_number_mismatch_got);
714   }
715   return *got_entry;
716 }
717 
718 static
helper_GOT_ORG(X86_64Relocator & pParent)719 X86Relocator::Address helper_GOT_ORG(X86_64Relocator& pParent)
720 {
721   return pParent.getTarget().getGOT().addr();
722 }
723 
724 static
helper_GOT(Relocation & pReloc,X86_64Relocator & pParent)725 X86Relocator::Address helper_GOT(Relocation& pReloc, X86_64Relocator& pParent)
726 {
727   X86_64GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pParent);
728   return got_entry.getOffset();
729 }
730 
731 static
helper_get_PLT_and_init(Relocation & pReloc,X86_64Relocator & pParent)732 PLTEntryBase& helper_get_PLT_and_init(Relocation& pReloc,
733 				      X86_64Relocator& pParent)
734 {
735   // rsym - The relocation target symbol
736   ResolveInfo* rsym = pReloc.symInfo();
737   X86_64GNULDBackend& ld_backend = pParent.getTarget();
738 
739   PLTEntryBase* plt_entry = pParent.getSymPLTMap().lookUp(*rsym);
740   if (NULL != plt_entry)
741     return *plt_entry;
742 
743   // not found
744   plt_entry = ld_backend.getPLT().consume();
745   pParent.getSymPLTMap().record(*rsym, *plt_entry);
746   // If we first get this PLT entry, we should initialize it.
747   if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
748     X86_64GOTEntry* gotplt_entry = pParent.getSymGOTPLTMap().lookUp(*rsym);
749     assert(NULL == gotplt_entry && "PLT entry not exist, but DynRel entry exist!");
750     gotplt_entry = ld_backend.getGOTPLT().consume();
751     pParent.getSymGOTPLTMap().record(*rsym, *gotplt_entry);
752     // init the corresponding rel entry in .rel.plt
753     Relocation& rel_entry = *ld_backend.getRelPLT().consumeEntry();
754     rel_entry.setType(llvm::ELF::R_X86_64_JUMP_SLOT);
755     rel_entry.targetRef().assign(*gotplt_entry);
756     rel_entry.setSymInfo(rsym);
757   }
758   else {
759     fatal(diag::reserve_entry_number_mismatch_plt);
760   }
761 
762   return *plt_entry;
763 }
764 
765 static
helper_PLT_ORG(X86_64Relocator & pParent)766 X86Relocator::Address helper_PLT_ORG(X86_64Relocator& pParent)
767 {
768   return pParent.getTarget().getPLT().addr();
769 }
770 
771 static
helper_PLT(Relocation & pReloc,X86_64Relocator & pParent)772 X86Relocator::Address helper_PLT(Relocation& pReloc, X86_64Relocator& pParent)
773 {
774   PLTEntryBase& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
775   return helper_PLT_ORG(pParent) + plt_entry.getOffset();
776 }
777 
778 //
779 // R_X86_64_NONE
none(Relocation & pReloc,X86_64Relocator & pParent)780 X86Relocator::Result none(Relocation& pReloc, X86_64Relocator& pParent)
781 {
782   return X86Relocator::OK;
783 }
784 
785 // R_X86_64_64: S + A
786 // R_X86_64_32:
787 // R_X86_64_16:
788 // R_X86_64_8
abs(Relocation & pReloc,X86_64Relocator & pParent)789 X86Relocator::Result abs(Relocation& pReloc, X86_64Relocator& pParent)
790 {
791   ResolveInfo* rsym = pReloc.symInfo();
792   Relocator::DWord A = pReloc.addend();
793   Relocator::DWord S = pReloc.symValue();
794   bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
795                               *rsym,
796                               (rsym->reserved() & X86GNULDBackend::ReservePLT),
797                               true);
798 
799   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
800   // If the flag of target section is not ALLOC, we will not scan this relocation
801   // but perform static relocation. (e.g., applying .debug section)
802   if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
803     pReloc.target() = S + A;
804     return X86Relocator::OK;
805   }
806 
807   Relocation::Type pointerRel = pParent.getTarget().getPointerRel();
808 
809   // A local symbol may need REL Type dynamic relocation
810   if (rsym->isLocal() && has_dyn_rel) {
811     if (pointerRel == pReloc.type()) {
812       Relocation& rel_entry = helper_DynRel(rsym, *pReloc.targetRef().frag(),
813 					    pReloc.targetRef().offset(),
814 					    llvm::ELF::R_X86_64_RELATIVE,
815 					    pParent);
816       rel_entry.setAddend(S + A);
817     }
818     else {
819       // FIXME: check Section symbol
820       Relocation& rel_entry = helper_DynRel(rsym, *pReloc.targetRef().frag(),
821 					    pReloc.targetRef().offset(),
822 					    pReloc.type(), pParent);
823       rel_entry.setAddend(S + A);
824     }
825     return X86Relocator::OK;
826   }
827 
828   // An external symbol may need PLT and dynamic relocation
829   if (!rsym->isLocal()) {
830     // If we generate a dynamic relocation for a place with explicit
831     // addend, there is no need to perform static relocation on it.
832     if (has_dyn_rel) {
833       Relocation& rel_entry = helper_DynRel(rsym, *pReloc.targetRef().frag(),
834 					    pReloc.targetRef().offset(),
835 					    llvm::ELF::R_X86_64_RELATIVE,
836 					    pParent);
837       // Copy addend.
838       rel_entry.setAddend(A);
839       return X86Relocator::OK;
840     }
841     else if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
842       S = helper_PLT(pReloc, pParent);
843     }
844   }
845 
846   // perform static relocation
847   pReloc.target() = S + A;
848   return X86Relocator::OK;
849 }
850 
851 // R_X86_64_32S: S + A
signed32(Relocation & pReloc,X86_64Relocator & pParent)852 X86Relocator::Result signed32(Relocation& pReloc, X86_64Relocator& pParent)
853 {
854   ResolveInfo* rsym = pReloc.symInfo();
855   Relocator::DWord A = pReloc.addend();
856   Relocator::DWord S = pReloc.symValue();
857   bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
858                               *rsym,
859                               (rsym->reserved() & X86GNULDBackend::ReservePLT),
860                               true);
861 
862   // There should be no dynamic relocations for R_X86_64_32S.
863   if (has_dyn_rel)
864     return X86Relocator::BadReloc;
865 
866   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
867   // If the flag of target section is not ALLOC, we will not scan this relocation
868   // but perform static relocation. (e.g., applying .debug section)
869   // An external symbol may need PLT and dynamic relocation
870   if (0x0 != (llvm::ELF::SHF_ALLOC & target_sect.flag()) &&
871       !rsym->isLocal() && rsym->reserved() & X86GNULDBackend::ReservePLT)
872     S = helper_PLT(pReloc, pParent);
873 
874   // Check 32-bit signed overflow.
875   Relocator::SWord V = S + A;
876   if (V > INT64_C(0x7fffffff) || V < INT64_C(-0x80000000))
877     return X86Relocator::Overflow;
878 
879   // perform static relocation
880   pReloc.target() = S + A;
881   return X86Relocator::OK;
882 }
883 
884 // R_X86_64_GOTPCREL: GOT(S) + GOT_ORG + A - P
gotpcrel(Relocation & pReloc,X86_64Relocator & pParent)885 X86Relocator::Result gotpcrel(Relocation& pReloc, X86_64Relocator& pParent)
886 {
887   if (!(pReloc.symInfo()->reserved()
888        & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
889     return X86Relocator::BadReloc;
890   }
891   X86Relocator::Address GOT_S   = helper_GOT(pReloc, pParent);
892   Relocator::DWord      A       = pReloc.addend();
893   X86Relocator::Address GOT_ORG = helper_GOT_ORG(pParent);
894   // Apply relocation.
895   pReloc.target() = GOT_S + GOT_ORG + A - pReloc.place();
896   return X86Relocator::OK;
897 }
898 
899 // R_X86_64_PLT32: PLT(S) + A - P
plt32(Relocation & pReloc,X86_64Relocator & pParent)900 X86Relocator::Result plt32(Relocation& pReloc, X86_64Relocator& pParent)
901 {
902   // PLT_S depends on if there is a PLT entry.
903   X86Relocator::Address PLT_S;
904   if ((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
905     PLT_S = helper_PLT(pReloc, pParent);
906   else
907     PLT_S = pReloc.symValue();
908   Relocator::DWord      A = pReloc.addend();
909   X86Relocator::Address P = pReloc.place();
910   pReloc.target() = PLT_S + A - P;
911   return X86Relocator::OK;
912 }
913 
914 // R_X86_64_PC32: S + A - P
915 // R_X86_64_PC16
916 // R_X86_64_PC8
rel(Relocation & pReloc,X86_64Relocator & pParent)917 X86Relocator::Result rel(Relocation& pReloc, X86_64Relocator& pParent)
918 {
919   ResolveInfo* rsym = pReloc.symInfo();
920   Relocator::DWord A = pReloc.addend();
921   Relocator::DWord S = pReloc.symValue();
922   Relocator::DWord P = pReloc.place();
923 
924   LDSection& target_sect = pReloc.targetRef().frag()->getParent()->getSection();
925   // If the flag of target section is not ALLOC, we will not scan this relocation
926   // but perform static relocation. (e.g., applying .debug section)
927   if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect.flag())) {
928     pReloc.target() = S + A - P;
929     return X86Relocator::OK;
930   }
931 
932   // An external symbol may need PLT and dynamic relocation
933   if (!rsym->isLocal()) {
934     if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
935        S = helper_PLT(pReloc, pParent);
936        pReloc.target() = S + A - P;
937     }
938     if (pParent.getTarget().symbolNeedsDynRel(
939                               *rsym,
940                               (rsym->reserved() & X86GNULDBackend::ReservePLT),
941                               false)) {
942           return X86Relocator::Overflow;
943     }
944   }
945 
946    // perform static relocation
947   pReloc.target() = S + A - P;
948   return X86Relocator::OK;
949 }
950 
unsupport(Relocation & pReloc,X86_64Relocator & pParent)951 X86Relocator::Result unsupport(Relocation& pReloc, X86_64Relocator& pParent)
952 {
953   return X86Relocator::Unsupport;
954 }
955