• 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 
18 #include <string>
19 
20 using namespace mcld;
21 
22 //===----------------------------------------------------------------------===//
23 // StubFactory
24 //===----------------------------------------------------------------------===//
~StubFactory()25 StubFactory::~StubFactory()
26 {
27   for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
28        it != ie; ++it)
29     delete(*it);
30 }
31 
32 /// addPrototype - register a stub prototype
addPrototype(Stub * pPrototype)33 void StubFactory::addPrototype(Stub* pPrototype)
34 {
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 {
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       // reset the branch target to the stub instead!
64       pReloc.setSymInfo(stub->symInfo());
65     } else {
66       // find if there is such a stub in the forward island.
67       stub = islands.first->findStub(prototype, pReloc);
68       if (stub != NULL) {
69         // reset the branch target to the stub instead!
70         pReloc.setSymInfo(stub->symInfo());
71       } else {
72         // create a stub from the prototype
73         stub = prototype->clone();
74 
75         // build a name for stub symbol
76         std::string name("__");
77         name.append(pReloc.symInfo()->name())
78             .append("_")
79             .append(stub->name())
80             .append("@")
81             .append(islands.first->name());
82 
83         // create LDSymbol for the stub
84         LDSymbol* symbol =
85             pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
86                 name,
87                 ResolveInfo::Function,
88                 ResolveInfo::Define,
89                 ResolveInfo::Local,
90                 stub->size(), // size
91                 stub->initSymValue(), // value
92                 FragmentRef::Create(*stub, stub->initSymValue()),
93                 ResolveInfo::Default);
94         stub->setSymInfo(symbol->resolveInfo());
95 
96         // add relocations of this stub (i.e., set the branch target of the stub)
97         for (Stub::fixup_iterator it = stub->fixup_begin(),
98              ie = stub->fixup_end(); it != ie; ++it) {
99 
100           Relocation* reloc =
101               Relocation::Create((*it)->type(),
102                                  *(FragmentRef::Create(*stub, (*it)->offset())),
103                                  (*it)->addend());
104           reloc->setSymInfo(pReloc.symInfo());
105           islands.first->addRelocation(*reloc);
106         }
107 
108         // add stub to the forward branch island
109         islands.first->addStub(prototype, pReloc, *stub);
110 
111         // reset the branch target of the input reloc to this stub instead!
112         pReloc.setSymInfo(stub->symInfo());
113       }
114     }
115   }
116   return stub;
117 }
118 
119 /// findPrototype - find if there is a registered stub prototype for the given
120 /// relocation
findPrototype(const Relocation & pReloc,uint64_t pSource,uint64_t pTargetSymValue)121 Stub* StubFactory::findPrototype(const Relocation& pReloc,
122                                  uint64_t pSource,
123                                  uint64_t pTargetSymValue)
124 {
125   for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
126        it != ie; ++it) {
127     if ((*it)->isMyDuty(pReloc, pSource, pTargetSymValue))
128       return (*it);
129   }
130   return NULL;
131 }
132