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