C++程序  |  342行  |  9.37 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/Support/LinkerConfig.h"
#include "bcc/Support/Log.h"

#include <llvm/Support/Signals.h>

#include <mcld/LinkerConfig.h>
#include <mcld/MC/MCLDDirectory.h>
#include <mcld/MC/ZOption.h>
#include <mcld/LD/TextDiagnosticPrinter.h>
#include <mcld/Support/Path.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/raw_ostream.h>

using namespace bcc;

LinkerConfig::LinkerConfig(const std::string &pTriple)
  : mTriple(pTriple), mSOName(), mTarget(NULL), mLDConfig(NULL),
    mDiagLineInfo(NULL), mDiagPrinter(NULL) {

  initializeTarget();
  initializeLDInfo();
  initializeDiagnostic();
}

LinkerConfig::~LinkerConfig() {
  delete mLDConfig;

  if (mDiagPrinter->getNumErrors() != 0) {
    // If here, the program failed ungracefully. Run the interrupt handlers to
    // ensure any other cleanups (e.g., files that registered by
    // RemoveFileOnSignal(...)) getting done before exit.
    llvm::sys::RunInterruptHandlers();
  }
  mDiagPrinter->finish();

  delete mDiagLineInfo;
  delete mDiagPrinter;
}

bool LinkerConfig::initializeTarget() {
  std::string error;
  mTarget = mcld::TargetRegistry::lookupTarget(mTriple, error);
  if (NULL != mTarget) {
    return true;
  } else {
    ALOGE("Cannot initialize mcld::Target for given triple '%s'! (%s)\n",
          mTriple.c_str(), error.c_str());
    return false;
  }
}

bool LinkerConfig::initializeLDInfo() {
  if (NULL != mLDConfig) {
    ALOGE("Cannot initialize mcld::MCLDInfo for given triple '%s!\n",
          mTriple.c_str());
    return false;
  }

  mLDConfig = new mcld::LinkerConfig(getTriple());
  mLDConfig->setCodeGenType(mcld::LinkerConfig::Exec);

  struct NameMap {
    const char* from;
    const char* to;
  };

  static const NameMap map[] =
  {
    {".text", ".text"},
    {".rodata", ".rodata"},
    {".data.rel.ro.local", ".data.rel.ro.local"},
    {".data.rel.ro", ".data.rel.ro"},
    {".data", ".data"},
    {".bss", ".bss"},
    {".tdata", ".tdata"},
    {".tbss", ".tbss"},
    {".init_array", ".init_array"},
    {".fini_array", ".fini_array"},
    // TODO: Support DT_INIT_ARRAY for all constructors?
    {".ctors", ".ctors"},
    {".dtors", ".dtors"},
    // FIXME: in GNU ld, if we are creating a shared object .sdata2 and .sbss2
    // sections would be handled differently.
    {".sdata2", ".sdata"},
    {".sbss2", ".sbss"},
    {".sdata", ".sdata"},
    {".sbss", ".sbss"},
    {".lrodata", ".lrodata"},
    {".ldata", ".ldata"},
    {".lbss", ".lbss"},
    {".gcc_except_table", ".gcc_except_table"},
    {".gnu.linkonce.d.rel.ro.local", ".data.rel.ro.local"},
    {".gnu.linkonce.d.rel.ro", ".data.rel.ro"},
    {".gnu.linkonce.r", ".rodata"},
    {".gnu.linkonce.d", ".data"},
    {".gnu.linkonce.b", ".bss"},
    {".gnu.linkonce.sb2", ".sbss"},
    {".gnu.linkonce.sb", ".sbss"},
    {".gnu.linkonce.s2", ".sdata"},
    {".gnu.linkonce.s", ".sdata"},
    {".gnu.linkonce.wi", ".debug_info"},
    {".gnu.linkonce.td", ".tdata"},
    {".gnu.linkonce.tb", ".tbss"},
    {".gnu.linkonce.t", ".text"},
    {".gnu.linkonce.lr", ".lrodata"},
    {".gnu.linkonce.lb", ".lbss"},
    {".gnu.linkonce.l", ".ldata"},
  };

  if (mLDConfig->codeGenType() != mcld::LinkerConfig::Object) {
    const unsigned int map_size =  (sizeof(map) / sizeof(map[0]) );
    for (unsigned int i = 0; i < map_size; ++i) {
      bool exist = false;
      mLDConfig->scripts().sectionMap().append(map[i].from,
                                               map[i].to,
                                               exist);
    }
  }
  return true;
}

bool LinkerConfig::initializeDiagnostic() {
  // Set up MsgHandler.
  mDiagPrinter = new mcld::TextDiagnosticPrinter(mcld::errs(), *mLDConfig);

  mcld::InitializeDiagnosticEngine(*mLDConfig, mDiagPrinter);

  mDiagLineInfo = mTarget->createDiagnosticLineInfo(*mTarget, mTriple);

  mcld::getDiagnosticEngine().setLineInfo(*mDiagLineInfo);
  return true;
}

bool LinkerConfig::isShared() const {
  return (mcld::LinkerConfig::DynObj == mLDConfig->codeGenType());
}

