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