//===- MCLDDriver.cpp -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/MC/InputTree.h>
#include <mcld/MC/MCLinker.h>
#include <mcld/MC/MCLDDriver.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/LD/ArchiveReader.h>
#include <mcld/LD/ObjectReader.h>
#include <mcld/LD/DynObjReader.h>
#include <mcld/LD/ObjectWriter.h>
#include <mcld/LD/DynObjWriter.h>
#include <mcld/LD/ExecWriter.h>
#include <mcld/LD/ResolveInfo.h>
#include <mcld/Support/RealPath.h>
#include <mcld/Support/MemoryAreaFactory.h>
#include <mcld/Target/TargetLDBackend.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/LD/Archive.h>
using namespace llvm;
using namespace mcld;
MCLDDriver::MCLDDriver(MCLDInfo& pLDInfo,
TargetLDBackend& pLDBackend,
MemoryAreaFactory& pAreaFactory)
: m_LDInfo(pLDInfo),
m_LDBackend(pLDBackend),
m_pLinker(NULL),
m_AreaFactory(pAreaFactory) {
}
MCLDDriver::~MCLDDriver()
{
if (NULL != m_pLinker)
delete m_pLinker;
}
/// initMCLinker - initialize MCLinker
/// Connect all components with MCLinker
bool MCLDDriver::initMCLinker()
{
if (0 == m_pLinker)
m_pLinker = new MCLinker(m_LDBackend,
m_LDInfo,
m_SectionMap);
// initialize the readers and writers
// Because constructor can not be failed, we initalize all readers and
// writers outside the MCLinker constructors.
if (!m_LDBackend.initObjectReader(*m_pLinker) ||
!m_LDBackend.initArchiveReader(*m_pLinker, m_LDInfo, m_AreaFactory) ||
!m_LDBackend.initObjectReader(*m_pLinker) ||
!m_LDBackend.initDynObjReader(*m_pLinker) ||
!m_LDBackend.initObjectWriter(*m_pLinker) ||
!m_LDBackend.initDynObjWriter(*m_pLinker) ||
!m_LDBackend.initExecWriter(*m_pLinker))
return false;
// initialize RelocationFactory
m_LDBackend.initRelocFactory(*m_pLinker);
return true;
}
/// initStdSections - initialize standard sections
bool MCLDDriver::initStdSections()
{
/// initialize section mapping for standard format, target-dependent section,
/// (and user-defined mapping)
if (!m_SectionMap.initStdSectionMap() ||
!m_LDBackend.initTargetSectionMap(m_SectionMap))
return false;
/// A technical debt. We need to initialize section map here because
/// we do not separate output file and temporary data structure. So far,
/// MCLinker directly use output file's LDContext as the temporary data
/// structure. We will create a new data structure mcld::Module to collect
/// all temporary data structures togather.
m_pLinker->initSectionMap();
// initialize standard sections
switch (m_LDInfo.output().type()) {
case Output::DynObj: {
// intialize standard and target-dependent sections
if (!m_LDBackend.initDynObjSections(*m_pLinker))
return false;
break;
}
case Output::Exec: {
// intialize standard and target-dependent sections
if (!m_LDBackend.initExecSections(*m_pLinker))
return false;
break;
}
case Output::Object: {
llvm::report_fatal_error(llvm::Twine("output type is not implemented yet. file: `") +
m_LDInfo.output().name() +
llvm::Twine("'."));
return false;
}
default: {
llvm::report_fatal_error(llvm::Twine("unknown output type of file `") +
m_LDInfo.output().name() +
llvm::Twine("'."));
return false;
}
} // end of switch
// initialize target-dependent sections
m_LDBackend.initTargetSections(*m_pLinker);
return true;
}
void MCLDDriver::normalize()
{
// ----- set up inputs ----- //
InputTree::iterator input, inEnd = m_LDInfo.inputs().end();
for (input = m_LDInfo.inputs().begin(); input!=inEnd; ++input) {
// already got type - for example, bitcode or external OIR (object
// intermediate representation)
if ((*input)->type() == Input::Script ||
(*input)->type() == Input::Object ||
(*input)->type() == Input::DynObj ||
(*input)->type() == Input::Archive ||
(*input)->type() == Input::External)
continue;
// is a relocatable object file
if (m_LDBackend.getObjectReader()->isMyFormat(**input)) {
(*input)->setType(Input::Object);
m_LDBackend.getObjectReader()->readObject(**input);
m_LDBackend.getObjectReader()->readSections(**input);
m_LDBackend.getObjectReader()->readSymbols(**input);
}
// is a shared object file
else if (m_LDBackend.getDynObjReader()->isMyFormat(**input)) {
(*input)->setType(Input::DynObj);
m_LDBackend.getDynObjReader()->readDSO(**input);
m_LDBackend.getDynObjReader()->readSymbols(**input);
}
// is an archive
else if (m_LDBackend.getArchiveReader()->isMyFormat(**input)) {
(*input)->setType(Input::Archive);
Archive archive(**input, m_LDInfo.inputFactory());
m_LDBackend.getArchiveReader()->readArchive(archive);
if(archive.numOfObjectMember() > 0) {
m_LDInfo.inputs().merge<InputTree::Inclusive>(input, archive.inputs());
}
}
else {
fatal(diag::err_unrecognized_input_file) << (*input)->path()
<< m_LDInfo.triple().str();
}
} // end of for
}
bool MCLDDriver::linkable() const
{
// check we have input and output files
if (m_LDInfo.inputs().empty()) {
error(diag::err_no_inputs);
return false;
}
// check all attributes are legal
mcld::AttributeFactory::const_iterator attr, attrEnd = m_LDInfo.attrFactory().end();
for (attr=m_LDInfo.attrFactory().begin(); attr!=attrEnd; ++attr) {
if (!m_LDInfo.attrFactory().constraint().isLegal((**attr))) {
return false;
}
}
// can not mix -static with shared objects
mcld::InputTree::const_bfs_iterator input, inEnd = m_LDInfo.inputs().bfs_end();
for (input=m_LDInfo.inputs().bfs_begin(); input!=inEnd; ++input) {
if ((*input)->type() == mcld::Input::DynObj) {
if((*input)->attribute()->isStatic()) {
error(diag::err_mixed_shared_static_objects)
<< (*input)->name() << (*input)->path();
return false;
}
}
}
// can not mix -r with shared objects
return true;
}
/// mergeSections - put allinput sections into output sections
bool MCLDDriver::mergeSections()
{
// TODO: when MCLinker can read other object files, we have to merge
// sections
return true;
}
/// addStandardSymbols - shared object and executable files need some
/// standard symbols
/// @return if there are some input symbols with the same name to the
/// standard symbols, return false
bool MCLDDriver::addStandardSymbols()
{
return m_LDBackend.initStandardSymbols(*m_pLinker, m_LDInfo.output());
}
/// addTargetSymbols - some targets, such as MIPS and ARM, need some
/// target-dependent symbols
/// @return if there are some input symbols with the same name to the
/// target symbols, return false
bool MCLDDriver::addTargetSymbols()
{
m_LDBackend.initTargetSymbols(*m_pLinker, m_LDInfo.output());
return true;
}
/// readRelocations - read all relocation entries
///
/// All symbols should be read and resolved before this function.
bool MCLDDriver::readRelocations()
{
// Bitcode is read by the other path. This function reads relocation sections
// in object files.
mcld::InputTree::bfs_iterator input, inEnd = m_LDInfo.inputs().bfs_end();
for (input=m_LDInfo.inputs().bfs_begin(); input!=inEnd; ++input) {
if ((*input)->type() == Input::Object) {
if (!m_LDBackend.getObjectReader()->readRelocations(**input))
return false;
}
// ignore the other kinds of files.
}
return true;
}
/// prelayout - help backend to do some modification before layout
bool MCLDDriver::prelayout()
{
m_LDBackend.preLayout(m_LDInfo.output(),
m_LDInfo,
*m_pLinker);
m_LDBackend.allocateCommonSymbols(m_LDInfo, *m_pLinker);
/// check program interpreter - computer the name size of the runtime dyld
/// FIXME: check if we are doing static linking!
if (m_LDInfo.output().type() == Output::Exec)
m_LDBackend.sizeInterp(m_LDInfo.output(), m_LDInfo);
/// measure NamePools - compute the size of name pool sections
/// In ELF, will compute the size of.symtab, .strtab, .dynsym, .dynstr,
/// and .hash sections.
///
/// dump all symbols and strings from MCLinker and build the format-dependent
/// hash table.
m_LDBackend.sizeNamePools(m_LDInfo.output(), m_pLinker->getOutputSymbols(), m_LDInfo);
return true;
}
/// layout - linearly layout all output sections and reserve some space
/// for GOT/PLT
/// Because we do not support instruction relaxing in this early version,
/// if there is a branch can not jump to its target, we return false
/// directly
bool MCLDDriver::layout()
{
return m_pLinker->layout();
}
/// prelayout - help backend to do some modification after layout
bool MCLDDriver::postlayout()
{
m_LDBackend.postLayout(m_LDInfo.output(),
m_LDInfo,
*m_pLinker);
return true;
}
/// finalizeSymbolValue - finalize the resolved symbol value.
/// Before relocate(), after layout(), MCLinker should correct value of all
/// symbol.
bool MCLDDriver::finalizeSymbolValue()
{
return m_pLinker->finalizeSymbols();
}
/// relocate - applying relocation entries and create relocation
/// section in the output files
/// Create relocation section, asking TargetLDBackend to
/// read the relocation information into RelocationEntry
/// and push_back into the relocation section
bool MCLDDriver::relocation()
{
return m_pLinker->applyRelocations();
}
/// emitOutput - emit the output file.
bool MCLDDriver::emitOutput()
{
switch(m_LDInfo.output().type()) {
case Output::Object:
m_LDBackend.getObjectWriter()->writeObject(m_LDInfo.output());
return true;
case Output::DynObj:
m_LDBackend.getDynObjWriter()->writeDynObj(m_LDInfo.output());
return true;
case Output::Exec:
m_LDBackend.getExecWriter()->writeExecutable(m_LDInfo.output());
return true;
}
return false;
}
/// postProcessing - do modification after all processes
bool MCLDDriver::postProcessing()
{
m_pLinker->syncRelocationResult();
m_LDBackend.postProcessing(m_LDInfo.output(),
m_LDInfo,
*m_pLinker);
return true;
}