void LinkerConfig::setShared(bool pEnable) {
  if (pEnable)
    mLDConfig->setCodeGenType(mcld::LinkerConfig::DynObj);
  else
    mLDConfig->setCodeGenType(mcld::LinkerConfig::Exec);
  return;
}

void LinkerConfig::setBsymbolic(bool pEnable) {
  mLDConfig->options().setBsymbolic(pEnable);
  return;
}

void LinkerConfig::setDefineCommon(bool pEnable) {
  mLDConfig->options().setDefineCommon(pEnable);
  return;
}

void LinkerConfig::setSOName(const std::string &pSOName) {
  mLDConfig->options().setSOName(pSOName);
  return;
}

void LinkerConfig::setDyld(const std::string &pDyld) {
  mLDConfig->options().setDyld(pDyld);
  return;
}

void LinkerConfig::setSysRoot(const std::string &pSysRoot) {
  mLDConfig->options().setSysroot(mcld::sys::fs::Path(pSysRoot));
  return;
}

void LinkerConfig::setZOption(unsigned int pOptions) {
  mcld::ZOption option;
  if (pOptions & kCombReloc) {
    option.setKind(mcld::ZOption::CombReloc);
    mLDConfig->options().addZOption(option);
  }
  else {
    option.setKind(mcld::ZOption::NoCombReloc);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kDefs) {
    option.setKind(mcld::ZOption::Defs);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kExecStack) {
    option.setKind(mcld::ZOption::ExecStack);
    mLDConfig->options().addZOption(option);
  }
  else {
    option.setKind(mcld::ZOption::NoExecStack);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kInitFirst) {
    option.setKind(mcld::ZOption::InitFirst);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kInterPose) {
    option.setKind(mcld::ZOption::InterPose);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kLoadFltr) {
    option.setKind(mcld::ZOption::LoadFltr);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kMulDefs) {
    option.setKind(mcld::ZOption::MulDefs);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kNoCopyReloc) {
    option.setKind(mcld::ZOption::NoCopyReloc);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kNoDefaultLib) {
    option.setKind(mcld::ZOption::NoDefaultLib);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kNoDelete) {
    option.setKind(mcld::ZOption::NoDelete);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kNoDLOpen) {
    option.setKind(mcld::ZOption::NoDLOpen);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kNoDump) {
    option.setKind(mcld::ZOption::NoDump);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kRelro) {
    option.setKind(mcld::ZOption::Relro);
    mLDConfig->options().addZOption(option);
  }
  else {
    option.setKind(mcld::ZOption::NoRelro);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kLazy) {
    option.setKind(mcld::ZOption::Lazy);
    mLDConfig->options().addZOption(option);
  }
  else {
    option.setKind(mcld::ZOption::Now);
    mLDConfig->options().addZOption(option);
  }

  if (pOptions & kOrigin) {
    option.setKind(mcld::ZOption::Origin);
    mLDConfig->options().addZOption(option);
  }
}

void LinkerConfig::addWrap(const std::string &pWrapSymbol) {
  bool exist = false;

  // Add wname -> __wrap_wname.
  mcld::StringEntry<llvm::StringRef>* to_wrap =
               mLDConfig->scripts().renameMap().insert(pWrapSymbol, exist);

  std::string to_wrap_str = "__wrap_" + pWrapSymbol;
  to_wrap->setValue(to_wrap_str);

  if (exist) {
    mcld::warning(mcld::diag::rewrap) << pWrapSymbol << to_wrap_str;
  }

  // Add __real_wname -> wname.
  std::string from_real_str = "__real_" + pWrapSymbol;
  mcld::StringEntry<llvm::StringRef>* from_real =
             mLDConfig->scripts().renameMap().insert(from_real_str, exist);
  from_real->setValue(pWrapSymbol);

  if (exist) {
    mcld::warning(mcld::diag::rewrap) << pWrapSymbol << from_real_str;
  }

  return;
}

void LinkerConfig::addPortable(const std::string &pPortableSymbol) {
  bool exist = false;

  // Add pname -> pname_portable.
  mcld::StringEntry<llvm::StringRef>* to_port =
                mLDConfig->scripts().renameMap().insert(pPortableSymbol, exist);

  std::string to_port_str = pPortableSymbol + "_portable";
  to_port->setValue(to_port_str);

  if (exist) {
    mcld::warning(mcld::diag::rewrap) << pPortableSymbol << to_port_str;
}

  // Add __real_pname -> pname.
  std::string from_real_str = "__real_" + pPortableSymbol;
  mcld::StringEntry<llvm::StringRef>* from_real =
           mLDConfig->scripts().renameMap().insert(from_real_str, exist);

  from_real->setValue(pPortableSymbol);

  if (exist) {
    mcld::warning(mcld::diag::rewrap) << pPortableSymbol << from_real_str;
  }

  return;
}

void LinkerConfig::addSearchDir(const std::string &pDirPath) {
  // SearchDirs will remove the created MCLDDirectory.
  if (!mLDConfig->options().directories().insert(pDirPath)) {
    mcld::warning(mcld::diag::warn_cannot_open_search_dir) << pDirPath;
  }
}