/* * 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; } }