C++程序  |  182行  |  4.93 KB

/*
 * Copyright 2012, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "bcc/Linker.h"
#include "bcc/Support/LinkerConfig.h"
#include "bcc/Support/Log.h"

#include <llvm/Support/ELF.h>

#include <mcld/Module.h>
#include <mcld/IRBuilder.h>
#include <mcld/MC/MCLDInput.h>
#include <mcld/Linker.h>
#include <mcld/LD/LDSection.h>
#include <mcld/LD/LDContext.h>
#include <mcld/Support/Path.h>

using namespace bcc;

const char* Linker::GetErrorString(enum Linker::ErrorCode pErrCode) {
  static const char* ErrorString[] = {
    /* kSuccess */
    "Successfully compiled.",
    /* kDoubleConfig */
    "Configure Linker twice.",
    /* kDelegateLDInfo */
    "Cannot get linker information",
    /* kFindNameSpec */
    "Cannot find -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()
  : mLDConfig(NULL), mModule(NULL), mLinker(NULL), mBuilder(NULL),
    mOutputHandler(-1) {
}

Linker::Linker(const LinkerConfig& pConfig)
  : mLDConfig(NULL), mModule(NULL), mLinker(NULL), mBuilder(NULL),
    mOutputHandler(-1) {

  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() {
  delete mModule;
  delete mLinker;
  delete mBuilder;
}

enum Linker::ErrorCode Linker::extractFiles(const LinkerConfig& pConfig) {
  mLDConfig = pConfig.getLDConfig();
  if (mLDConfig == NULL) {
    return kDelegateLDInfo;
  }
  return kSuccess;
}

enum Linker::ErrorCode Linker::config(const LinkerConfig& pConfig) {
  if (mLDConfig != NULL) {
    return kDoubleConfig;
  }

  extractFiles(pConfig);

  mModule = new mcld::Module(mLDConfig->options().soname());

  mBuilder = new mcld::IRBuilder(*mModule, *mLDConfig);

  mLinker = new mcld::Linker();

  mLinker->config(const_cast<mcld::LinkerConfig&>(*mLDConfig));

  return kSuccess;
}

enum Linker::ErrorCode Linker::addNameSpec(const std::string &pNameSpec) {
  mcld::Input* input = mBuilder->ReadInput(pNameSpec);
  if (NULL == input)
    return kFindNameSpec;
  return kSuccess;
}

/// addObject - Add a object file by the filename.
enum Linker::ErrorCode Linker::addObject(const std::string &pObjectPath) {
  mcld::Input* input = mBuilder->ReadInput(pObjectPath, pObjectPath);
  if (NULL == input)
    return kOpenObjectFile;
  return kSuccess;
}

/// 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 = mBuilder->ReadInput("NAN", pMemory, pSize);
  if (NULL == input)
    return kOpenMemory;
  return kSuccess;
}

enum Linker::ErrorCode Linker::addCode(void* pMemory, size_t pSize) {
  mcld::Input* input = mBuilder->CreateInput("NAN", "NAN", mcld::Input::Object);
  mcld::LDSection* sect = mBuilder->CreateELFHeader(*input, ".text",
                                llvm::ELF::SHT_PROGBITS,
                                llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
                                0x1);
  mcld::SectionData* data = mBuilder->CreateSectionData(*sect);
  mcld::Fragment* frag = mBuilder->CreateRegion(pMemory, pSize);
  mBuilder->AppendFragment(*frag, *data);
  return kSuccess;
}

enum Linker::ErrorCode Linker::setOutput(const std::string &pPath) {
  mOutputPath = pPath;
  return kSuccess;
}

enum Linker::ErrorCode Linker::setOutput(int pFileHandler) {
  mOutputHandler = pFileHandler;
  return kSuccess;
}

enum Linker::ErrorCode Linker::link() {
  mLinker->link(*mModule, *mBuilder);
  if (!mOutputPath.empty()) {
    mLinker->emit(mOutputPath);
    return kSuccess;
  }

  if (-1 != mOutputHandler) {
    mLinker->emit(mOutputHandler);
    return kSuccess;
  }
  return kNotSetUpOutput;
}