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