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