C++程序  |  130行  |  4.15 KB

//===- 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