1//===- X86RelocationFactory.cpp -------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include <llvm/ADT/Twine.h>
11#include <llvm/Support/DataTypes.h>
12#include <llvm/Support/ELF.h>
13#include <mcld/MC/MCLDInfo.h>
14#include <mcld/LD/Layout.h>
15#include <mcld/Support/MsgHandling.h>
16
17#include "X86RelocationFactory.h"
18#include "X86RelocationFunctions.h"
19
20using namespace mcld;
21
22//===--------------------------------------------------------------------===//
23// Relocation Functions and Tables
24//===--------------------------------------------------------------------===//
25DECL_X86_APPLY_RELOC_FUNCS
26
27/// the prototype of applying function
28typedef RelocationFactory::Result
29                          (*ApplyFunctionType)(Relocation& pReloc,
30                                               const MCLDInfo& pLDInfo,
31                                               X86RelocationFactory& pParent);
32
33// the table entry of applying functions
34struct ApplyFunctionTriple
35{
36  ApplyFunctionType func;
37  unsigned int type;
38  const char* name;
39};
40
41// declare the table of applying functions
42static const ApplyFunctionTriple ApplyFunctions[] = {
43  DECL_X86_APPLY_RELOC_FUNC_PTRS
44};
45
46//===--------------------------------------------------------------------===//
47// X86RelocationFactory
48//===--------------------------------------------------------------------===//
49X86RelocationFactory::X86RelocationFactory(size_t pNum,
50                                           X86GNULDBackend& pParent)
51  : RelocationFactory(pNum),
52    m_Target(pParent) {
53}
54
55X86RelocationFactory::~X86RelocationFactory()
56{
57}
58
59RelocationFactory::Result
60X86RelocationFactory::applyRelocation(Relocation& pRelocation,
61                                           const MCLDInfo& pLDInfo)
62{
63  Relocation::Type type = pRelocation.type();
64
65  if (type >= sizeof (ApplyFunctions) / sizeof (ApplyFunctions[0]) ) {
66    fatal(diag::unknown_relocation) << (int)type <<
67                                       pRelocation.symInfo()->name();
68    return Unknown;
69  }
70
71  // apply the relocation
72  return ApplyFunctions[type].func(pRelocation, pLDInfo, *this);
73}
74
75const char* X86RelocationFactory::getName(Relocation::Type pType) const
76{
77  return ApplyFunctions[pType].name;
78}
79
80//===--------------------------------------------------------------------===//
81// Relocation helper function
82//===--------------------------------------------------------------------===//
83
84// Check if symbol can use relocation R_386_RELATIVE
85static bool
86helper_use_relative_reloc(const ResolveInfo& pSym,
87                          const MCLDInfo& pLDInfo,
88                          const X86RelocationFactory& pFactory)
89
90{
91  // if symbol is dynamic or undefine or preemptible
92  if (pSym.isDyn() ||
93     pSym.isUndef() ||
94     pFactory.getTarget().isSymbolPreemptible(pSym, pLDInfo, pLDInfo.output()))
95    return false;
96  return true;
97}
98
99static
100GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
101                                  const MCLDInfo& pLDInfo,
102                                  X86RelocationFactory& pParent)
103{
104  // rsym - The relocation target symbol
105  ResolveInfo* rsym = pReloc.symInfo();
106  X86GNULDBackend& ld_backend = pParent.getTarget();
107
108  bool exist;
109  GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
110  if (!exist) {
111    // If we first get this GOT entry, we should initialize it.
112    if (rsym->reserved() & X86GNULDBackend::ReserveGOT) {
113      // No corresponding dynamic relocation, initialize to the symbol value.
114      got_entry.setContent(pReloc.symValue());
115    }
116    else if (rsym->reserved() & X86GNULDBackend::GOTRel) {
117      // Initialize corresponding dynamic relocation.
118      Relocation& rel_entry =
119        *ld_backend.getRelDyn().getEntry(*rsym, true, exist);
120      assert(!exist && "GOT entry not exist, but DynRel entry exist!");
121      if (helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
122        // Initialize got entry to target symbol address
123        got_entry.setContent(pReloc.symValue());
124        rel_entry.setType(llvm::ELF::R_386_RELATIVE);
125        rel_entry.setSymInfo(0);
126      }
127      else {
128        got_entry.setContent(0);
129        rel_entry.setType(llvm::ELF::R_386_GLOB_DAT);
130        rel_entry.setSymInfo(rsym);
131      }
132      rel_entry.targetRef().assign(got_entry);
133    }
134    else {
135      fatal(diag::reserve_entry_number_mismatch_got);
136    }
137  }
138  return got_entry;
139}
140
141
142static
143X86RelocationFactory::Address helper_GOT_ORG(X86RelocationFactory& pParent)
144{
145  return pParent.getTarget().getGOTPLT().getSection().addr();
146}
147
148
149static
150X86RelocationFactory::Address helper_GOT(Relocation& pReloc,
151                                         const MCLDInfo& pLDInfo,
152                                         X86RelocationFactory& pParent)
153{
154  GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pLDInfo,  pParent);
155  X86RelocationFactory::Address got_addr =
156    pParent.getTarget().getGOT().getSection().addr();
157  return got_addr + pParent.getLayout().getOutputOffset(got_entry);
158}
159
160
161static
162PLTEntry& helper_get_PLT_and_init(Relocation& pReloc,
163                                  X86RelocationFactory& pParent)
164{
165  // rsym - The relocation target symbol
166  ResolveInfo* rsym = pReloc.symInfo();
167  X86GNULDBackend& ld_backend = pParent.getTarget();
168
169  bool exist;
170  PLTEntry& plt_entry = *ld_backend.getPLT().getPLTEntry(*rsym, exist);
171  if (!exist) {
172    // If we first get this PLT entry, we should initialize it.
173    if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
174      GOTEntry& gotplt_entry =
175        *ld_backend.getPLT().getGOTPLTEntry(*rsym, exist);
176      // Initialize corresponding dynamic relocation.
177      Relocation& rel_entry =
178        *ld_backend.getRelPLT().getEntry(*rsym, true, exist);
179      assert(!exist && "PLT entry not exist, but DynRel entry exist!");
180      rel_entry.setType(llvm::ELF::R_386_JUMP_SLOT);
181      rel_entry.targetRef().assign(gotplt_entry);
182      rel_entry.setSymInfo(rsym);
183    }
184    else {
185      fatal(diag::reserve_entry_number_mismatch_plt);
186    }
187  }
188  return plt_entry;
189}
190
191
192
193static
194X86RelocationFactory::Address helper_PLT_ORG(X86RelocationFactory& pParent)
195{
196  return pParent.getTarget().getPLT().getSection().addr();
197}
198
199
200static
201X86RelocationFactory::Address helper_PLT(Relocation& pReloc,
202                                         X86RelocationFactory& pParent)
203{
204  PLTEntry& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
205  return helper_PLT_ORG(pParent) + pParent.getLayout().getOutputOffset(plt_entry);
206}
207
208// Get an relocation entry in .rel.dyn and set its type to pType,
209// its FragmentRef to pReloc->targetFrag() and its ResolveInfo to pReloc->symInfo()
210static
211void helper_DynRel(Relocation& pReloc,
212                   X86RelocationFactory::Type pType,
213                   X86RelocationFactory& pParent)
214{
215  // rsym - The relocation target symbol
216  ResolveInfo* rsym = pReloc.symInfo();
217  X86GNULDBackend& ld_backend = pParent.getTarget();
218  bool exist;
219
220  Relocation& rel_entry =
221    *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
222  rel_entry.setType(pType);
223  rel_entry.targetRef() = pReloc.targetRef();
224
225  if (pType == llvm::ELF::R_386_RELATIVE)
226    rel_entry.setSymInfo(0);
227  else
228    rel_entry.setSymInfo(rsym);
229}
230
231
232//=========================================//
233// Each relocation function implementation //
234//=========================================//
235
236// R_386_NONE
237X86RelocationFactory::Result none(Relocation& pReloc,
238                                  const MCLDInfo& pLDInfo,
239                                  X86RelocationFactory& pParent)
240{
241  return X86RelocationFactory::OK;
242}
243
244// R_386_32: S + A
245X86RelocationFactory::Result abs32(Relocation& pReloc,
246                                   const MCLDInfo& pLDInfo,
247                                   X86RelocationFactory& pParent)
248{
249  ResolveInfo* rsym = pReloc.symInfo();
250  RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
251  RelocationFactory::DWord S = pReloc.symValue();
252  bool has_dyn_rel = pParent.getTarget().symbolNeedsDynRel(
253                       *rsym, (rsym->reserved() & X86GNULDBackend::ReservePLT),
254                       pLDInfo, pLDInfo.output(), true);
255
256  const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
257                                                  *(pReloc.targetRef().frag()));
258  assert(NULL != target_sect);
259  // If the flag of target section is not ALLOC, we will not scan this relocation
260  // but perform static relocation. (e.g., applying .debug section)
261  if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
262    pReloc.target() = S + A;
263    return X86RelocationFactory::OK;
264  }
265
266  // A local symbol may need REL Type dynamic relocation
267  if (rsym->isLocal() && has_dyn_rel) {
268    helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
269    pReloc.target() = S + A;
270    return X86RelocationFactory::OK;
271  }
272
273  // An external symbol may need PLT and dynamic relocation
274  if (!rsym->isLocal()) {
275    if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
276      S = helper_PLT(pReloc, pParent);
277      pReloc.target() = S + A;
278    }
279    // If we generate a dynamic relocation (except R_386_RELATIVE)
280    // for a place, we should not perform static relocation on it
281    // in order to keep the addend store in the place correct.
282    if (has_dyn_rel) {
283      if (helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
284        helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
285      }
286      else {
287        helper_DynRel(pReloc, pReloc.type(), pParent);
288        return X86RelocationFactory::OK;
289      }
290    }
291  }
292
293  // perform static relocation
294  pReloc.target() = S + A;
295  return X86RelocationFactory::OK;
296}
297
298// R_386_PC32: S + A - P
299X86RelocationFactory::Result rel32(Relocation& pReloc,
300                                   const MCLDInfo& pLDInfo,
301                                   X86RelocationFactory& pParent)
302{
303  ResolveInfo* rsym = pReloc.symInfo();
304  RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
305  RelocationFactory::DWord S = pReloc.symValue();
306  RelocationFactory::DWord P = pReloc.place(pParent.getLayout());
307
308  const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
309                                                  *(pReloc.targetRef().frag()));
310  assert(NULL != target_sect);
311  // If the flag of target section is not ALLOC, we will not scan this relocation
312  // but perform static relocation. (e.g., applying .debug section)
313  if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
314    pReloc.target() = S + A - P;
315    return X86RelocationFactory::OK;
316  }
317
318  // An external symbol may need PLT and dynamic relocation
319  if (!rsym->isLocal()) {
320    if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
321       S = helper_PLT(pReloc, pParent);
322       pReloc.target() = S + A - P;
323    }
324    if (pParent.getTarget().symbolNeedsDynRel(
325          *rsym, (rsym->reserved() & X86GNULDBackend::ReservePLT), pLDInfo,
326                  pLDInfo.output(), false)) {
327      if (helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) {
328        helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
329      }
330      else {
331        helper_DynRel(pReloc, pReloc.type(), pParent);
332          return X86RelocationFactory::OK;
333      }
334    }
335  }
336
337   // perform static relocation
338  pReloc.target() = S + A - P;
339  return X86RelocationFactory::OK;
340}
341
342// R_386_GOTOFF: S + A - GOT_ORG
343X86RelocationFactory::Result gotoff32(Relocation& pReloc,
344                                      const MCLDInfo& pLDInfo,
345                                      X86RelocationFactory& pParent)
346{
347  RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
348  X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
349  X86RelocationFactory::Address S = pReloc.symValue();
350
351  pReloc.target() = S + A - GOT_ORG;
352  return X86RelocationFactory::OK;
353}
354
355// R_386_GOTPC: GOT_ORG + A - P
356X86RelocationFactory::Result gotpc32(Relocation& pReloc,
357                                     const MCLDInfo& pLDInfo,
358                                     X86RelocationFactory& pParent)
359{
360  RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
361  X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
362  // Apply relocation.
363  pReloc.target() = GOT_ORG + A - pReloc.place(pParent.getLayout());
364  return X86RelocationFactory::OK;
365}
366
367// R_386_GOT32: GOT(S) + A - GOT_ORG
368X86RelocationFactory::Result got32(Relocation& pReloc,
369                                   const MCLDInfo& pLDInfo,
370                                   X86RelocationFactory& pParent)
371{
372  if (!(pReloc.symInfo()->reserved()
373       & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
374    return X86RelocationFactory::BadReloc;
375  }
376  X86RelocationFactory::Address GOT_S   = helper_GOT(pReloc, pLDInfo, pParent);
377  RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
378  X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
379  // Apply relocation.
380  pReloc.target() = GOT_S + A - GOT_ORG;
381  return X86RelocationFactory::OK;
382}
383
384// R_386_PLT32: PLT(S) + A - P
385X86RelocationFactory::Result plt32(Relocation& pReloc,
386                                   const MCLDInfo& pLDInfo,
387                                   X86RelocationFactory& pParent)
388{
389  // PLT_S depends on if there is a PLT entry.
390  X86RelocationFactory::Address PLT_S;
391  if ((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
392    PLT_S = helper_PLT(pReloc, pParent);
393  else
394    PLT_S = pReloc.symValue();
395  RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
396  X86RelocationFactory::Address P = pReloc.place(pParent.getLayout());
397  pReloc.target() = PLT_S + A - P;
398  return X86RelocationFactory::OK;
399}
400