bool SearchPathOptions::parse(LinkerConfig& pConfig, LinkerScript& pScript)
{
  // set --sysroot
  if (!m_SysRoot.empty()) {
    if (exists(m_SysRoot) && is_directory(m_SysRoot))
      pScript.setSysroot(m_SysRoot);
  }

  // set -L[path]
  llvm::cl::list<std::string>::iterator sd;
  llvm::cl::list<std::string>::iterator sdEnd = m_SearchDirList.end();
  for (sd = m_SearchDirList.begin(); sd != sdEnd; ++sd) {
    if (!pScript.directories().insert(*sd)) {
      // FIXME: need a warning function
      errs() << "WARNING: can not open search directory `-L"
             << *sd
             << "'.\n";
    }
  }

  // set -no-stdlib
  pConfig.options().setNoStdlib(m_NoStdlib);

  // set --rpath [path]
  llvm::cl::list<std::string>::iterator rp;
  llvm::cl::list<std::string>::iterator rpEnd = m_RuntimePath.end();
  for (rp = m_RuntimePath.begin(); rp != rpEnd; ++rp) {
    pConfig.options().getRpathList().push_back(*rp);
  }

  return true;
}
// FIXME: LinkerConfig& pConfig should be constant
bool MCLDEmulateELF(LinkerScript& pScript, LinkerConfig& pConfig) {
  // set up section map
  if (pConfig.options().getScriptList().empty() &&
      pConfig.codeGenType() != LinkerConfig::Object) {
    const unsigned int map_size = (sizeof(map) / sizeof(map[0]));
    for (unsigned int i = 0; i < map_size; ++i) {
      std::pair<SectionMap::mapping, bool> res =
          pScript.sectionMap().insert(map[i].from, map[i].to, map[i].policy);
      if (!res.second)
        return false;
    }
  } else {
    // FIXME: this is the hack to help assignment processing in current
    // implementation.
    pScript.sectionMap().insert("", "");
  }

  if (!pConfig.options().nostdlib()) {
    // TODO: check if user sets the default search path instead via -Y option
    // set up default search path
    switch (pConfig.targets().triple().getOS()) {
      case llvm::Triple::NetBSD:
        pScript.directories().insert("=/usr/lib");
        break;
      case llvm::Triple::Win32:
        pScript.directories().insert("=/mingw/lib");
        break;
      default:
        pScript.directories().insert("=/lib");
        pScript.directories().insert("=/usr/lib");
        break;
    }
  }
  return true;
}
bool TargetControlOptions::parse(LinkerConfig& pConfig)
{
  // set -G [size]
  pConfig.options().setGPSize(m_GPSize);

  // set --warn-shared-textrel
  pConfig.options().setWarnSharedTextrel(m_WarnSharedTextrel);

  // set --fix-cortex-a8
  if (m_FIXCA8)
    mcld::warning(mcld::diag::warn_unsupported_option) << m_FIXCA8.ArgStr;

  return true;
}
static bool MCLDEmulateARMELF(LinkerScript& pScript, LinkerConfig& pConfig)
{
  if (!MCLDEmulateELF(pScript, pConfig))
    return false;

  // set up bitclass and endian
  pConfig.targets().setEndian(TargetOptions::Little);
  pConfig.targets().setBitClass(32);

  // set up target-dependent constraints of attributes
  pConfig.attribute().constraint().enableWholeArchive();
  pConfig.attribute().constraint().enableAsNeeded();
  pConfig.attribute().constraint().setSharedSystem();

  // set up the predefined attributes
  pConfig.attribute().predefined().unsetWholeArchive();
  pConfig.attribute().predefined().unsetAsNeeded();
  pConfig.attribute().predefined().setDynamic();

  // set up section map
  if (pConfig.options().getScriptList().empty() &&
      pConfig.codeGenType() != LinkerConfig::Object) {
    pScript.sectionMap().insert(".ARM.exidx*", ".ARM.exidx");
    pScript.sectionMap().insert(".ARM.extab*", ".ARM.extab");
    pScript.sectionMap().insert(".ARM.attributes*", ".ARM.attributes");
  }
  return true;
}
bool DynamicSectionOptions::parse(LinkerConfig& pConfig,
                                  LinkerScript& pScript) {
  // set up entry point from -e
  pScript.setEntry(m_Entry);

  // --Bsymbolic
  pConfig.options().setBsymbolic(m_Bsymbolic);

  // --Bgroup
  pConfig.options().setBgroup(m_Bgroup);

  // set --soname [soname]
  pConfig.options().setSOName(m_SOName);

  // set -z options
  llvm::cl::list<ZOption>::iterator zOpt;
  llvm::cl::list<ZOption>::iterator zOptEnd = m_ZOptionList.end();
  for (zOpt = m_ZOptionList.begin(); zOpt != zOptEnd; ++zOpt) {
    pConfig.options().addZOption(*zOpt);
  }

  // set --no-undefined
  if (llvm::cl::BOU_UNSET != m_NoUndefined)
    pConfig.options().setNoUndefined(llvm::cl::BOU_TRUE == m_NoUndefined);

  // set --allow-multiple-definition
  if (llvm::cl::BOU_UNSET != m_AllowMulDefs)
    pConfig.options().setMulDefs(llvm::cl::BOU_TRUE == m_AllowMulDefs);

  // set --dynamic-linker [dyld]
  pConfig.options().setDyld(m_Dyld);

  // set --enable-new-dtags
  pConfig.options().setNewDTags(m_EnableNewDTags);

  // set --auxiliary, -f
  llvm::cl::list<std::string>::iterator aux;
  llvm::cl::list<std::string>::iterator auxEnd = m_Auxiliary.end();
  for (aux = m_Auxiliary.begin(); aux != auxEnd; ++aux)
    pConfig.options().getAuxiliaryList().push_back(*aux);

  // set --filter, -F
  pConfig.options().setFilter(m_Filter);

  return true;
}
//===----------------------------------------------------------------------===//
// Testcases
//===----------------------------------------------------------------------===//
TEST_F(ELFBinaryReaderTest, is_myformat) {
  LinkerScript script;
  Module module("test", script);
  LinkerConfig config;
  IRBuilder builder(module, config);
  ELFBinaryReader* reader = new ELFBinaryReader(builder, config);

  Input input("test.bin");

  bool doContinue = false;
  config.options().setBinaryInput();
  ASSERT_TRUE(reader->isMyFormat(input, doContinue));

  config.options().setBinaryInput(false);
  ASSERT_FALSE(reader->isMyFormat(input, doContinue));

  delete reader;
}
/// getEntryPoint
uint64_t ELFObjectWriter::getEntryPoint(const LinkerConfig& pConfig,
                                        const Module& pModule) const
{
  llvm::StringRef entry_name;
  if (pConfig.options().hasEntry())
    entry_name = pConfig.options().entry();
  else
    entry_name = target().getInfo().entry();

  uint64_t result = 0x0;

  bool issue_warning = (pConfig.options().hasEntry() &&
                        LinkerConfig::Object != pConfig.codeGenType() &&
                        LinkerConfig::DynObj != pConfig.codeGenType());

  const LDSymbol* entry_symbol = pModule.getNamePool().findSymbol(entry_name);

  // found the symbol
  if (NULL != entry_symbol) {
    if (entry_symbol->desc() != ResolveInfo::Define && issue_warning) {
      llvm::errs() << "WARNING: entry symbol '"
                   << entry_symbol->name()
                   << "' exists but is not defined.\n";
    }
    result = entry_symbol->value();
  }
  // not in the symbol pool
  else {
    // We should parse entry as a number.
    // @ref GNU ld manual, Options -e. e.g., -e 0x1000.
    char* endptr;
    result = strtoull(entry_name.data(), &endptr, 0);
    if (*endptr != '\0') {
      if (issue_warning) {
        llvm::errs() << "cannot find entry symbol '"
                     << entry_name.data()
                     << "'.\n";
      }
      result = 0x0;
    }
  }
  return result;
}
bool OptimizationOptions::parse(LinkerConfig& pConfig)
{
  // set --gc-sections
  if (m_GCSections)
    pConfig.options().setGCSections();

  // set --ld-generated-unwind-info (or not)
  pConfig.options().setGenUnwindInfo(m_GenUnwindInfo);

  // set --icf [mode]
  switch (m_ICF) {
    case ICF_None:
      break;
    case ICF_All:
    case ICF_Safe:
    default:
      warning(mcld::diag::warn_unsupported_option) << m_ICF.ArgStr;
      break;
  }

  return true;
}
bool OutputFormatOptions::parse(mcld::Module& pModule, LinkerConfig& pConfig)
{
  if (!parseOutput(pModule, pConfig)) {
    mcld::unreachable(mcld::diag::unrecognized_output_file) << pModule.name();
    return false;
  }

  if (mcld::Input::Binary == m_Format)
    pConfig.options().setBinaryInput();

  pConfig.options().setStripDebug(m_StripDebug || m_StripAll);
  if (m_StripAll)
    pConfig.options().setStripSymbols(mcld::GeneralOptions::StripAllSymbols);
  else if (m_DiscardAll)
    pConfig.options().setStripSymbols(mcld::GeneralOptions::StripLocals);
  else if (m_DiscardLocals)
    pConfig.options().setStripSymbols(mcld::GeneralOptions::StripTemporaries);
  else
    pConfig.options().setStripSymbols(mcld::GeneralOptions::KeepAllSymbols);

  pConfig.options().setEhFrameHdr(m_EhFrameHdr);
  pConfig.options().setPIE(m_PIE);
  pConfig.options().setNMagic(m_NMagic);
  pConfig.options().setOMagic(m_OMagic);
  pConfig.options().setHashStyle(m_HashStyle);
  pConfig.options().setExportDynamic(m_ExportDynamic);
  if (m_NoWarnMismatch)
    pConfig.options().setWarnMismatch(false);
  else
    pConfig.options().setWarnMismatch(true);
  // build-id
  // exclude-libs

  return true;
}