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.
151 lines
4.5 KiB
151 lines
4.5 KiB
//===- 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/LDSection.h"
|
|
#include "mcld/LD/LDSymbol.h"
|
|
#include "mcld/LD/RelocationFactory.h"
|
|
#include "mcld/LD/Relocator.h"
|
|
#include "mcld/LD/ResolveInfo.h"
|
|
#include "mcld/LD/SectionData.h"
|
|
#include "mcld/Support/MsgHandling.h"
|
|
|
|
#include <llvm/Support/ManagedStatic.h>
|
|
|
|
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 (pTargetRef != NULL)
|
|
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()) {
|
|
const FragmentRef* fragRef = m_pSymInfo->outSymbol()->fragRef();
|
|
return fragRef->frag()->getParent()->getSection().addr() +
|
|
fragRef->getOutputOffset();
|
|
}
|
|
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::Unsupported: {
|
|
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;
|
|
}
|
|
|
|
Relocation::Size Relocation::size(Relocator& pRelocator) const {
|
|
return pRelocator.getSize(m_Type);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
} // namespace mcld
|