/frameworks/compile/mclinker/lib/CodeGen/SectLinker.cpp
C++ | 404 lines | 260 code | 64 blank | 80 comment | 34 complexity | e133149e5cc8e548b50e544aa72da032 MD5 | raw file
- //===- 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());
- }