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