//===- 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/LinkerConfig.h>
#include <mcld/Module.h>
#include <mcld/IRBuilder.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/TargetRegistry.h>
#include <mcld/Support/FileHandle.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/raw_ostream.h>
#include <mcld/Object/ObjectLinker.h>
#include <mcld/MC/InputBuilder.h>
#include <mcld/Target/TargetLDBackend.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/SectionData.h>
#include <mcld/LD/RelocData.h>
#include <mcld/Fragment/Relocation.h>
#include <mcld/Fragment/FragmentRef.h>
#include <cassert>
using namespace mcld;
Linker::Linker()
: m_pConfig(NULL), m_pIRBuilder(NULL),
m_pTarget(NULL), m_pBackend(NULL), m_pObjLinker(NULL) {
}
Linker::~Linker()
{
reset();
}
bool Linker::config(LinkerConfig& pConfig)
{
m_pConfig = &pConfig;
if (!initTarget())
return false;
if (!initBackend())
return false;
m_pObjLinker = new ObjectLinker(*m_pConfig,
*m_pBackend);
if (!initEmulator())
return false;
if (!initOStream())
return false;
return true;
}
bool Linker::link(Module& pModule, IRBuilder& pBuilder)
{
if (!resolve(pModule, pBuilder))
return false;
return layout();
}
bool Linker::resolve(Module& pModule, IRBuilder& pBuilder)
{
assert(NULL != m_pConfig);
m_pIRBuilder = &pBuilder;
assert(m_pObjLinker!=NULL);
m_pObjLinker->setup(pModule, pBuilder);
// 2. - initialize FragmentLinker
if (!m_pObjLinker->initFragmentLinker())
return false;
// 3. - initialize output's standard sections
if (!m_pObjLinker->initStdSections())
return false;
if (!Diagnose())
return false;
// 4. - 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);
}
else {
m_pConfig->setCodePosition(LinkerConfig::DynamicDependent);
}
if (!m_pObjLinker->linkable())
return Diagnose();
// 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.
m_pObjLinker->readRelocations();
// 7. - merge all sections
// Push sections into Module's SectionTable.
// Merge sections that have the same name.
// Maintain them as fragments in the section.
if (!m_pObjLinker->mergeSections())
return false;
// 8. - allocateCommonSymbols
// Allocate fragments for common symbols to the corresponding sections.
if (!m_pObjLinker->allocateCommonSymbols())
return false;
return true;
}
bool Linker::layout()
{
assert(NULL != m_pConfig && NULL != m_pObjLinker);
// 9. - add standard symbols, target-dependent symbols and script symbols
// m_pObjLinker->addUndefSymbols();
if (!m_pObjLinker->addStandardSymbols() ||
!m_pObjLinker->addTargetSymbols() ||
!m_pObjLinker->addScriptSymbols())
return false;
// 10. - 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();
// 11.a - init relaxation stuff.
m_pObjLinker->initStubs();
// 11.b - pre-layout
m_pObjLinker->prelayout();
// 11.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();
// 11.d - post-layout (create segment, instruction relaxing)
m_pObjLinker->postlayout();
// 12. - finalize symbol value
m_pObjLinker->finalizeSymbolValue();
// 13. - apply relocations
m_pObjLinker->relocation();
if (!Diagnose())
return false;
return true;
}
bool Linker::emit(MemoryArea& pOutput)
{
// 13. - write out output
m_pObjLinker->emitOutput(pOutput);
// 14. - post processing
m_pObjLinker->postProcessing(pOutput);
if (!Diagnose())
return false;
return true;
}
bool Linker::emit(const std::string& pPath)
{
FileHandle file;
FileHandle::Permission perm = 0755;
if (!file.open(pPath,
FileHandle::ReadWrite | FileHandle::Truncate | FileHandle::Create,
perm)) {
error(diag::err_cannot_open_output_file) << "Linker::emit()" << pPath;
return false;
}
MemoryArea* output = new MemoryArea(file);
bool result = emit(*output);
delete output;
file.close();
return result;
}
bool Linker::emit(int pFileDescriptor)
{
FileHandle file;
file.delegate(pFileDescriptor);
MemoryArea* output = new MemoryArea(file);
bool result = emit(*output);
delete output;
file.close();
return result;
}
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(NULL != m_pConfig);
std::string error;
m_pTarget = mcld::TargetRegistry::lookupTarget(m_pConfig->targets().triple().str(), error);
if (NULL == m_pTarget) {
fatal(diag::fatal_cannot_init_target) << m_pConfig->targets().triple().str() << error;
return false;
}
return true;
}
bool Linker::initBackend()
{
assert(NULL != m_pTarget);
m_pBackend = m_pTarget->createLDBackend(*m_pConfig);
if (NULL == m_pBackend) {
fatal(diag::fatal_cannot_init_backend) << m_pConfig->targets().triple().str();
return false;
}
return true;
}
bool Linker::initEmulator()
{
assert(NULL != m_pTarget && NULL != m_pConfig);
bool result = m_pTarget->emulate(m_pConfig->targets().triple().str(),
*m_pConfig);
// Relocation should be set up after emulation.
Relocation::SetUp(*m_pConfig);
return result;
}
bool Linker::initOStream()
{
assert(NULL != m_pConfig);
mcld::outs().setColor(m_pConfig->options().color());
mcld::errs().setColor(m_pConfig->options().color());
return true;
}