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