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