• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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 "X86RelocationFactory.h"
18 #include "X86RelocationFunctions.h"
19 
20 using namespace mcld;
21 
22 DECL_X86_APPLY_RELOC_FUNCS
23 
24 //===--------------------------------------------------------------------===//
25 // X86RelocationFactory
X86RelocationFactory(size_t pNum,X86GNULDBackend & pParent)26 X86RelocationFactory::X86RelocationFactory(size_t pNum,
27                                            X86GNULDBackend& pParent)
28   : RelocationFactory(pNum),
29     m_Target(pParent) {
30 }
31 
~X86RelocationFactory()32 X86RelocationFactory::~X86RelocationFactory()
33 {
34 }
35 
applyRelocation(Relocation & pRelocation,const MCLDInfo & pLDInfo)36 void X86RelocationFactory::applyRelocation(Relocation& pRelocation,
37                                            const MCLDInfo& pLDInfo)
38 {
39   Relocation::Type type = pRelocation.type();
40 
41   /// the prototype of applying function
42   typedef Result (*ApplyFunctionType)(Relocation& pReloc,
43 				      const MCLDInfo& pLDInfo,
44                                       X86RelocationFactory& pParent);
45 
46   // the table entry of applying functions
47   struct ApplyFunctionTriple {
48     ApplyFunctionType func;
49     unsigned int type;
50     const char* name;
51   };
52 
53   // declare the table of applying functions
54   static ApplyFunctionTriple apply_functions[] = {
55     DECL_X86_APPLY_RELOC_FUNC_PTRS
56   };
57 
58   if (type >= sizeof (apply_functions) / sizeof (apply_functions[0]) ) {
59     llvm::report_fatal_error(llvm::Twine("Unknown relocation type ") +
60 			     llvm::Twine((int) type) +
61 			     llvm::Twine(" to symbol `") +
62                              pRelocation.symInfo()->name() +
63                              llvm::Twine("'."));
64     return;
65   }
66 
67   // apply the relocation
68   Result result = apply_functions[type].func(pRelocation, pLDInfo, *this);
69 
70   // check result
71   if (Overflow == result) {
72     llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
73                              llvm::Twine(apply_functions[type].name) +
74                              llvm::Twine("' causes overflow. on symbol: `") +
75                              llvm::Twine(pRelocation.symInfo()->name()) +
76                              llvm::Twine("'."));
77     return;
78   }
79 
80   if (BadReloc == result) {
81     llvm::report_fatal_error(llvm::Twine("Applying relocation `") +
82                              llvm::Twine(apply_functions[type].name) +
83                              llvm::Twine("' encounters unexpected opcode. "
84                                          "on symbol: `") +
85                              llvm::Twine(pRelocation.symInfo()->name()) +
86                              llvm::Twine("'."));
87     return;
88   }
89 }
90 
91 
92 
93 // non-member functions
94 
95 //=========================================//
96 // Relocation helper function              //
97 //=========================================//
98 
99 // Check if symbol can use relocation R_386_RELATIVE
100 static bool
helper_use_relative_reloc(const ResolveInfo & pSym,const MCLDInfo & pLDInfo,const X86RelocationFactory & pFactory)101 helper_use_relative_reloc(const ResolveInfo& pSym,
102                           const MCLDInfo& pLDInfo,
103                           const X86RelocationFactory& pFactory)
104 
105 {
106   // if symbol is dynamic or undefine or preemptible
107   if(pSym.isDyn() ||
108      pSym.isUndef() ||
109      pFactory.getTarget().isSymbolPreemptible(pSym, pLDInfo, pLDInfo.output()))
110     return false;
111   return true;
112 }
113 
114 static
helper_get_GOT_and_init(Relocation & pReloc,const MCLDInfo & pLDInfo,X86RelocationFactory & pParent)115 GOTEntry& helper_get_GOT_and_init(Relocation& pReloc,
116                                   const MCLDInfo& pLDInfo,
117                                   X86RelocationFactory& pParent)
118 {
119   // rsym - The relocation target symbol
120   ResolveInfo* rsym = pReloc.symInfo();
121   X86GNULDBackend& ld_backend = pParent.getTarget();
122 
123   bool exist;
124   GOTEntry& got_entry = *ld_backend.getGOT().getEntry(*rsym, exist);
125   if (!exist) {
126     // If we first get this GOT entry, we should initialize it.
127     if (rsym->reserved() & X86GNULDBackend::ReserveGOT) {
128       // No corresponding dynamic relocation, initialize to the symbol value.
129       got_entry.setContent(pReloc.symValue());
130     }
131     else if (rsym->reserved() & X86GNULDBackend::GOTRel) {
132       // Initialize corresponding dynamic relocation.
133       Relocation& rel_entry =
134         *ld_backend.getRelDyn().getEntry(*rsym, true, exist);
135       assert(!exist && "GOT entry not exist, but DynRel entry exist!");
136       if(helper_use_relative_reloc(*rsym, pLDInfo, pParent)) {
137         // Initialize got entry to target symbol address
138         got_entry.setContent(pReloc.symValue());
139         rel_entry.setType(llvm::ELF::R_386_RELATIVE);
140         rel_entry.setSymInfo(0);
141       }
142       else {
143         got_entry.setContent(0);
144         rel_entry.setType(llvm::ELF::R_386_GLOB_DAT);
145         rel_entry.setSymInfo(rsym);
146       }
147       rel_entry.targetRef().assign(got_entry);
148     }
149     else {
150       llvm::report_fatal_error("No GOT entry reserved for GOT type relocation!");
151     }
152   }
153   return got_entry;
154 }
155 
156 
157 static
helper_GOT_ORG(X86RelocationFactory & pParent)158 X86RelocationFactory::Address helper_GOT_ORG(X86RelocationFactory& pParent)
159 {
160   return pParent.getTarget().getGOT().getSection().addr();
161 }
162 
163 
164 static
helper_GOT(Relocation & pReloc,const MCLDInfo & pLDInfo,X86RelocationFactory & pParent)165 X86RelocationFactory::Address helper_GOT(Relocation& pReloc,
166                                          const MCLDInfo& pLDInfo,
167                                          X86RelocationFactory& pParent)
168 {
169   GOTEntry& got_entry = helper_get_GOT_and_init(pReloc, pLDInfo,  pParent);
170   return helper_GOT_ORG(pParent) + pParent.getLayout().getOutputOffset(got_entry);
171 }
172 
173 
174 static
helper_get_PLT_and_init(Relocation & pReloc,X86RelocationFactory & pParent)175 PLTEntry& helper_get_PLT_and_init(Relocation& pReloc,
176                                   X86RelocationFactory& pParent)
177 {
178   // rsym - The relocation target symbol
179   ResolveInfo* rsym = pReloc.symInfo();
180   X86GNULDBackend& ld_backend = pParent.getTarget();
181 
182   bool exist;
183   PLTEntry& plt_entry = *ld_backend.getPLT().getPLTEntry(*rsym, exist);
184   if (!exist) {
185     // If we first get this PLT entry, we should initialize it.
186     if (rsym->reserved() & X86GNULDBackend::ReservePLT) {
187       GOTEntry& gotplt_entry =
188         *ld_backend.getPLT().getGOTPLTEntry(*rsym, exist);
189       // Initialize corresponding dynamic relocation.
190       Relocation& rel_entry =
191         *ld_backend.getRelPLT().getEntry(*rsym, true, exist);
192       assert(!exist && "PLT entry not exist, but DynRel entry exist!");
193       rel_entry.setType(llvm::ELF::R_386_JUMP_SLOT);
194       rel_entry.targetRef().assign(gotplt_entry);
195       rel_entry.setSymInfo(rsym);
196     }
197     else {
198       llvm::report_fatal_error("No PLT entry reserved for PLT type relocation!");
199     }
200   }
201   return plt_entry;
202 }
203 
204 
205 
206 static
helper_PLT_ORG(X86RelocationFactory & pParent)207 X86RelocationFactory::Address helper_PLT_ORG(X86RelocationFactory& pParent)
208 {
209   return pParent.getTarget().getPLT().getSection().addr();
210 }
211 
212 
213 static
helper_PLT(Relocation & pReloc,X86RelocationFactory & pParent)214 X86RelocationFactory::Address helper_PLT(Relocation& pReloc,
215                                          X86RelocationFactory& pParent)
216 {
217   PLTEntry& plt_entry = helper_get_PLT_and_init(pReloc, pParent);
218   return helper_PLT_ORG(pParent) + pParent.getLayout().getOutputOffset(plt_entry);
219 }
220 
221 // Get an relocation entry in .rel.dyn and set its type to pType,
222 // its FragmentRef to pReloc->targetFrag() and its ResolveInfo to pReloc->symInfo()
223 static
helper_DynRel(Relocation & pReloc,X86RelocationFactory::Type pType,X86RelocationFactory & pParent)224 void helper_DynRel(Relocation& pReloc,
225                    X86RelocationFactory::Type pType,
226                    X86RelocationFactory& pParent)
227 {
228   // rsym - The relocation target symbol
229   ResolveInfo* rsym = pReloc.symInfo();
230   X86GNULDBackend& ld_backend = pParent.getTarget();
231   bool exist;
232 
233   Relocation& rel_entry =
234     *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
235   rel_entry.setType(pType);
236   rel_entry.targetRef() = pReloc.targetRef();
237 
238   if(pType == llvm::ELF::R_386_RELATIVE)
239     rel_entry.setSymInfo(0);
240   else
241     rel_entry.setSymInfo(rsym);
242 }
243 
244 
245 //=========================================//
246 // Each relocation function implementation //
247 //=========================================//
248 
249 // R_386_NONE
none(Relocation & pReloc,const MCLDInfo & pLDInfo,X86RelocationFactory & pParent)250 X86RelocationFactory::Result none(Relocation& pReloc,
251                                   const MCLDInfo& pLDInfo,
252                                   X86RelocationFactory& pParent)
253 {
254   return X86RelocationFactory::OK;
255 }
256 
257 // R_386_32: S + A
abs32(Relocation & pReloc,const MCLDInfo & pLDInfo,X86RelocationFactory & pParent)258 X86RelocationFactory::Result abs32(Relocation& pReloc,
259                                    const MCLDInfo& pLDInfo,
260                                    X86RelocationFactory& pParent)
261 {
262   ResolveInfo* rsym = pReloc.symInfo();
263   RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
264   RelocationFactory::DWord S = pReloc.symValue();
265 
266   if(rsym->isLocal() && (rsym->reserved() & X86GNULDBackend::ReserveRel)) {
267     helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
268     pReloc.target() = S + A;
269     return X86RelocationFactory::OK;
270   }
271   else if(!rsym->isLocal()) {
272     if(rsym->reserved() & X86GNULDBackend::ReservePLT) {
273       S = helper_PLT(pReloc, pParent);
274       pReloc.target() = S + A;
275     }
276     if(rsym->reserved() & X86GNULDBackend::ReserveRel) {
277       if(helper_use_relative_reloc(*rsym, pLDInfo, pParent) ) {
278         helper_DynRel(pReloc, llvm::ELF::R_386_RELATIVE, pParent);
279       }
280       else {
281         helper_DynRel(pReloc, pReloc.type(), pParent);
282         return X86RelocationFactory::OK;
283       }
284     }
285   }
286 
287   // perform static relocation
288   pReloc.target() = S + A;
289   return X86RelocationFactory::OK;
290 }
291 
292 // R_386_PC32: S + A - P
rel32(Relocation & pReloc,const MCLDInfo & pLDInfo,X86RelocationFactory & pParent)293 X86RelocationFactory::Result rel32(Relocation& pReloc,
294                                    const MCLDInfo& pLDInfo,
295                                    X86RelocationFactory& pParent)
296 {
297   // perform static relocation
298   RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
299   pReloc.target() = pReloc.symValue() + A
300       - pReloc.place(pParent.getLayout());
301   return X86RelocationFactory::OK;
302 }
303 
304 // R_386_GOTOFF: S + A - GOT_ORG
gotoff32(Relocation & pReloc,const MCLDInfo & pLDInfo,X86RelocationFactory & pParent)305 X86RelocationFactory::Result gotoff32(Relocation& pReloc,
306                                       const MCLDInfo& pLDInfo,
307                                       X86RelocationFactory& pParent)
308 {
309   RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
310   X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
311   X86RelocationFactory::Address S = pReloc.symValue();
312 
313   pReloc.target() = S + A - GOT_ORG;
314   return X86RelocationFactory::OK;
315 }
316 
317 // R_386_GOTPC: GOT_ORG + A - P
gotpc32(Relocation & pReloc,const MCLDInfo & pLDInfo,X86RelocationFactory & pParent)318 X86RelocationFactory::Result gotpc32(Relocation& pReloc,
319                                      const MCLDInfo& pLDInfo,
320                                      X86RelocationFactory& pParent)
321 {
322   RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
323   X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
324   // Apply relocation.
325   pReloc.target() = GOT_ORG + A - pReloc.place(pParent.getLayout());
326   return X86RelocationFactory::OK;
327 }
328 
329 // R_386_GOT32: GOT(S) + A - GOT_ORG
got32(Relocation & pReloc,const MCLDInfo & pLDInfo,X86RelocationFactory & pParent)330 X86RelocationFactory::Result got32(Relocation& pReloc,
331                                    const MCLDInfo& pLDInfo,
332                                    X86RelocationFactory& pParent)
333 {
334   if(!(pReloc.symInfo()->reserved()
335        & (X86GNULDBackend::ReserveGOT |X86GNULDBackend::GOTRel))) {
336     return X86RelocationFactory::BadReloc;
337   }
338   X86RelocationFactory::Address GOT_S   = helper_GOT(pReloc, pLDInfo, pParent);
339   RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
340   X86RelocationFactory::Address GOT_ORG = helper_GOT_ORG(pParent);
341   // Apply relocation.
342   pReloc.target() = GOT_S + A - GOT_ORG;
343   return X86RelocationFactory::OK;
344 }
345 
346 // R_386_PLT32: PLT(S) + A - P
plt32(Relocation & pReloc,const MCLDInfo & pLDInfo,X86RelocationFactory & pParent)347 X86RelocationFactory::Result plt32(Relocation& pReloc,
348                                    const MCLDInfo& pLDInfo,
349                                    X86RelocationFactory& pParent)
350 {
351   // PLT_S depends on if there is a PLT entry.
352   X86RelocationFactory::Address PLT_S;
353   if((pReloc.symInfo()->reserved() & X86GNULDBackend::ReservePLT))
354     PLT_S = helper_PLT(pReloc, pParent);
355   else
356     PLT_S = pReloc.symValue();
357   RelocationFactory::DWord   A       = pReloc.target() + pReloc.addend();
358   X86RelocationFactory::Address P = pReloc.place(pParent.getLayout());
359   pReloc.target() = PLT_S + A - P;
360   return X86RelocationFactory::OK;
361 }
362