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