StubFactory.cpp revision 87f34658dec9097d987d254a990ea7f311bfc95f
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
21using namespace mcld;
22
23//===----------------------------------------------------------------------===//
24// StubFactory
25//===----------------------------------------------------------------------===//
26StubFactory::~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
34void StubFactory::addPrototype(Stub* pPrototype)
35{
36  m_StubPool.push_back(pPrototype);
37}
38
39/// create - create a stub if needed, otherwise return NULL
40Stub* 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      return NULL;
54    }
55
56    // find if there is such a stub in the island already
57    Stub* stub = island->findStub(prototype, pReloc);
58    if (NULL != stub) {
59      // reset the branch target to the stub instead!
60      pReloc.setSymInfo(stub->symInfo());
61    }
62    else {
63      // create a stub from the prototype
64      stub = prototype->clone();
65
66      // build a name for stub symbol
67      std::string name("__");
68      name.append(pReloc.symInfo()->name());
69      name.append("_");
70      name.append(stub->name());
71      name.append("@");
72      name.append(island->name());
73
74      // create LDSymbol for the stub
75      LDSymbol* symbol =
76        pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
77                               name,
78                               ResolveInfo::Function,
79                               ResolveInfo::Define,
80                               ResolveInfo::Local,
81                               stub->size(), // size
82                               stub->initSymValue(), // value
83                               FragmentRef::Create(*stub, stub->initSymValue()),
84                               ResolveInfo::Default);
85      stub->setSymInfo(symbol->resolveInfo());
86
87      // add relocations of this stub (i.e., set the branch target of the stub)
88      for (Stub::fixup_iterator it = stub->fixup_begin(),
89             ie = stub->fixup_end(); it != ie; ++it) {
90
91        Relocation* reloc = Relocation::Create((*it)->type(),
92                                 *(FragmentRef::Create(*stub, (*it)->offset())),
93                                 (*it)->addend());
94        reloc->setSymInfo(pReloc.symInfo());
95        island->addRelocation(*reloc);
96      }
97
98      // add stub to the branch island
99      island->addStub(prototype, pReloc, *stub);
100
101      // reset the branch target of the input reloc to this stub instead!
102      pReloc.setSymInfo(stub->symInfo());
103      return stub;
104    }
105  }
106  return NULL;
107}
108
109/// findPrototype - find if there is a registered stub prototype for the given
110/// relocation
111Stub* StubFactory::findPrototype(const Relocation& pReloc,
112                                 uint64_t pSource,
113                                 uint64_t pTargetSymValue)
114{
115  for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
116       it != ie; ++it) {
117    if ((*it)->isMyDuty(pReloc, pSource, pTargetSymValue))
118      return (*it);
119  }
120  return NULL;
121}
122
123