blob: 293b1c934e948592605f15523ededb7cd45d2232 [file] [log] [blame]
//===- Relocation.cpp -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/Fragment/Relocation.h>
#include <mcld/LD/Relocator.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/SectionData.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/LD/RelocationFactory.h>
#include <llvm/Support/ManagedStatic.h>
using namespace mcld;
static llvm::ManagedStatic<RelocationFactory> g_RelocationFactory;
//===----------------------------------------------------------------------===//
// Relocation Factory Methods
//===----------------------------------------------------------------------===//
/// Initialize - set up the relocation factory
void Relocation::SetUp(const LinkerConfig& pConfig)
{
g_RelocationFactory->setConfig(pConfig);
}
/// Clear - Clean up the relocation factory
void Relocation::Clear()
{
g_RelocationFactory->clear();
}
/// Create - produce an empty relocation entry
Relocation* Relocation::Create()
{
return g_RelocationFactory->produceEmptyEntry();
}
/// Create - produce a relocation entry
/// @param pType [in] the type of the relocation entry
/// @param pFragRef [in] the place to apply the relocation
/// @param pAddend [in] the addend of the relocation entry
Relocation* Relocation::Create(Type pType, FragmentRef& pFragRef, Address pAddend)
{
return g_RelocationFactory->produce(pType, pFragRef, pAddend);
}
/// Destroy - destroy a relocation entry
void Relocation::Destroy(Relocation*& pRelocation)
{
g_RelocationFactory->destroy(pRelocation);
pRelocation = NULL;
}
//===----------------------------------------------------------------------===//
// Relocation
//===----------------------------------------------------------------------===//
Relocation::Relocation()
: m_Type(0x0), m_TargetData(0x0), m_pSymInfo(NULL), m_Addend(0x0) {
}
Relocation::Relocation(Relocation::Type pType,
FragmentRef* pTargetRef,
Relocation::Address pAddend,
Relocation::DWord pTargetData)
: m_Type(pType),
m_TargetData(pTargetData),
m_pSymInfo(NULL),
m_Addend(pAddend)
{
if(NULL != pTargetRef)
m_TargetAddress.assign(*pTargetRef->frag(), pTargetRef->offset()) ;
}
Relocation::~Relocation()
{
}
Relocation::Address Relocation::place() const
{
Address sect_addr = m_TargetAddress.frag()->getParent()->getSection().addr();
return sect_addr + m_TargetAddress.getOutputOffset();
}
Relocation::Address Relocation::symValue() const
{
if (m_pSymInfo->type() == ResolveInfo::Section &&
m_pSymInfo->outSymbol()->hasFragRef()) {
return m_pSymInfo->outSymbol()->fragRef()->frag()->getParent()->getSection().addr();
}
return m_pSymInfo->outSymbol()->value();
}
void Relocation::apply(Relocator& pRelocator)
{
Relocator::Result result = pRelocator.applyRelocation(*this);
switch (result) {
case Relocator::OK: {
// do nothing
return;
}
case Relocator::Overflow: {
error(diag::result_overflow) << pRelocator.getName(type())
<< symInfo()->name();
return;
}
case Relocator::BadReloc: {
error(diag::result_badreloc) << pRelocator.getName(type())
<< symInfo()->name();
return;
}
case Relocator::Unsupport: {
fatal(diag::unsupported_relocation) << type()
<< "mclinker@googlegroups.com";
return;
}
case Relocator::Unknown: {
fatal(diag::unknown_relocation) << type() << symInfo()->name();
return;
}
} // end of switch
}
void Relocation::setType(Type pType)
{
m_Type = pType;
}
void Relocation::setAddend(Address pAddend)
{
m_Addend = pAddend;
}
void Relocation::setSymInfo(ResolveInfo* pSym)
{
m_pSymInfo = pSym;
}
size_t Relocation::size() const
{
// TODO: the size of Relocation fragment is handled by backend
return 0;
}
void Relocation::updateAddend()
{
// Update value keep in addend if we meet a section symbol
if (m_pSymInfo->type() == ResolveInfo::Section) {
uint32_t offset = m_pSymInfo->outSymbol()->fragRef()->getOutputOffset();
m_Addend += offset;
}
}