//===- FragmentGraph.cpp --------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/Fragment/FragmentGraph.h>
#include <mcld/Fragment/Fragment.h>
#include <mcld/Fragment/Relocation.h>
#include <mcld/LD/LDContext.h>
#include <mcld/LD/LDFileFormat.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/SectionData.h>
#include <mcld/LD/RelocData.h>
#include <mcld/LinkerConfig.h>
#include <mcld/Module.h>
#include <mcld/Support/MsgHandling.h>
#include <llvm/Support/Casting.h>
#include <llvm/Support/ELF.h>
#include <iostream>
using namespace mcld;
//===----------------------------------------------------------------------===//
// non-member functions
//===----------------------------------------------------------------------===//
static int get_state(Fragment::Type pKind)
{
switch(pKind) {
case Fragment::Alignment:
return 0;
case Fragment::Fillment:
case Fragment::Region:
return 1;
case Fragment::Null:
return 2;
default:
unreachable(diag::unexpected_frag_type) << pKind;
}
return 0;
}
//===----------------------------------------------------------------------===//
// ReachMatrix
//===----------------------------------------------------------------------===//
FragmentGraph::ReachMatrix::ReachMatrix(size_t pSize)
{
assert(pSize != 0);
m_Data.assign(pSize * pSize, 0x0);
m_N = pSize;
}
uint32_t& FragmentGraph::ReachMatrix::at(uint32_t pX, uint32_t pY)
{
return m_Data[pX * m_N + pY];
}
uint32_t FragmentGraph::ReachMatrix::at(uint32_t pX, uint32_t pY) const
{
return m_Data[pX * m_N + pY];
}
//===----------------------------------------------------------------------===//
// FragmentGraph
//===----------------------------------------------------------------------===//
FragmentGraph::FragmentGraph()
: m_pMatrix(NULL), m_NumOfPNodes(0x0), m_NumOfRNodes(0x0), m_NumOfEdges(0x0)
{
m_pPseudoNodeFactory = new NodeFactoryType();
m_pRegularNodeFactory = new NodeFactoryType();
m_pFragNodeMap = new FragHashTableType(256);
m_pSymNodeMap = new SymHashTableType(256);
}
FragmentGraph::~FragmentGraph()
{
delete m_pPseudoNodeFactory;
delete m_pRegularNodeFactory;
delete m_pFragNodeMap;
}
FGNode* FragmentGraph::getNode(const Fragment& pFrag)
{
FragHashTableType::iterator entry = m_pFragNodeMap->find(&pFrag);
if (entry == m_pFragNodeMap->end())
return NULL;
return entry.getEntry()->value();
}
const FGNode* FragmentGraph::getNode(const Fragment& pFrag) const
{
FragHashTableType::iterator entry = m_pFragNodeMap->find(&pFrag);
if (entry == m_pFragNodeMap->end())
return NULL;
return entry.getEntry()->value();
}
FGNode* FragmentGraph::getNode(const ResolveInfo& pSym)
{
SymHashTableType::iterator entry = m_pSymNodeMap->find(&pSym);
if (entry == m_pSymNodeMap->end())
return NULL;
return entry.getEntry()->value();
}
const FGNode* FragmentGraph::getNode(const ResolveInfo& pSym) const
{
SymHashTableType::iterator entry = m_pSymNodeMap->find(&pSym);
if (entry == m_pSymNodeMap->end())
return NULL;
return entry.getEntry()->value();
}
FGNode* FragmentGraph::producePseudoNode()
{
FGNode* result = m_pPseudoNodeFactory->allocate();
new (result) FGNode(m_NumOfPNodes + m_NumOfRNodes);
++m_NumOfPNodes;
return result;
}
FGNode* FragmentGraph::produceRegularNode()
{
FGNode* result = m_pRegularNodeFactory->allocate();
new (result) FGNode(m_NumOfPNodes + m_NumOfRNodes);
++m_NumOfRNodes;
return result;
}
bool FragmentGraph::setNodeSlots(Module& pModule)
{
// symbols are the slots of nodes, push the symbols into the corresponding
// nodes.
// Traverse all defined symbols, including global and local symbols, to add
// symbols into the corresponding nodes
Module::SymbolTable& sym_tab = pModule.getSymbolTable();
SymbolCategory::iterator sym_it, sym_end = sym_tab.end();
for (sym_it = sym_tab.begin(); sym_it != sym_end; ++sym_it) {
// only the defined symbols with FragmnentRef can form a slot. The defined
// symbol with no FragmentRef such as ABS symbol should be skipped
LDSymbol* sym = *sym_it;
if (!sym->resolveInfo()->isDefine() ||
!sym->hasFragRef())
continue;
// FIXME: judge by getNode() is NULL or not
LDFileFormat::Kind sect_kind =
sym->fragRef()->frag()->getParent()->getSection().kind();
if (sect_kind != LDFileFormat::Regular &&
sect_kind != LDFileFormat::BSS)
continue;
FGNode* node = getNode(*sym->fragRef()->frag());
assert(NULL != node);
node->addSlot(sym->resolveInfo());
}
return true;
}
bool FragmentGraph::createRegularEdges(Module& pModule)
{
// The reference between nodes are presented by the relocations. Set the
// reachability matrix to present the connection
// Traverse all input relocations to set connection
Module::obj_iterator input, inEnd = pModule.obj_end();
for (input = pModule.obj_begin(); input != inEnd; ++input) {
LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
// bypass the discarded relocations
// 1. its section kind is changed to Ignore. (The target section is a
// discarded group section.)
// 2. it has no reloc data. (All symbols in the input relocs are in the
// discarded group sections)
if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
continue;
RelocData::iterator reloc_it, rEnd = (*rs)->getRelocData()->end();
for (reloc_it = (*rs)->getRelocData()->begin(); reloc_it != rEnd;
++reloc_it) {
Relocation* reloc = llvm::cast<Relocation>(reloc_it);
ResolveInfo* sym = reloc->symInfo();
// only the target symbols defined in the input fragments can make the
// connection
if (NULL == sym)
continue;
if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
continue;
// only the relocation target places which defined in the concerned
// sections can make the connection
// FIXME: judge by getNode() is NULL or not
LDFileFormat::Kind sect_kind =
reloc->targetRef().frag()->getParent()->getSection().kind();
if (sect_kind != LDFileFormat::Regular &&
sect_kind != LDFileFormat::BSS)
continue;
// only the target symbols defined in the concerned sections can make
// the connection
// FIXME: judge by getNode() is NULL or not
sect_kind =
sym->outSymbol()->fragRef()->frag()->getParent()->getSection().kind();
if (sect_kind != LDFileFormat::Regular &&
sect_kind != LDFileFormat::BSS)
continue;
connect(reloc, sym);
}
}
}
return true;
}
bool FragmentGraph::createPseudoEdges(Module& pModule)
{
// the pseudo edges are the edges from pseudo nodes to regular nodes, which
// present the reference from out-side world when building shared library
// Traverse all pseudo relocations in the pseudo nodes to set the connection
node_iterator node_it, node_end = m_pPseudoNodeFactory->end();
for (node_it = m_pPseudoNodeFactory->begin(); node_it != node_end; ++node_it) {
FGNode& node = *node_it;
FGNode::signal_iterator sig_it, sig_end = node.signal_end();
for (sig_it = node.signal_begin(); sig_it != sig_end; ++sig_it) {
connect(node, (*sig_it)->symInfo());
}
}
return true;
}
bool FragmentGraph::connect(Signal pSignal, Slot pSlot)
{
FGNode* from = getNode(*pSignal->targetRef().frag());
assert(NULL != from);
FGNode* to = getNode(*pSlot->outSymbol()->fragRef()->frag());
assert(NULL != to);
// maintain edge counter
if (0 == m_pMatrix->at(from->getIndex(), to->getIndex()))
++m_NumOfEdges;
++m_pMatrix->at(from->getIndex(), to->getIndex());
return true;
}
bool FragmentGraph::connect(FGNode& pFrom, Slot pSlot)
{
FGNode* to = getNode(*pSlot->outSymbol()->fragRef()->frag());
assert(NULL != to);
// maintain edge counter
if (0 == m_pMatrix->at(pFrom.getIndex(), to->getIndex()))
++m_NumOfEdges;
++m_pMatrix->at(pFrom.getIndex(), to->getIndex());
return true;
}
bool FragmentGraph::createPseudoNodes(Module& pModule)
{
// when generating shared library, we need to create pseudo node for every
// global defined symbols to present the fan-in of a regular node.
// Traverse all global defined symbols to build the pseudo nodes.
Module::SymbolTable& sym_tab = pModule.getSymbolTable();
SymbolCategory::iterator sym_it, sym_end = sym_tab.dynamicEnd();
for (sym_it = sym_tab.dynamicBegin(); sym_it != sym_end; ++sym_it) {
ResolveInfo* sym = (*sym_it)->resolveInfo();
if (!sym->isDefine() || !sym->outSymbol()->hasFragRef())
continue;
FGNode* node = producePseudoNode();
// create the pseudo relocation to present the fan-out of the pseudo node
Relocation* reloc = Relocation::Create();
reloc->setSymInfo(sym);
// set the signal of the pseudo node
node->addSignal(reloc);
// maintain the map for symbol to pseudo node
SymHashTableType::entry_type* entry = 0;
bool exist = false;
entry = m_pSymNodeMap->insert(sym, exist);
entry->setValue(node);
}
return true;
}
bool FragmentGraph::createRegularNodes(Module& pModule)
{
// Traverse all sections to build the Nodes. We build nodes only for Regular,
// and BSS
Module::iterator sect_it, sect_end = pModule.end();
for (sect_it = pModule.begin(); sect_it != sect_end; ++sect_it) {
LDSection* section = *sect_it;
SectionData* sect_data = NULL;
if (LDFileFormat::Regular != section->kind() &&
LDFileFormat::BSS != section->kind())
continue;
sect_data = section->getSectionData();
if (NULL == sect_data)
continue;
// Traverse all fragments in the sections, create Nodes and push the
// fragments into Nodes. Each Region or Fillment fragment belongs to a
// unique Node. The corresponding Align fragments and Null fragments belong
// to the same Node as the Region or Fillment fragment.
SectionData::iterator frag_it = sect_data->begin();
SectionData::iterator frag_end = sect_data->end();
if (frag_it == frag_end)
continue;
int cur_stat = 0;
int last_stat = 0;
// FIXME:
// To prevent some cases that we add the redundant NULL or Align fragments
// and lead a Region/Fillment fragment has more than one NULL or Align
// fragment. We should put all of them into the same Node.
static int stat_matrix[3][3] = {{0, 1, 1},
{0, 1, 1},
{0, 0, 0}};
FragHashTableType::entry_type* entry = 0;
bool exist = false;
FGNode* node = produceRegularNode();
Fragment* frag = NULL;
frag = &(*frag_it);
cur_stat = get_state(frag->getKind());
node->addFragment(frag);
// maintain the fragment to Node map
entry = m_pFragNodeMap->insert(frag, exist);
entry->setValue(node);
++frag_it;
while (frag_it != frag_end) {
last_stat = cur_stat;
frag = &(*frag_it);
cur_stat = get_state(frag->getKind());
if (stat_matrix[cur_stat][last_stat]) {
node = produceRegularNode();
}
node->addFragment(frag);
// maintain the fragment to Node map
entry = m_pFragNodeMap->insert(frag, exist);
entry->setValue(node);
++frag_it;
}
}
return true;
}
void FragmentGraph::initMatrix()
{
m_pMatrix = new ReachMatrix(m_NumOfPNodes + m_NumOfRNodes);
}
bool FragmentGraph::getEdges(FGNode& pNode, EdgeListType& pEdges)
{
// Traverse all regular nodes to find the connection to pNode
node_iterator it, itEnd = m_pRegularNodeFactory->end();
for (it = m_pRegularNodeFactory->begin(); it != itEnd; ++it) {
FGNode& node_to = *it;
uint32_t weight = m_pMatrix->at(pNode.getIndex(), node_to.getIndex());
if (weight > 0) {
// build an Edge
pEdges.push_back(FGEdge(pNode, node_to, weight));
}
}
return true;
}
bool FragmentGraph::construct(const LinkerConfig& pConfig, Module& pModule)
{
// create nodes - traverse all fragments to create the regular nodes, and
// then traverse all global defined symbols to create pseudo nodes
if (!createRegularNodes(pModule))
return false;
if (!createPseudoNodes(pModule))
return false;
// after all nodes created, we know the number of the nodes and then can
// create the reachability matrix
initMatrix();
// set slots - traverse all symbols to set the slots of regular nodes
if(!setNodeSlots(pModule))
return false;
// connect edges - traverse all relocations to set the edges
if(!createRegularEdges(pModule))
return false;
if(!createPseudoEdges(pModule))
return false;
return true;
}