//===- Linker.cpp ---------------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "mcld/Linker.h" #include "mcld/IRBuilder.h" #include "mcld/LinkerConfig.h" #include "mcld/Module.h" #include "mcld/Fragment/FragmentRef.h" #include "mcld/Fragment/Relocation.h" #include "mcld/LD/LDSection.h" #include "mcld/LD/LDSymbol.h" #include "mcld/LD/ObjectWriter.h" #include "mcld/LD/RelocData.h" #include "mcld/LD/SectionData.h" #include "mcld/MC/InputBuilder.h" #include "mcld/Object/ObjectLinker.h" #include "mcld/Support/FileHandle.h" #include "mcld/Support/FileOutputBuffer.h" #include "mcld/Support/MsgHandling.h" #include "mcld/Support/TargetRegistry.h" #include "mcld/Support/raw_ostream.h" #include "mcld/Target/TargetLDBackend.h" #include namespace mcld { Linker::Linker() : m_pConfig(NULL), m_pIRBuilder(NULL), m_pTarget(NULL), m_pBackend(NULL), m_pObjLinker(NULL) { } Linker::~Linker() { reset(); } /// emulate - To set up target-dependent options and default linker script. /// Follow GNU ld quirks. bool Linker::emulate(LinkerScript& pScript, LinkerConfig& pConfig) { m_pConfig = &pConfig; if (!initTarget()) return false; if (!initBackend()) return false; if (!initOStream()) return false; if (!initEmulator(pScript)) return false; return true; } bool Linker::link(Module& pModule, IRBuilder& pBuilder) { if (!normalize(pModule, pBuilder)) return false; if (!resolve(pModule)) return false; return layout(); } /// normalize - to convert the command line language to the input tree. bool Linker::normalize(Module& pModule, IRBuilder& pBuilder) { assert(m_pConfig != NULL); m_pIRBuilder = &pBuilder; m_pObjLinker = new ObjectLinker(*m_pConfig, *m_pBackend); // 2. - initialize ObjectLinker if (!m_pObjLinker->initialize(pModule, pBuilder)) return false; // 3. - initialize output's standard sections if (!m_pObjLinker->initStdSections()) return false; if (!Diagnose()) return false; // 4.a - add undefined symbols // before reading the inputs, we should add undefined symbols set by -u to // ensure that correspoding objects (e.g. in an archive) will be included m_pObjLinker->addUndefinedSymbols(); // 4.b - normalize the input tree // read out sections and symbol/string tables (from the files) and // set them in Module. When reading out the symbol, resolve their symbols // immediately and set their ResolveInfo (i.e., Symbol Resolution). m_pObjLinker->normalize(); if (m_pConfig->options().trace()) { static int counter = 0; mcld::outs() << "** name\ttype\tpath\tsize (" << pModule.getInputTree().size() << ")\n"; InputTree::const_dfs_iterator input, inEnd = pModule.getInputTree().dfs_end(); for (input = pModule.getInputTree().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. - set up code position if (LinkerConfig::DynObj == m_pConfig->codeGenType() || m_pConfig->options().isPIE()) { m_pConfig->setCodePosition(LinkerConfig::Independent); } else if (pModule.getLibraryList().empty()) { // If the output is dependent on its loaded address, and it does not need // to call outside functions, then we can treat the output static dependent // and perform better optimizations. m_pConfig->setCodePosition(LinkerConfig::StaticDependent); if (LinkerConfig::Exec == m_pConfig->codeGenType()) { // Since the output is static dependent, there should not have any // undefined // references in the output module. m_pConfig->options().setNoUndefined(); } } else { m_pConfig->setCodePosition(LinkerConfig::DynamicDependent); } if (!m_pObjLinker->linkable()) return Diagnose(); return true; } bool Linker::resolve(Module& pModule) { assert(m_pConfig != NULL); assert(m_pObjLinker != NULL); // 6. - read all relocation entries from input files // For all relocation sections of each input file (in the tree), // read out reloc entry info from the object file and accordingly // initiate their reloc entries in SectOrRelocData of LDSection. // // To collect all edges in the reference graph. m_pObjLinker->readRelocations(); // 7. - data stripping optimizations m_pObjLinker->dataStrippingOpt(); // 8. - merge all sections // Push sections into Module's SectionTable. // Merge sections that have the same name. // Maintain them as fragments in the section. // // To merge nodes of the reference graph. if (!m_pObjLinker->mergeSections()) return false; // 9.a - add symbols to output // After all input symbols have been resolved, add them to output symbol // table at once m_pObjLinker->addSymbolsToOutput(pModule); // 9.b - allocateCommonSymbols // Allocate fragments for common symbols to the corresponding sections. if (!m_pObjLinker->allocateCommonSymbols()) return false; return true; } bool Linker::layout() { assert(m_pConfig != NULL && m_pObjLinker != NULL); // 10. - add standard symbols, target-dependent symbols and script symbols if (!m_pObjLinker->addStandardSymbols() || !m_pObjLinker->addTargetSymbols() || !m_pObjLinker->addScriptSymbols()) return false; // 11. - scan all relocation entries by output symbols. // reserve GOT space for layout. // the space info is needed by pre-layout to compute the section size m_pObjLinker->scanRelocations(); // 12.a - init relaxation stuff. m_pObjLinker->initStubs(); // 12.b - pre-layout m_pObjLinker->prelayout(); // 12.c - linear layout // Decide which sections will be left in. Sort the sections according to // a given order. Then, create program header accordingly. // Finally, set the offset for sections (@ref LDSection) // according to the new order. m_pObjLinker->layout(); // 12.d - post-layout (create segment, instruction relaxing) m_pObjLinker->postlayout(); // 13. - finalize symbol value m_pObjLinker->finalizeSymbolValue(); // 14. - apply relocations m_pObjLinker->relocation(); if (!Diagnose()) return false; return true; } bool Linker::emit(FileOutputBuffer& pOutput) { // 15. - write out output m_pObjLinker->emitOutput(pOutput); // 16. - post processing m_pObjLinker->postProcessing(pOutput); if (!Diagnose()) return false; return true; } bool Linker::emit(const Module& pModule, const std::string& pPath) { FileHandle file; FileHandle::OpenMode open_mode( FileHandle::ReadWrite | FileHandle::Truncate | FileHandle::Create); FileHandle::Permission permission; switch (m_pConfig->codeGenType()) { case mcld::LinkerConfig::Unknown: case mcld::LinkerConfig::Object: permission = FileHandle::Permission(0x644); break; case mcld::LinkerConfig::DynObj: case mcld::LinkerConfig::Exec: case mcld::LinkerConfig::Binary: permission = FileHandle::Permission(0x755); break; default: assert(0 && "Unknown file type"); } bool result = file.open(sys::fs::Path(pPath), open_mode, permission); if (!result) { error(diag::err_cannot_open_output_file) << "Linker::emit()" << pPath; return false; } std::unique_ptr output; FileOutputBuffer::create( file, m_pObjLinker->getWriter()->getOutputSize(pModule), output); result = emit(*output); file.close(); return result; } bool Linker::emit(const Module& pModule, int pFileDescriptor) { FileHandle file; file.delegate(pFileDescriptor); std::unique_ptr output; FileOutputBuffer::create( file, m_pObjLinker->getWriter()->getOutputSize(pModule), output); return emit(*output); } bool Linker::reset() { m_pConfig = NULL; m_pIRBuilder = NULL; m_pTarget = NULL; // Because llvm::iplist will touch the removed node, we must clear // RelocData before deleting target backend. RelocData::Clear(); SectionData::Clear(); EhFrame::Clear(); delete m_pBackend; m_pBackend = NULL; delete m_pObjLinker; m_pObjLinker = NULL; LDSection::Clear(); LDSymbol::Clear(); FragmentRef::Clear(); Relocation::Clear(); return true; } bool Linker::initTarget() { assert(m_pConfig != NULL); std::string error; llvm::Triple triple(m_pConfig->targets().triple()); m_pTarget = mcld::TargetRegistry::lookupTarget( m_pConfig->targets().getArch(), triple, error); m_pConfig->targets().setTriple(triple); if (m_pTarget == NULL) { fatal(diag::fatal_cannot_init_target) << triple.str() << error; return false; } return true; } bool Linker::initBackend() { assert(m_pTarget != NULL); m_pBackend = m_pTarget->createLDBackend(*m_pConfig); if (m_pBackend == NULL) { fatal(diag::fatal_cannot_init_backend) << m_pConfig->targets().triple().str(); return false; } return true; } bool Linker::initOStream() { assert(m_pConfig != NULL); mcld::outs().setColor(m_pConfig->options().color()); mcld::errs().setColor(m_pConfig->options().color()); return true; } bool Linker::initEmulator(LinkerScript& pScript) { assert(m_pTarget != NULL && m_pConfig != NULL); return m_pTarget->emulate(pScript, *m_pConfig); } } // namespace mcld