1 //===- StubFactory.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 "mcld/LD/StubFactory.h"
10
11 #include "mcld/IRBuilder.h"
12 #include "mcld/Fragment/FragmentRef.h"
13 #include "mcld/Fragment/Relocation.h"
14 #include "mcld/Fragment/Stub.h"
15 #include "mcld/LD/BranchIsland.h"
16 #include "mcld/LD/BranchIslandFactory.h"
17 #include "mcld/LD/LDSymbol.h"
18 #include "mcld/LD/ResolveInfo.h"
19
20 #include <string>
21
22 namespace mcld {
23
24 //===----------------------------------------------------------------------===//
25 // StubFactory
26 //===----------------------------------------------------------------------===//
~StubFactory()27 StubFactory::~StubFactory() {
28 for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
29 it != ie;
30 ++it)
31 delete (*it);
32 }
33
34 /// addPrototype - register a stub prototype
addPrototype(Stub * pPrototype)35 void StubFactory::addPrototype(Stub* pPrototype) {
36 m_StubPool.push_back(pPrototype);
37 }
38
39 /// create - create a stub if needed, otherwise return NULL
create(Relocation & pReloc,uint64_t pTargetSymValue,IRBuilder & pBuilder,BranchIslandFactory & pBRIslandFactory)40 Stub* StubFactory::create(Relocation& pReloc,
41 uint64_t pTargetSymValue,
42 IRBuilder& pBuilder,
43 BranchIslandFactory& pBRIslandFactory) {
44 // find if there is a prototype stub for the input relocation
45 Stub* stub = NULL;
46 Stub* prototype = findPrototype(pReloc, pReloc.place(), pTargetSymValue);
47 if (prototype != NULL) {
48 const Fragment* frag = pReloc.targetRef().frag();
49 // find the islands for the input relocation
50 std::pair<BranchIsland*, BranchIsland*> islands =
51 pBRIslandFactory.getIslands(*frag);
52 if (islands.first == NULL) {
53 // early exit if we can not find the forward island.
54 return NULL;
55 }
56
57 // find if there is such a stub in the backward island first.
58 if (islands.second != NULL) {
59 stub = islands.second->findStub(prototype, pReloc);
60 }
61
62 if (stub == NULL) {
63 // find if there is such a stub in the forward island.
64 stub = islands.first->findStub(prototype, pReloc);
65 if (stub == NULL) {
66 // create a stub from the prototype
67 stub = prototype->clone();
68
69 // apply fixups in this new stub
70 stub->applyFixup(pReloc, pBuilder, *islands.first);
71
72 // add stub to the forward branch island
73 islands.first->addStub(prototype, pReloc, *stub);
74 }
75 }
76 }
77 return stub;
78 }
79
create(FragmentRef & pFragRef,IRBuilder & pBuilder,BranchIslandFactory & pBRIslandFactory)80 Stub* StubFactory::create(FragmentRef& pFragRef,
81 IRBuilder& pBuilder,
82 BranchIslandFactory& pBRIslandFactory) {
83 Stub* prototype = findPrototype(pFragRef);
84 if (prototype == NULL) {
85 return NULL;
86 } else {
87 std::pair<BranchIsland*, BranchIsland*> islands =
88 pBRIslandFactory.getIslands(*(pFragRef.frag()));
89 // early exit if we can not find the forward island.
90 if (islands.first == NULL) {
91 return NULL;
92 } else {
93 // create a stub from the prototype
94 Stub* stub = prototype->clone();
95
96 // apply fixups in this new stub
97 stub->applyFixup(pFragRef, pBuilder, *islands.first);
98
99 // add stub to the forward branch island
100 islands.first->addStub(*stub);
101
102 return stub;
103 } // (islands.first == NULL)
104 } // if (prototype == NULL)
105 }
106
107 /// findPrototype - find if there is a registered stub prototype for the given
108 /// relocation
findPrototype(const Relocation & pReloc,uint64_t pSource,uint64_t pTargetSymValue) const109 Stub* StubFactory::findPrototype(const Relocation& pReloc,
110 uint64_t pSource,
111 uint64_t pTargetSymValue) const {
112 for (StubPoolType::const_iterator it = m_StubPool.begin(),
113 ie = m_StubPool.end(); it != ie; ++it) {
114 if ((*it)->isMyDuty(pReloc, pSource, pTargetSymValue))
115 return (*it);
116 }
117 return NULL;
118 }
119
findPrototype(const FragmentRef & pFragRef) const120 Stub* StubFactory::findPrototype(const FragmentRef& pFragRef) const {
121 for (StubPoolType::const_iterator it = m_StubPool.begin(),
122 ie = m_StubPool.end(); it != ie; ++it) {
123 if ((*it)->isMyDuty(pFragRef))
124 return (*it);
125 }
126 return NULL;
127 }
128
129 } // namespace mcld
130