You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
4.2 KiB
130 lines
4.2 KiB
//===- 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
|