367 lines
10 KiB
C++
367 lines
10 KiB
C++
//===- 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 <cassert>
|
|
|
|
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<FileOutputBuffer> 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<FileOutputBuffer> 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
|