X86Relocator.cpp revision 6f75755c9204b1d8817ae5a65a2f7e5af0ec3f70
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
19using namespace mcld;
20
21//===--------------------------------------------------------------------===//
22// Relocation Functions and Tables
23//===--------------------------------------------------------------------===//
24DECL_X86_32_APPLY_RELOC_FUNCS
25
26/// the prototype of applying function
27typedef Relocator::Result (*X86_32ApplyFunctionType)(Relocation& pReloc,
28						     X86_32Relocator& pParent);
29
30// the table entry of applying functions
31struct 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
40static const X86_32ApplyFunctionTriple X86_32ApplyFunctions[] = {
41  DECL_X86_32_APPLY_RELOC_FUNC_PTRS
42};
43
44//===--------------------------------------------------------------------===//
45// X86Relocator
46//===--------------------------------------------------------------------===//
47X86Relocator::X86Relocator()
48  : Relocator() {
49}
50
51X86Relocator::~X86Relocator()
52{
53}
54
55//===--------------------------------------------------------------------===//
56// X86_32Relocator
57//===--------------------------------------------------------------------===//
58X86_32Relocator::X86_32Relocator(X86_32GNULDBackend& pParent)
59  : X86Relocator(), m_Target(pParent) {
60}
61
62Relocator::Result
63X86_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
75const char* X86_32Relocator::getName(Relocation::Type pType) const
76{
77  return X86_32ApplyFunctions[pType].name;
78}
79
80Relocator::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
90static
91Relocation& 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
112static bool
113helper_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
125static
126X86_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
164static
165X86Relocator::Address helper_GOT_ORG(X86_32Relocator& pParent)
166{
167  return pParent.getTarget().getGOTPLT().addr();
168}
169
170
171static
172X86Relocator::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
180static
181PLTEntryBase& 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
215static
216X86Relocator::Address helper_PLT_ORG(X86_32Relocator& pParent)
217{
218  return pParent.getTarget().getPLT().addr();
219}
220
221
222static
223X86Relocator::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
235X86Relocator::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
243X86Relocator::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
307X86Relocator::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
350X86Relocator::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
361X86Relocator::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
371X86Relocator::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
386X86Relocator::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:
401X86Relocator::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
464X86Relocator::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
480X86Relocator::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
490X86Relocator::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
529X86Relocator::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
561X86Relocator::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
583X86Relocator::Result unsupport(Relocation& pReloc, X86_32Relocator& pParent)
584{
585  return X86Relocator::Unsupport;
586}
587
588//===--------------------------------------------------------------------===//
589// Relocation Functions and Tables
590//===--------------------------------------------------------------------===//
591DECL_X86_64_APPLY_RELOC_FUNCS
592
593/// the prototype of applying function
594typedef Relocator::Result (*X86_64ApplyFunctionType)(Relocation& pReloc,
595						     X86_64Relocator& pParent);
596
597// the table entry of applying functions
598struct 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
607static const X86_64ApplyFunctionTriple X86_64ApplyFunctions[] = {
608  DECL_X86_64_APPLY_RELOC_FUNC_PTRS
609};
610
611//===--------------------------------------------------------------------===//
612// X86_64Relocator
613//===--------------------------------------------------------------------===//
614X86_64Relocator::X86_64Relocator(X86_64GNULDBackend& pParent)
615  : X86Relocator(), m_Target(pParent) {
616}
617
618Relocator::Result
619X86_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
631const char* X86_64Relocator::getName(Relocation::Type pType) const
632{
633  return X86_64ApplyFunctions[pType].name;
634}
635
636Relocator::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
642static
643Relocation& 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
664static bool
665helper_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
677static
678X86_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
718static
719X86Relocator::Address helper_GOT_ORG(X86_64Relocator& pParent)
720{
721  return pParent.getTarget().getGOT().addr();
722}
723
724static
725X86Relocator::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
731static
732PLTEntryBase& 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
765static
766X86Relocator::Address helper_PLT_ORG(X86_64Relocator& pParent)
767{
768  return pParent.getTarget().getPLT().addr();
769}
770
771static
772X86Relocator::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
780X86Relocator::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
789X86Relocator::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
852X86Relocator::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
885X86Relocator::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
900X86Relocator::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
917X86Relocator::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
951X86Relocator::Result unsupport(Relocation& pReloc, X86_64Relocator& pParent)
952{
953  return X86Relocator::Unsupport;
954}
955