//===- StubFactory.cpp ----------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "mcld/LD/StubFactory.h" #include "mcld/IRBuilder.h" #include "mcld/Fragment/FragmentRef.h" #include "mcld/Fragment/Relocation.h" #include "mcld/Fragment/Stub.h" #include "mcld/LD/BranchIsland.h" #include "mcld/LD/BranchIslandFactory.h" #include "mcld/LD/LDSymbol.h" #include "mcld/LD/ResolveInfo.h" #include <string> namespace mcld { //===----------------------------------------------------------------------===// // StubFactory //===----------------------------------------------------------------------===// StubFactory::~StubFactory() { for (StubPoolType::iterator it = m_StubPool.begin(), ie = m_StubPool.end(); it != ie; ++it) delete (*it); } /// addPrototype - register a stub prototype void StubFactory::addPrototype(Stub* pPrototype) { m_StubPool.push_back(pPrototype); } /// create - create a stub if needed, otherwise return NULL Stub* StubFactory::create(Relocation& pReloc, uint64_t pTargetSymValue, IRBuilder& pBuilder, BranchIslandFactory& pBRIslandFactory) { // find if there is a prototype stub for the input relocation Stub* stub = NULL; Stub* prototype = findPrototype(pReloc, pReloc.place(), pTargetSymValue); if (prototype != NULL) { const Fragment* frag = pReloc.targetRef().frag(); // find the islands for the input relocation std::pair<BranchIsland*, BranchIsland*> islands = pBRIslandFactory.getIslands(*frag); if (islands.first == NULL) { // early exit if we can not find the forward island. return NULL; } // find if there is such a stub in the backward island first. if (islands.second != NULL) { stub = islands.second->findStub(prototype, pReloc); } if (stub == NULL) { // find if there is such a stub in the forward island. stub = islands.first->findStub(prototype, pReloc); if (stub == NULL) { // create a stub from the prototype stub = prototype->clone(); // apply fixups in this new stub stub->applyFixup(pReloc, pBuilder, *islands.first); // add stub to the forward branch island islands.first->addStub(prototype, pReloc, *stub); } } } return stub; } Stub* StubFactory::create(FragmentRef& pFragRef, IRBuilder& pBuilder, BranchIslandFactory& pBRIslandFactory) { Stub* prototype = findPrototype(pFragRef); if (prototype == NULL) { return NULL; } else { std::pair<BranchIsland*, BranchIsland*> islands = pBRIslandFactory.getIslands(*(pFragRef.frag())); // early exit if we can not find the forward island. if (islands.first == NULL) { return NULL; } else { // create a stub from the prototype Stub* stub = prototype->clone(); // apply fixups in this new stub stub->applyFixup(pFragRef, pBuilder, *islands.first); // add stub to the forward branch island islands.first->addStub(*stub); return stub; } // (islands.first == NULL) } // if (prototype == NULL) } /// findPrototype - find if there is a registered stub prototype for the given /// relocation Stub* StubFactory::findPrototype(const Relocation& pReloc, uint64_t pSource, uint64_t pTargetSymValue) const { for (StubPoolType::const_iterator it = m_StubPool.begin(), ie = m_StubPool.end(); it != ie; ++it) { if ((*it)->isMyDuty(pReloc, pSource, pTargetSymValue)) return (*it); } return NULL; } Stub* StubFactory::findPrototype(const FragmentRef& pFragRef) const { for (StubPoolType::const_iterator it = m_StubPool.begin(), ie = m_StubPool.end(); it != ie; ++it) { if ((*it)->isMyDuty(pFragRef)) return (*it); } return NULL; } } // namespace mcld