blob: 0d112ba0f52d6bb469157e42f75f058d9619dd58 [file] [log] [blame]
//===- Linker.cpp ---------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "alone/Linker.h"
#include "alone/Support/LinkerConfig.h"
#include "alone/Support/MemoryFactory.h"
#include <llvm/Support/ELF.h>
#include <mcld/MC/MCLinker.h>
#include <mcld/MC/InputTree.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/LDContext.h>
#include <mcld/Target/TargetLDBackend.h>
#include <mcld/Support/Path.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/FileHandle.h>
using namespace alone;
const char* Linker::GetErrorString(enum Linker::ErrorCode pErrCode)
{
static const char* ErrorString[] = {
/* kSuccess */
"Successfully compiled.",
/* kDoubleConfig */
"Configure Linker twice.",
/* kCreateBackend */
"Cannot create backend.",
/* kDelegateLDInfo */
"Cannot get linker information",
/* kOpenNameSpec */
"Cannot open -lnamespec",
/* kOpenObjectFile */
"Cannot open object file",
/* kNotConfig */
"Linker::config() is not called",
/* kNotSetUpOutput */
"Linker::setOutput() is not called before add input files",
/* kOpenOutput */
"Cannot open output file",
/* kReadSections */
"Cannot read sections",
/* kReadSymbols */
"Cannot read symbols",
/* kAddAdditionalSymbols */
"Cannot add standard and target symbols",
/* kMaxErrorCode */
"(Unknown error code)"
};
if (pErrCode > kMaxErrorCode) {
pErrCode = kMaxErrorCode;
}
return ErrorString[ static_cast<size_t>(pErrCode) ];
}
//===----------------------------------------------------------------------===//
// Linker
//===----------------------------------------------------------------------===//
Linker::Linker()
: mBackend(NULL), mDriver(NULL), mMemAreaFactory(NULL), mLDInfo(NULL) {
}
Linker::Linker(const LinkerConfig& pConfig)
: mBackend(NULL), mDriver(NULL), mMemAreaFactory(NULL), mLDInfo(NULL) {
const std::string &triple = pConfig.getTriple();
enum ErrorCode err = config(pConfig);
if (kSuccess != err) {
ALOGE("%s (%s)", GetErrorString(err), triple.c_str());
return;
}
return;
}
Linker::~Linker()
{
if (NULL != mDriver)
delete mDriver;
if (NULL != mBackend)
delete mBackend;
if (NULL != mMemAreaFactory)
delete mMemAreaFactory;
}
enum Linker::ErrorCode Linker::extractFiles(const LinkerConfig& pConfig)
{
mLDInfo = const_cast<mcld::MCLDInfo*>(pConfig.getLDInfo());
if (NULL == mLDInfo)
return kDelegateLDInfo;
mRoot = mLDInfo->inputs().root();
return kSuccess;
}
enum Linker::ErrorCode Linker::config(const LinkerConfig& pConfig)
{
if (NULL != mLDInfo)
return kDoubleConfig;
extractFiles(pConfig);
mBackend = pConfig.getTarget()->createLDBackend(pConfig.getTriple());
if (NULL == mBackend)
return kCreateBackend;
mDriver = new mcld::MCLDDriver(*mLDInfo, *mBackend);
mMemAreaFactory = new MemoryFactory();
mDriver->initMCLinker();
return kSuccess;
}
void Linker::advanceRoot()
{
if (mRoot.isRoot())
--mRoot;
else
++mRoot;
}
enum Linker::ErrorCode
Linker::openFile(const mcld::sys::fs::Path& pPath, enum Linker::ErrorCode pCode, mcld::Input& pInput)
{
mcld::MemoryArea *input_memory = mMemAreaFactory->produce(pPath,
mcld::FileHandle::ReadOnly);
if (input_memory->handler()->isGood())
pInput.setMemArea(input_memory);
else
return pCode;
mcld::LDContext *input_context = mLDInfo->contextFactory().produce(pPath);
pInput.setContext(input_context);
return kSuccess;
}
enum Linker::ErrorCode Linker::addNameSpec(const std::string &pNameSpec)
{
mcld::sys::fs::Path* path = NULL;
// find out the real path of the namespec.
if (mLDInfo->attrFactory().constraint().isSharedSystem()) {
// In the system with shared object support, we can find both archive
// and shared object.
if (mLDInfo->attrFactory().last().isStatic()) {
// with --static, we must search an archive.
path = mLDInfo->options().directories().find(pNameSpec, mcld::Input::Archive);
}
else {
// otherwise, with --Bdynamic, we can find either an archive or a
// shared object.
path = mLDInfo->options().directories().find(pNameSpec, mcld::Input::DynObj);
}
}
else {
// In the system without shared object support, we only look for an
// archive.
path = mLDInfo->options().directories().find(pNameSpec, mcld::Input::Archive);
}
mcld::Input* input = mLDInfo->inputFactory().produce(pNameSpec, *path,
mcld::Input::Unknown);
mLDInfo->inputs().insert<mcld::InputTree::Positional>(mRoot, *input);
advanceRoot();
return openFile(*path, kOpenNameSpec, *input);
}
/// addObject - Add a object file by the filename.
enum Linker::ErrorCode Linker::addObject(const std::string &pObjectPath)
{
mcld::Input* input = mLDInfo->inputFactory().produce(pObjectPath,
pObjectPath,
mcld::Input::Unknown);
mLDInfo->inputs().insert<mcld::InputTree::Positional>(mRoot, *input);
advanceRoot();
return openFile(pObjectPath, kOpenObjectFile, *input);
}
/// addObject - Add a piece of memory. The memory is of ELF format.
enum Linker::ErrorCode Linker::addObject(void* pMemory, size_t pSize)
{
mcld::Input* input = mLDInfo->inputFactory().produce("memory object",
"NAN",
mcld::Input::Unknown);
mLDInfo->inputs().insert<mcld::InputTree::Positional>(mRoot, *input);
advanceRoot();
mcld::MemoryArea *input_memory = mMemAreaFactory->produce(pMemory, pSize);
input->setMemArea(input_memory);
mcld::LDContext *input_context = mLDInfo->contextFactory().produce();
input->setContext(input_context);
return kSuccess;
}
enum Linker::ErrorCode Linker::addCode(void* pMemory, size_t pSize)
{
mcld::Input* input = mLDInfo->inputFactory().produce("code object",
"NAN",
mcld::Input::External);
mLDInfo->inputs().insert<mcld::InputTree::Positional>(mRoot, *input);
advanceRoot();
mcld::MemoryArea *input_memory = mMemAreaFactory->produce(pMemory, pSize);
input->setMemArea(input_memory);
mcld::LDContext *input_context = mLDInfo->contextFactory().produce();
input->setContext(input_context);
// FIXME: So far, MCLinker must set up output before add input files.
// set up LDContext
if (mDriver->hasInitLinker())
return kNotConfig;
if (!mLDInfo->output().hasContext())
return kNotSetUpOutput;
// create NULL section
mcld::LDSection& null = mDriver->getLinker()->createSectHdr("",
mcld::LDFileFormat::Null,
llvm::ELF::SHT_NULL,
0);
null.setSize(0);
null.setOffset(0);
null.setIndex(0);
null.setInfo(0);
null.setAlign(0);
input_context->getSectionTable().push_back(&null);
// create .text section
mcld::LDSection& text = mDriver->getLinker()->createSectHdr(".text",
mcld::LDFileFormat::Regular,
llvm::ELF::SHT_PROGBITS,
llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR);
text.setSize(pSize);
text.setOffset(0x0);
text.setIndex(1);
text.setInfo(0);
text.setAlign(1);
input_context->getSectionTable().push_back(&text);
return kSuccess;
}
enum Linker::ErrorCode Linker::setOutput(const std::string &pPath)
{
if (mLDInfo->output().hasContext())
return kDoubleConfig;
// ----- initialize output file ----- //
mcld::FileHandle::Permission perm = 0755;
mcld::MemoryArea* out_area = mMemAreaFactory->produce(
pPath,
mcld::FileHandle::ReadWrite | mcld::FileHandle::Truncate,
perm);
if (!out_area->handler()->isGood())
return kOpenOutput;
// FIXME: decide output type by command line option.
mLDInfo->output().setType(mcld::Output::DynObj);
mLDInfo->output().setMemArea(out_area);
mLDInfo->output().setContext(mLDInfo->contextFactory().produce(pPath));
// FIXME: We must initialize MCLinker before setOutput, and initialize
// standard sections here. This is because we have to build the section
// map before input files using it.
if (!mDriver->hasInitLinker())
return kNotConfig;
mDriver->initStdSections();
return kSuccess;
}
enum Linker::ErrorCode Linker::setOutput(int pFileHandler)
{
if (mLDInfo->output().hasContext())
return kDoubleConfig;
// ----- initialize output file ----- //
mcld::MemoryArea* out_area = mMemAreaFactory->produce(pFileHandler);
mLDInfo->output().setType(mcld::Output::DynObj);
mLDInfo->output().setMemArea(out_area);
mLDInfo->output().setContext(mLDInfo->contextFactory().produce());
// FIXME: We must initialize MCLinker before setOutput, and initialize
// standard sections here. This is because we have to build the section
// map before input files using it.
if (!mDriver->hasInitLinker())
return kNotConfig;
mDriver->initStdSections();
return kSuccess;
}
enum Linker::ErrorCode Linker::link()
{
mDriver->normalize();
if (!mDriver->readSections() ||
!mDriver->mergeSections())
return kReadSections;
if (!mDriver->readSymbolTables())
return kReadSymbols;
if (!mDriver->addStandardSymbols() ||
!mDriver->addTargetSymbols())
return kAddAdditionalSymbols;
mDriver->readRelocations();
mDriver->prelayout();
mDriver->layout();
mDriver->postlayout();
mDriver->finalizeSymbolValue();
mDriver->relocation();
mDriver->emitOutput();
mDriver->postProcessing();
return kSuccess;
}