blob: 4dc9897baf39a414a2937e99588c264b5231832f [file] [log] [blame]
//===- Layout.h -----------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MCLD_LD_LAYOUT_H
#define MCLD_LD_LAYOUT_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <map>
#include <llvm/ADT/ilist.h>
#include <llvm/ADT/ilist_node.h>
#include <llvm/ADT/DenseMap.h>
#include <mcld/LD/FragmentRef.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/SectionData.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/Support/GCFactory.h>
namespace mcld
{
class MCLinker;
class Output;
class TargetLDBackend;
/** \class Layout
* \brief Layout maintains the mapping between sections and fragments.
*
* MCLinker is a fragment-based linker. But readers and target backends
* still need section information. Layout is used to maintain the mapping
* between sections and fragments. Layout helps readers and target backends
* get the input or output section information from a fragment.
*/
class Layout
{
public:
typedef std::vector<LDSection*> SectionOrder;
typedef SectionOrder::iterator sect_iterator;
typedef SectionOrder::const_iterator const_sect_iterator;
public:
/// constructor
Layout();
/// destructor
~Layout();
/// getInputLDSection - give a Fragment, return the corresponding input
/// LDSection*
///
/// @return return NULL if the fragment is not found in input
LDSection* getInputLDSection(const Fragment& pFrag);
/// getInputLDSection - give a Fragment, return the corresponding input
/// LDSection*
///
/// @return return NULL if the fragment is not found in input
const LDSection* getInputLDSection(const Fragment& pFrag) const;
/// getFragmentRef - give a LDSection in input file and an offset, return
/// the fragment reference.
///
/// @param pInputSection - the given input section
/// @param pOffset - the offset, cannot be larger than this input section.
/// @return if found, return the fragment. Otherwise, return NULL.
FragmentRef*
getFragmentRef(const LDSection& pInputSection, uint64_t pOffset);
/// getFragmentRef - give a fragment and a big offset, return the fragment
/// reference in the section data.
///
/// @param pFrag - the given fragment
/// @param pBigOffset - the offset, can be larger than the fragment, but can
/// not larger than this input section.
/// @return if found, return the fragment. Otherwise, return NULL.
FragmentRef* getFragmentRef(const Fragment& pFrag, uint64_t pBigOffset);
/// getOutputOffset - Get the offset of the given fragment inside the
/// the output's SectionData.
uint64_t getOutputOffset(const Fragment& pFrag);
/// getOutputOffset - Get the offset of the given fragment inside the
/// the output's SectionData.
uint64_t getOutputOffset(const Fragment& pFrag) const;
/// getOutputOffset - Get the offset of the given fragment inside
/// the output's SectionData.
///
/// @return return -1 if the fragment is not found in output's SectionData.
uint64_t getOutputOffset(const FragmentRef& pFragRef);
/// getOutputOffset - Get the offset of the given fragment inside
/// the output's SectionData.
///
/// @return return -1 if the fragment is not found in output's SectionData.
uint64_t getOutputOffset(const FragmentRef& pFragRef) const;
/// getOutputLDSection - give a Fragment, return the corresponding output
/// LDSection*
///
/// @return return NULL if the fragment is not found in the output
LDSection* getOutputLDSection(const Fragment& pFrag);
/// getOutputLDSection - give a Fragment, return the corresponding output
/// LDSection*
///
/// @return return NULL if the fragment is not found in the output
const LDSection* getOutputLDSection(const Fragment& pFrag) const;
// ----- modifiers ----- //
bool layout(Output& pOutput,
const TargetLDBackend& pBackend, const MCLDInfo& pInfo);
/// addInputRange
void addInputRange(const SectionData& pSD, const LDSection& pInputHdr);
/// appendFragment - append the given Fragment to the given SectionData,
/// and insert a AlignFragment to preserve the required align constraint if
/// needed
/// @return return the inserted size, i.e., the size of pFrag and alignment
/// size if any
uint64_t appendFragment(Fragment& pFrag, SectionData& pSD,
uint32_t pAlignConstraint = 1);
private:
/** \class Range
* \brief Range is a <input's LDSection, previous rear fragment> pair
*/
struct Range : public llvm::ilist_node<Range>
{
public:
Range();
Range(const LDSection& pHeader);
~Range();
public:
LDSection* header;
Fragment* prevRear;
};
typedef llvm::iplist<Range> RangeList;
typedef std::map<const SectionData*, RangeList*> SDRangeMap;
typedef GCFactory<FragmentRef, 0> FragRefFactory;
private:
inline bool isFirstRange(const Range& pRange) const
{ return (NULL == pRange.prevRear); }
inline bool isLastRange(const Range& pRange) const
{ return (NULL == pRange.getNextNode()); }
inline bool isEmptyRange(const Range& pRange) const
{
if (isFirstRange(pRange)) {
if (!pRange.header->hasSectionData() ||
pRange.header->getSectionData()->getFragmentList().empty())
return true;
else
return false;
}
return (NULL == pRange.prevRear->getNextNode());
}
// get the front fragment in the range.
inline Fragment* getFront(Range& pRange) const
{
if (!pRange.header->hasSectionData())
return NULL;
if (pRange.header->getSectionData()->getFragmentList().empty())
return NULL;
if (isFirstRange(pRange))
return &pRange.header->getSectionData()->getFragmentList().front();
if (isEmptyRange(pRange))
return NULL;
return pRange.prevRear->getNextNode();
}
inline const Fragment* getFront(const Range& pRange) const
{
if (!pRange.header->hasSectionData())
return NULL;
if (pRange.header->getSectionData()->getFragmentList().empty())
return NULL;
if (isFirstRange(pRange))
return &pRange.header->getSectionData()->getFragmentList().front();
if (isEmptyRange(pRange))
return NULL;
return pRange.prevRear->getNextNode();
}
// get the rear fragment in the range.
inline Fragment* getRear(Range& pRange) const
{
if (!pRange.header->hasSectionData())
return NULL;
if (pRange.header->getSectionData()->getFragmentList().empty())
return NULL;
if (isLastRange(pRange)) {
if (isEmptyRange(pRange))
return NULL;
return &pRange.header->getSectionData()->getFragmentList().back();
}
return pRange.getNextNode()->prevRear;
}
inline const Fragment* getRear(const Range& pRange) const
{
if (!pRange.header->hasSectionData())
return NULL;
if (pRange.header->getSectionData()->getFragmentList().empty())
return NULL;
if (isLastRange(pRange)) {
if (isEmptyRange(pRange))
return NULL;
return &pRange.header->getSectionData()->getFragmentList().back();
}
return pRange.getNextNode()->prevRear;
}
FragmentRef* getFragmentRef(Range &pRange, uint64_t pOffset);
FragmentRef*
getFragmentRef(Fragment& pFront, Fragment& pRear, uint64_t pOffset);
bool hasLayoutOrder(const Fragment& pFragment) const
{ return (pFragment.getLayoutOrder() != ~(0U)); }
bool hasLayoutOffset(const Fragment& pFragment) const
{ return (pFragment.getOffset() != ~UINT64_C(0)); }
bool isValidOffset(const Fragment& pFrag, uint64_t pTargetOffset) const;
void setFragmentLayoutOrder(Fragment* pFragment);
void setFragmentLayoutOffset(Fragment* pFragment);
/// sortSectionOrder - perform sorting on m_SectionOrder to get final layout
/// ordering
void sortSectionOrder(const Output& pOutput,
const TargetLDBackend& pBackend,
const MCLDInfo& pInfo);
private:
/// a vector to describe the order of sections
SectionOrder m_SectionOrder;
/// the map from SectionData* to its own RangeList.
SDRangeMap m_SDRangeMap;
FragRefFactory m_FragRefFactory;
};
} // namespace of mcld
#endif