• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- MipsRelocationFactory.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/ELF.h>
12 #include <mcld/LD/Layout.h>
13 #include <mcld/Target/OutputRelocSection.h>
14 #include <mcld/Support/MsgHandling.h>
15 
16 #include "MipsRelocationFactory.h"
17 #include "MipsRelocationFunctions.h"
18 
19 using namespace mcld;
20 
21 //===----------------------------------------------------------------------===//
22 // Relocation Functions and Tables
23 //===----------------------------------------------------------------------===//
24 DECL_MIPS_APPLY_RELOC_FUNCS
25 
26 /// the prototype of applying function
27 typedef RelocationFactory::Result (*ApplyFunctionType)(Relocation&,
28                                                        const MCLDInfo& pLDInfo,
29                                                        MipsRelocationFactory&);
30 
31 // the table entry of applying functions
32 struct ApplyFunctionTriple
33 {
34   ApplyFunctionType func;
35   unsigned int type;
36   const char* name;
37 };
38 
39 // declare the table of applying functions
40 static const ApplyFunctionTriple ApplyFunctions[] = {
41   DECL_MIPS_APPLY_RELOC_FUNC_PTRS
42 };
43 
44 //===----------------------------------------------------------------------===//
45 // MipsRelocationFactory
46 //===----------------------------------------------------------------------===//
MipsRelocationFactory(size_t pNum,MipsGNULDBackend & pParent)47 MipsRelocationFactory::MipsRelocationFactory(size_t pNum,
48                                              MipsGNULDBackend& pParent)
49   : RelocationFactory(pNum),
50     m_Target(pParent),
51     m_AHL(0)
52 {
53 }
54 
55 RelocationFactory::Result
applyRelocation(Relocation & pRelocation,const MCLDInfo & pLDInfo)56 MipsRelocationFactory::applyRelocation(Relocation& pRelocation,
57                                        const MCLDInfo& pLDInfo)
58 
59 {
60   Relocation::Type type = pRelocation.type();
61 
62   if (type >= sizeof(ApplyFunctions) / sizeof(ApplyFunctions[0])) {
63     fatal(diag::unknown_relocation) << (int)type
64                                     << pRelocation.symInfo()->name();
65     return Unknown;
66   }
67 
68   // apply the relocation
69   return ApplyFunctions[type].func(pRelocation, pLDInfo, *this);
70 }
71 
getName(Relocation::Type pType) const72 const char* MipsRelocationFactory::getName(Relocation::Type pType) const
73 {
74   return ApplyFunctions[pType].name;
75 }
76 
77 //===----------------------------------------------------------------------===//
78 // Relocation helper function
79 
80 //===----------------------------------------------------------------------===//
81 static const char * const GP_DISP_NAME = "_gp_disp";
82 
83 // Find next R_MIPS_LO16 relocation paired to pReloc.
84 static
helper_FindLo16Reloc(Relocation & pReloc)85 Relocation* helper_FindLo16Reloc(Relocation& pReloc)
86 {
87   Relocation* reloc = static_cast<Relocation*>(pReloc.getNextNode());
88   while (NULL != reloc)
89   {
90     if (llvm::ELF::R_MIPS_LO16 == reloc->type() &&
91         reloc->symInfo() == pReloc.symInfo())
92       return reloc;
93 
94     reloc = static_cast<Relocation*>(reloc->getNextNode());
95   }
96   return NULL;
97 }
98 
99 // Check the symbol is _gp_disp.
100 static
helper_isGpDisp(const Relocation & pReloc)101 bool helper_isGpDisp(const Relocation& pReloc)
102 {
103   const ResolveInfo* rsym = pReloc.symInfo();
104   return 0 == strcmp(GP_DISP_NAME, rsym->name());
105 }
106 
107 static
helper_GetGP(MipsRelocationFactory & pParent)108 RelocationFactory::Address helper_GetGP(MipsRelocationFactory& pParent)
109 {
110   return pParent.getTarget().getGOT().getSection().addr() + 0x7FF0;
111 }
112 
113 static
helper_GetGOTEntry(Relocation & pReloc,MipsRelocationFactory & pParent,bool & pExist,int32_t value)114 GOTEntry& helper_GetGOTEntry(Relocation& pReloc,
115                              MipsRelocationFactory& pParent,
116                              bool& pExist, int32_t value)
117 {
118   // rsym - The relocation target symbol
119   ResolveInfo* rsym = pReloc.symInfo();
120   MipsGNULDBackend& ld_backend = pParent.getTarget();
121   MipsGOT& got = ld_backend.getGOT();
122 
123   GOTEntry& got_entry = *got.getEntry(*rsym, pExist);
124 
125   if (pExist)
126     return got_entry;
127 
128   // If we first get this GOT entry, we should initialize it.
129   if (!(got.isLocal(rsym) && rsym->type() == ResolveInfo::Section)) {
130     if (rsym->reserved() & MipsGNULDBackend::ReserveGot) {
131       got_entry.setContent(pReloc.symValue());
132     }
133     else {
134       fatal(diag::reserve_entry_number_mismatch_got);
135     }
136   }
137 
138   return got_entry;
139 }
140 
141 static
helper_GetGOTOffset(Relocation & pReloc,MipsRelocationFactory & pParent)142 RelocationFactory::Address helper_GetGOTOffset(Relocation& pReloc,
143                                                MipsRelocationFactory& pParent)
144 {
145   bool exist;
146   GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent, exist, 0);
147   return pParent.getLayout().getOutputOffset(got_entry) - 0x7FF0;
148 }
149 
150 static
helper_CalcAHL(const Relocation & pHiReloc,const Relocation & pLoReloc)151 int32_t helper_CalcAHL(const Relocation& pHiReloc, const Relocation& pLoReloc)
152 {
153   assert((pHiReloc.type() == llvm::ELF::R_MIPS_HI16 ||
154           pHiReloc.type() == llvm::ELF::R_MIPS_GOT16) &&
155          pLoReloc.type() == llvm::ELF::R_MIPS_LO16 &&
156          "Incorrect type of relocation for AHL calculation");
157 
158   // Note the addend is section symbol offset here
159   assert (pHiReloc.addend() == pLoReloc.addend());
160 
161   int32_t AHI = pHiReloc.target();
162   int32_t ALO = pLoReloc.target();
163   int32_t AHL = ((AHI & 0xFFFF) << 16) + (int16_t)(ALO & 0xFFFF) + pLoReloc.addend();
164   return AHL;
165 }
166 
167 static
helper_DynRel(Relocation & pReloc,MipsRelocationFactory & pParent)168 void helper_DynRel(Relocation& pReloc,
169                    MipsRelocationFactory& pParent)
170 {
171   ResolveInfo* rsym = pReloc.symInfo();
172   MipsGNULDBackend& ld_backend = pParent.getTarget();
173   MipsGOT& got = ld_backend.getGOT();
174 
175   bool exist;
176   Relocation& rel_entry =
177     *ld_backend.getRelDyn().getEntry(*rsym, false, exist);
178 
179   rel_entry.setType(llvm::ELF::R_MIPS_REL32);
180   rel_entry.targetRef() = pReloc.targetRef();
181 
182   RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
183   RelocationFactory::DWord S = pReloc.symValue();
184 
185   if (got.isLocal(rsym)) {
186     rel_entry.setSymInfo(NULL);
187     pReloc.target() = A + S;
188   }
189   else {
190     rel_entry.setSymInfo(rsym);
191     // Don't add symbol value that will be resolved by the dynamic linker
192     pReloc.target() = A;
193   }
194 }
195 
196 //=========================================//
197 // Relocation functions implementation     //
198 //=========================================//
199 
200 // R_MIPS_NONE and those unsupported/deprecated relocation type
201 static
none(Relocation & pReloc,const MCLDInfo & pLDInfo,MipsRelocationFactory & pParent)202 MipsRelocationFactory::Result none(Relocation& pReloc,
203                                    const MCLDInfo& pLDInfo,
204                                    MipsRelocationFactory& pParent)
205 {
206   return MipsRelocationFactory::OK;
207 }
208 
209 // R_MIPS_32: S + A
210 static
abs32(Relocation & pReloc,const MCLDInfo & pLDInfo,MipsRelocationFactory & pParent)211 MipsRelocationFactory::Result abs32(Relocation& pReloc,
212                                     const MCLDInfo& pLDInfo,
213                                     MipsRelocationFactory& pParent)
214 {
215   ResolveInfo* rsym = pReloc.symInfo();
216 
217   RelocationFactory::DWord A = pReloc.target() + pReloc.addend();
218   RelocationFactory::DWord S = pReloc.symValue();
219 
220   const LDSection* target_sect = pParent.getLayout().getOutputLDSection(
221                                                   *(pReloc.targetRef().frag()));
222   assert(NULL != target_sect);
223   // If the flag of target section is not ALLOC, we will not scan this relocation
224   // but perform static relocation. (e.g., applying .debug section)
225   if (0x0 == (llvm::ELF::SHF_ALLOC & target_sect->flag())) {
226     pReloc.target() = S + A;
227     return MipsRelocationFactory::OK;
228   }
229 
230   if (rsym->reserved() & MipsGNULDBackend::ReserveRel) {
231     helper_DynRel(pReloc, pParent);
232 
233     return MipsRelocationFactory::OK;
234   }
235 
236   pReloc.target() = (S + A);
237 
238   return MipsRelocationFactory::OK;
239 }
240 
241 // R_MIPS_HI16:
242 //   local/external: ((AHL + S) - (short)(AHL + S)) >> 16
243 //   _gp_disp      : ((AHL + GP - P) - (short)(AHL + GP - P)) >> 16
244 static
hi16(Relocation & pReloc,const MCLDInfo & pLDInfo,MipsRelocationFactory & pParent)245 MipsRelocationFactory::Result hi16(Relocation& pReloc,
246                                    const MCLDInfo& pLDInfo,
247                                    MipsRelocationFactory& pParent)
248 {
249   Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
250   assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_HI16");
251 
252   int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
253   int32_t res = 0;
254 
255   pParent.setAHL(AHL);
256 
257   if (helper_isGpDisp(pReloc)) {
258     int32_t P = pReloc.place(pParent.getLayout());
259     int32_t GP = helper_GetGP(pParent);
260     res = ((AHL + GP - P) - (int16_t)(AHL + GP - P)) >> 16;
261   }
262   else {
263     int32_t S = pReloc.symValue();
264     res = ((AHL + S) - (int16_t)(AHL + S)) >> 16;
265   }
266 
267   pReloc.target() &= 0xFFFF0000;
268   pReloc.target() |= (res & 0xFFFF);
269 
270   return MipsRelocationFactory::OK;
271 }
272 
273 // R_MIPS_LO16:
274 //   local/external: AHL + S
275 //   _gp_disp      : AHL + GP - P + 4
276 static
lo16(Relocation & pReloc,const MCLDInfo & pLDInfo,MipsRelocationFactory & pParent)277 MipsRelocationFactory::Result lo16(Relocation& pReloc,
278                                    const MCLDInfo& pLDInfo,
279                                    MipsRelocationFactory& pParent)
280 {
281   int32_t res = 0;
282 
283   if (helper_isGpDisp(pReloc)) {
284     int32_t P = pReloc.place(pParent.getLayout());
285     int32_t GP = helper_GetGP(pParent);
286     int32_t AHL = pParent.getAHL();
287     res = AHL + GP - P + 4;
288   }
289   else {
290     int32_t S = pReloc.symValue();
291     // The previous AHL may be for other hi/lo pairs.
292     // We need to calcuate the lo part now.  It is easy.
293     // Remember to add the section offset to ALO.
294     int32_t ALO = (pReloc.target() & 0xFFFF) + pReloc.addend();
295     res = ALO + S;
296   }
297 
298   pReloc.target() &= 0xFFFF0000;
299   pReloc.target() |= (res & 0xFFFF);
300 
301   return MipsRelocationFactory::OK;
302 }
303 
304 // R_MIPS_GOT16:
305 //   local   : G (calculate AHL and put high 16 bit to GOT)
306 //   external: G
307 static
got16(Relocation & pReloc,const MCLDInfo & pLDInfo,MipsRelocationFactory & pParent)308 MipsRelocationFactory::Result got16(Relocation& pReloc,
309                                     const MCLDInfo& pLDInfo,
310                                     MipsRelocationFactory& pParent)
311 {
312   ResolveInfo* rsym = pReloc.symInfo();
313   RelocationFactory::Address G = 0;
314 
315   if (rsym->isLocal()) {
316     Relocation* lo_reloc = helper_FindLo16Reloc(pReloc);
317     assert(NULL != lo_reloc && "There is no paired R_MIPS_LO16 for R_MIPS_GOT16");
318 
319     int32_t AHL = helper_CalcAHL(pReloc, *lo_reloc);
320     int32_t S = pReloc.symValue();
321 
322     pParent.setAHL(AHL);
323 
324     int32_t res = (AHL + S + 0x8000) & 0xFFFF0000;
325     bool exist;
326     GOTEntry& got_entry = helper_GetGOTEntry(pReloc, pParent, exist, res);
327 
328     got_entry.setContent(res);
329     G = pParent.getLayout().getOutputOffset(got_entry) - 0x7FF0;
330   }
331   else {
332     G = helper_GetGOTOffset(pReloc, pParent);
333   }
334 
335   pReloc.target() &= 0xFFFF0000;
336   pReloc.target() |= (G & 0xFFFF);
337 
338   return MipsRelocationFactory::OK;
339 }
340 
341 // R_MIPS_CALL16: G
342 static
call16(Relocation & pReloc,const MCLDInfo & pLDInfo,MipsRelocationFactory & pParent)343 MipsRelocationFactory::Result call16(Relocation& pReloc,
344                                      const MCLDInfo& pLDInfo,
345                                      MipsRelocationFactory& pParent)
346 {
347   RelocationFactory::Address G = helper_GetGOTOffset(pReloc, pParent);
348 
349   pReloc.target() &= 0xFFFF0000;
350   pReloc.target() |= (G & 0xFFFF);
351 
352   return MipsRelocationFactory::OK;
353 }
354 
355 // R_MIPS_GPREL32: A + S + GP0 - GP
356 static
gprel32(Relocation & pReloc,const MCLDInfo & pLDInfo,MipsRelocationFactory & pParent)357 MipsRelocationFactory::Result gprel32(Relocation& pReloc,
358                                       const MCLDInfo& pLDInfo,
359                                       MipsRelocationFactory& pParent)
360 {
361   // Remember to add the section offset to A.
362   int32_t A = pReloc.target() + pReloc.addend();
363   int32_t S = pReloc.symValue();
364   int32_t GP = helper_GetGP(pParent);
365 
366   // llvm does not emits SHT_MIPS_REGINFO section.
367   // Assume that GP0 is zero.
368   pReloc.target() = (A + S - GP) & 0xFFFFFFFF;
369 
370   return MipsRelocationFactory::OK;
371 }
372