C++程序  |  330行  |  10.53 KB

//===- 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;
}