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/FragmentRef.h"
13#include "mcld/Fragment/Relocation.h"
14#include "mcld/Fragment/Stub.h"
15#include "mcld/LD/BranchIsland.h"
16#include "mcld/LD/BranchIslandFactory.h"
17#include "mcld/LD/LDSymbol.h"
18#include "mcld/LD/ResolveInfo.h"
19
20#include <string>
21
22namespace mcld {
23
24//===----------------------------------------------------------------------===//
25// StubFactory
26//===----------------------------------------------------------------------===//
27StubFactory::~StubFactory() {
28  for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end();
29       it != ie;
30       ++it)
31    delete (*it);
32}
33
34/// addPrototype - register a stub prototype
35void StubFactory::addPrototype(Stub* pPrototype) {
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  // 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      // find if there is such a stub in the forward island.
64      stub = islands.first->findStub(prototype, pReloc);
65      if (stub == NULL) {
66        // create a stub from the prototype
67        stub = prototype->clone();
68
69        // apply fixups in this new stub
70        stub->applyFixup(pReloc, pBuilder, *islands.first);
71
72        // add stub to the forward branch island
73        islands.first->addStub(prototype, pReloc, *stub);
74      }
75    }
76  }
77  return stub;
78}
79
80Stub* StubFactory::create(FragmentRef& pFragRef,
81                          IRBuilder& pBuilder,
82                          BranchIslandFactory& pBRIslandFactory) {
83  Stub* prototype = findPrototype(pFragRef);
84  if (prototype == NULL) {
85    return NULL;
86  } else {
87    std::pair<BranchIsland*, BranchIsland*> islands =
88        pBRIslandFactory.getIslands(*(pFragRef.frag()));
89    // early exit if we can not find the forward island.
90    if (islands.first == NULL) {
91      return NULL;
92    } else {
93      // create a stub from the prototype
94      Stub* stub = prototype->clone();
95
96      // apply fixups in this new stub
97      stub->applyFixup(pFragRef, pBuilder, *islands.first);
98
99      // add stub to the forward branch island
100      islands.first->addStub(*stub);
101
102      return stub;
103    }  // (islands.first == NULL)
104  }  // if (prototype == NULL)
105}
106
107/// findPrototype - find if there is a registered stub prototype for the given
108/// relocation
109Stub* StubFactory::findPrototype(const Relocation& pReloc,
110                                 uint64_t pSource,
111                                 uint64_t pTargetSymValue) const {
112  for (StubPoolType::const_iterator it = m_StubPool.begin(),
113                                    ie = m_StubPool.end(); it != ie; ++it) {
114    if ((*it)->isMyDuty(pReloc, pSource, pTargetSymValue))
115      return (*it);
116  }
117  return NULL;
118}
119
120Stub* StubFactory::findPrototype(const FragmentRef& pFragRef) const {
121  for (StubPoolType::const_iterator it = m_StubPool.begin(),
122                                    ie = m_StubPool.end(); it != ie; ++it) {
123    if ((*it)->isMyDuty(pFragRef))
124      return (*it);
125  }
126  return NULL;
127}
128
129}  // namespace mcld
130