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