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.
158 lines
4.3 KiB
158 lines
4.3 KiB
//===- FragmentRef.cpp --------------------------------------------------===//
|
|
//
|
|
// The MCLinker Project
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "mcld/Fragment/FragmentRef.h"
|
|
|
|
#include "mcld/Fragment/Fragment.h"
|
|
#include "mcld/Fragment/RegionFragment.h"
|
|
#include "mcld/Fragment/Stub.h"
|
|
#include "mcld/LD/EhFrame.h"
|
|
#include "mcld/LD/LDSection.h"
|
|
#include "mcld/LD/SectionData.h"
|
|
#include "mcld/Support/GCFactory.h"
|
|
|
|
#include <llvm/ADT/StringRef.h>
|
|
#include <llvm/Support/Casting.h>
|
|
#include <llvm/Support/ManagedStatic.h>
|
|
|
|
#include <cassert>
|
|
|
|
namespace mcld {
|
|
|
|
typedef GCFactory<FragmentRef, MCLD_SECTIONS_PER_INPUT> FragRefFactory;
|
|
|
|
static llvm::ManagedStatic<FragRefFactory> g_FragRefFactory;
|
|
|
|
FragmentRef FragmentRef::g_NullFragmentRef;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// FragmentRef
|
|
//===----------------------------------------------------------------------===//
|
|
FragmentRef::FragmentRef() : m_pFragment(NULL), m_Offset(0) {
|
|
}
|
|
|
|
FragmentRef::FragmentRef(Fragment& pFrag, FragmentRef::Offset pOffset)
|
|
: m_pFragment(&pFrag), m_Offset(pOffset) {
|
|
}
|
|
|
|
/// Create - create a fragment reference for a given fragment.
|
|
///
|
|
/// @param pFrag - the given fragment
|
|
/// @param pOffset - the offset, can be larger than the fragment, but can not
|
|
/// be larger than the section size.
|
|
/// @return if the offset is legal, return the fragment reference. Otherwise,
|
|
/// return NULL.
|
|
FragmentRef* FragmentRef::Create(Fragment& pFrag, uint64_t pOffset) {
|
|
int64_t offset = pOffset;
|
|
Fragment* frag = &pFrag;
|
|
|
|
while (frag != NULL) {
|
|
offset -= frag->size();
|
|
if (offset <= 0)
|
|
break;
|
|
frag = frag->getNextNode();
|
|
}
|
|
if ((frag != NULL) && (frag->size() != 0)) {
|
|
if (offset == 0)
|
|
frag = frag->getNextNode();
|
|
else
|
|
offset += frag->size();
|
|
}
|
|
|
|
if (frag == NULL)
|
|
return Null();
|
|
|
|
FragmentRef* result = g_FragRefFactory->allocate();
|
|
new (result) FragmentRef(*frag, offset);
|
|
|
|
return result;
|
|
}
|
|
|
|
FragmentRef* FragmentRef::Create(LDSection& pSection, uint64_t pOffset) {
|
|
SectionData* data = NULL;
|
|
switch (pSection.kind()) {
|
|
case LDFileFormat::Relocation:
|
|
// No fragment reference refers to a relocation section
|
|
break;
|
|
case LDFileFormat::EhFrame:
|
|
if (pSection.hasEhFrame())
|
|
data = pSection.getEhFrame()->getSectionData();
|
|
break;
|
|
default:
|
|
data = pSection.getSectionData();
|
|
break;
|
|
}
|
|
|
|
if (data == NULL || data->empty()) {
|
|
return Null();
|
|
}
|
|
|
|
return Create(data->front(), pOffset);
|
|
}
|
|
|
|
void FragmentRef::Clear() {
|
|
g_FragRefFactory->clear();
|
|
}
|
|
|
|
FragmentRef* FragmentRef::Null() {
|
|
return &g_NullFragmentRef;
|
|
}
|
|
|
|
FragmentRef& FragmentRef::assign(const FragmentRef& pCopy) {
|
|
m_pFragment = const_cast<Fragment*>(pCopy.m_pFragment);
|
|
m_Offset = pCopy.m_Offset;
|
|
return *this;
|
|
}
|
|
|
|
FragmentRef& FragmentRef::assign(Fragment& pFrag, FragmentRef::Offset pOffset) {
|
|
m_pFragment = &pFrag;
|
|
m_Offset = pOffset;
|
|
return *this;
|
|
}
|
|
|
|
void FragmentRef::memcpy(void* pDest, size_t pNBytes, Offset pOffset) const {
|
|
// check if the offset is still in a legal range.
|
|
if (m_pFragment == NULL)
|
|
return;
|
|
|
|
unsigned int total_offset = m_Offset + pOffset;
|
|
switch (m_pFragment->getKind()) {
|
|
case Fragment::Region: {
|
|
RegionFragment* region_frag = static_cast<RegionFragment*>(m_pFragment);
|
|
unsigned int total_length = region_frag->getRegion().size();
|
|
if (total_length < (total_offset + pNBytes))
|
|
pNBytes = total_length - total_offset;
|
|
|
|
std::memcpy(
|
|
pDest, region_frag->getRegion().begin() + total_offset, pNBytes);
|
|
return;
|
|
}
|
|
case Fragment::Stub: {
|
|
Stub* stub_frag = static_cast<Stub*>(m_pFragment);
|
|
unsigned int total_length = stub_frag->size();
|
|
if (total_length < (total_offset + pNBytes))
|
|
pNBytes = total_length - total_offset;
|
|
std::memcpy(pDest, stub_frag->getContent() + total_offset, pNBytes);
|
|
return;
|
|
}
|
|
case Fragment::Alignment:
|
|
case Fragment::Fillment:
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
FragmentRef::Offset FragmentRef::getOutputOffset() const {
|
|
Offset result = 0;
|
|
if (m_pFragment != NULL)
|
|
result = m_pFragment->getOffset();
|
|
return (result + m_Offset);
|
|
}
|
|
|
|
} // namespace mcld
|