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