//===- SectLinker.cpp -----------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the SectLinker class. // //===----------------------------------------------------------------------===// #include <mcld/Support/FileHandle.h> #include <mcld/MC/InputTree.h> #include <mcld/MC/MCLDDriver.h> #include <mcld/Support/FileSystem.h> #include <mcld/Support/MsgHandling.h> #include <mcld/Support/FileHandle.h> #include <mcld/Support/raw_ostream.h> #include <mcld/Support/MemoryAreaFactory.h> #include <mcld/Support/DerivedPositionDependentOptions.h> #include <mcld/Target/TargetLDBackend.h> #include <mcld/CodeGen/SectLinker.h> #include <mcld/CodeGen/SectLinkerOption.h> #include <llvm/Module.h> #include <algorithm> #include <stack> #include <string> using namespace mcld; using namespace llvm; //===----------------------------------------------------------------------===// // Forward declarations char SectLinker::m_ID = 0; static bool CompareOption(const PositionDependentOption* X, const PositionDependentOption* Y); //===----------------------------------------------------------------------===// // SectLinker SectLinker::SectLinker(SectLinkerOption &pOption, TargetLDBackend& pLDBackend) : MachineFunctionPass(m_ID), m_pOption(&pOption), m_pLDBackend(&pLDBackend), m_pLDDriver(NULL), m_pMemAreaFactory(NULL) { m_pMemAreaFactory = new MemoryAreaFactory(32); } SectLinker::~SectLinker() { delete m_pLDDriver; // FIXME: current implementation can not change the order of delete. // // Instance of TargetLDBackend was created outside and is not managed by // SectLinker. It should not be destroyed here and by SectLinker. However, in // order to follow the LLVM convention - that is, the pass manages all the // objects it used during the processing, we destroy the object of // TargetLDBackend here. delete m_pLDBackend; delete m_pMemAreaFactory; } bool SectLinker::doInitialization(Module &pM) { MCLDInfo &info = m_pOption->info(); // ----- convert position dependent options into tree of input files ----- // PositionDependentOptions &PosDepOpts = m_pOption->pos_dep_options(); std::stable_sort(PosDepOpts.begin(), PosDepOpts.end(), CompareOption); initializeInputTree(PosDepOpts); initializeInputOutput(info); // Now, all input arguments are prepared well, send it into MCLDDriver m_pLDDriver = new MCLDDriver(info, *m_pLDBackend, *memAreaFactory()); return false; } bool SectLinker::doFinalization(Module &pM) { const MCLDInfo &info = m_pOption->info(); // 2. - initialize MCLinker if (!m_pLDDriver->initMCLinker()) return true; // 3. - initialize output's standard sections if (!m_pLDDriver->initStdSections()) return true; // 4. - normalize the input tree m_pLDDriver->normalize(); if (info.options().trace()) { static int counter = 0; mcld::outs() << "** name\ttype\tpath\tsize (" << info.inputs().size() << ")\n"; InputTree::const_dfs_iterator input, inEnd = info.inputs().dfs_end(); for (input=info.inputs().dfs_begin(); input!=inEnd; ++input) { mcld::outs() << counter++ << " * " << (*input)->name(); switch((*input)->type()) { case Input::Archive: mcld::outs() << "\tarchive\t("; break; case Input::Object: mcld::outs() << "\tobject\t("; break; case Input::DynObj: mcld::outs() << "\tshared\t("; break; case Input::Script: mcld::outs() << "\tscript\t("; break; case Input::External: mcld::outs() << "\textern\t("; break; default: unreachable(diag::err_cannot_trace_file) << (*input)->type() << (*input)->name() << (*input)->path(); } mcld::outs() << (*input)->path() << ")\n"; } } // 5. - check if we can do static linking and if we use split-stack. if (!m_pLDDriver->linkable()) return true; // 6. - merge all sections if (!m_pLDDriver->mergeSections()) return true; // 7. - add standard symbols and target-dependent symbols // m_pLDDriver->addUndefSymbols(); if (!m_pLDDriver->addStandardSymbols() || !m_pLDDriver->addTargetSymbols()) return true; // 8. - read all relocation entries from input files m_pLDDriver->readRelocations(); // 9. - pre-layout m_pLDDriver->prelayout(); // 10. - linear layout m_pLDDriver->layout(); // 10.b - post-layout (create segment, instruction relaxing) m_pLDDriver->postlayout(); // 11. - finalize symbol value m_pLDDriver->finalizeSymbolValue(); // 12. - apply relocations m_pLDDriver->relocation(); // 13. - write out output m_pLDDriver->emitOutput(); // 14. - post processing m_pLDDriver->postProcessing(); return false; } bool SectLinker::runOnMachineFunction(MachineFunction& pF) { // basically, linkers do nothing during function is generated. return false; } void SectLinker::initializeInputOutput(MCLDInfo &pLDInfo) { // ----- initialize output file ----- // FileHandle::Permission perm; if (Output::Object == pLDInfo.output().type()) perm = 0544; else perm = 0755; MemoryArea* out_area = memAreaFactory()->produce(pLDInfo.output().path(), FileHandle::ReadWrite, perm); if (!out_area->handler()->isGood()) { // make sure output is openend successfully. fatal(diag::err_cannot_open_output_file) << pLDInfo.output().name() << pLDInfo.output().path(); } pLDInfo.output().setMemArea(out_area); pLDInfo.output().setContext(pLDInfo.contextFactory().produce()); // ----- initialize input files ----- // InputTree::dfs_iterator input, inEnd = pLDInfo.inputs().dfs_end(); for (input = pLDInfo.inputs().dfs_begin(); input!=inEnd; ++input) { // already got type - for example, bitcode if ((*input)->type() == Input::Script || (*input)->type() == Input::Object || (*input)->type() == Input::DynObj || (*input)->type() == Input::Archive) continue; MemoryArea *input_memory = memAreaFactory()->produce((*input)->path(), FileHandle::ReadOnly); if (input_memory->handler()->isGood()) { (*input)->setMemArea(input_memory); } else { error(diag::err_cannot_open_input) << (*input)->name() << (*input)->path(); return; } LDContext *input_context = pLDInfo.contextFactory().produce((*input)->path()); (*input)->setContext(input_context); } } void SectLinker::initializeInputTree(const PositionDependentOptions &pPosDepOptions) const { if (pPosDepOptions.empty()) fatal(diag::err_no_inputs); MCLDInfo &info = m_pOption->info(); PositionDependentOptions::const_iterator option = pPosDepOptions.begin(); if (1 == pPosDepOptions.size() && ((*option)->type() != PositionDependentOption::INPUT_FILE && (*option)->type() != PositionDependentOption::NAMESPEC) && (*option)->type() != PositionDependentOption::BITCODE) { // if we only have one positional options, and the option is // not an input file, then emit error message. fatal(diag::err_no_inputs); } // ----- Input tree insertion algorithm ----- // // The type of the previsou node indicates the direction of the current // insertion. // // root : the parent node who being inserted. // mover : the direcion of current movement. // // for each positional options: // insert the options in current root. // calculate the next movement // Initialization InputTree::Mover *move = &InputTree::Downward; InputTree::iterator root = info.inputs().root(); PositionDependentOptions::const_iterator optionEnd = pPosDepOptions.end(); std::stack<InputTree::iterator> returnStack; while (option != optionEnd ) { switch ((*option)->type()) { /** bitcode **/ case PositionDependentOption::BITCODE: { const BitcodeOption *bitcode_option = static_cast<const BitcodeOption*>(*option); // threat bitcode as an external IR in this version. info.inputs().insert(root, *move, bitcode_option->path()->native(), *(bitcode_option->path()), Input::External); info.setBitcode(**root); // move root on the new created node. move->move(root); // the next file is appended after bitcode file. move = &InputTree::Afterward; break; } /** input object file **/ case PositionDependentOption::INPUT_FILE: { const InputFileOption *input_file_option = static_cast<const InputFileOption*>(*option); info.inputs().insert(root, *move, input_file_option->path()->native(), *(input_file_option->path())); // move root on the new created node. move->move(root); // the next file is appended after object file. move = &InputTree::Afterward; break; } /** -lnamespec **/ case PositionDependentOption::NAMESPEC: { sys::fs::Path* path = NULL; const NamespecOption *namespec_option = static_cast<const NamespecOption*>(*option); // find out the real path of the namespec. if (info.attrFactory().constraint().isSharedSystem()) { // In the system with shared object support, we can find both archive // and shared object. if (info.attrFactory().last().isStatic()) { // with --static, we must search an archive. path = info.options().directories().find(namespec_option->namespec(), Input::Archive); } else { // otherwise, with --Bdynamic, we can find either an archive or a // shared object. path = info.options().directories().find(namespec_option->namespec(), Input::DynObj); } } else { // In the system without shared object support, we only look for an // archive. path = info.options().directories().find(namespec_option->namespec(), Input::Archive); } if (NULL == path) fatal(diag::err_cannot_find_namespec) << namespec_option->namespec(); info.inputs().insert(root, *move, namespec_option->namespec(), *path); // iterate root on the new created node. move->move(root); // the file after a namespec must be appended afterward. move = &InputTree::Afterward; break; } /** start group **/ case PositionDependentOption::START_GROUP: info.inputs().enterGroup(root, *move); move->move(root); returnStack.push(root); move = &InputTree::Downward; break; /** end group **/ case PositionDependentOption::END_GROUP: root = returnStack.top(); returnStack.pop(); move = &InputTree::Afterward; break; case PositionDependentOption::WHOLE_ARCHIVE: info.attrFactory().last().setWholeArchive(); break; case PositionDependentOption::NO_WHOLE_ARCHIVE: info.attrFactory().last().unsetWholeArchive(); break; case PositionDependentOption::AS_NEEDED: info.attrFactory().last().setAsNeeded(); break; case PositionDependentOption::NO_AS_NEEDED: info.attrFactory().last().unsetAsNeeded(); break; case PositionDependentOption::ADD_NEEDED: info.attrFactory().last().setAddNeeded(); break; case PositionDependentOption::NO_ADD_NEEDED: info.attrFactory().last().unsetAddNeeded(); break; case PositionDependentOption::BSTATIC: info.attrFactory().last().setStatic(); break; case PositionDependentOption::BDYNAMIC: info.attrFactory().last().setDynamic(); break; default: fatal(diag::err_cannot_identify_option) << (*option)->position() << (uint32_t)(*option)->type(); } // end of switch ++option; } // end of while if (!returnStack.empty()) { report_fatal_error("no matched --start-group and --end-group"); } } //===----------------------------------------------------------------------===// // Non-member functions static bool CompareOption(const PositionDependentOption* X, const PositionDependentOption* Y) { return (X->position() < Y->position()); }