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