C++程序  |  1073行  |  33.53 KB

//===- Main.cpp -----------------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/Environment.h>
#include <mcld/IRBuilder.h>
#include <mcld/Linker.h>
#include <mcld/LinkerConfig.h>
#include <mcld/LinkerScript.h>
#include <mcld/Module.h>
#include <mcld/ADT/StringEntry.h>
#include <mcld/MC/InputAction.h>
#include <mcld/MC/CommandAction.h>
#include <mcld/MC/FileAction.h>
#include <mcld/MC/ZOption.h>
#include <mcld/Support/raw_ostream.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/Path.h>
#include <mcld/Support/SystemUtils.h>
#include <mcld/Support/TargetRegistry.h>

#include <llvm/ADT/ArrayRef.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/ADT/STLExtras.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/ADT/StringSwitch.h>
#include <llvm/Option/Arg.h>
#include <llvm/Option/ArgList.h>
#include <llvm/Option/OptTable.h>
#include <llvm/Option/Option.h>
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/Process.h>
#include <llvm/Support/Signals.h>

#include <cassert>
#include <cstdlib>
#include <string>

#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif

#if defined(_MSC_VER) || defined(__MINGW32__)
#include <io.h>
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
#endif

namespace {

class Driver {
 private:
  enum Option {
    // This is not an option.
    kOpt_INVALID = 0,
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
               HELPTEXT, METAVAR) \
    kOpt_ ## ID,
#include "Options.inc"  // NOLINT
#undef OPTION
    kOpt_LastOption
  };

  class OptTable : public llvm::opt::OptTable {
   private:
#define PREFIX(NAME, VALUE) \
    static const char* const NAME[];
#include "Options.inc"  // NOLINT
#undef PREFIX
    static const llvm::opt::OptTable::Info InfoTable[];

   public:
    OptTable();
  };

 private:
  explicit Driver(const char* prog_name)
      : prog_name_(prog_name),
        module_(script_),
        ir_builder_(module_, config_) {
    return;
  }

 public:
  static std::unique_ptr<Driver> Create(llvm::ArrayRef<const char*> argv);

  bool Run();

 private:
  bool TranslateArguments(llvm::opt::InputArgList& args);

 private:
  const char* prog_name_;

  mcld::LinkerScript script_;

  mcld::LinkerConfig config_;

  mcld::Module module_;

  mcld::IRBuilder ir_builder_;

  mcld::Linker linker_;

 private:
  DISALLOW_COPY_AND_ASSIGN(Driver);
};

#define PREFIX(NAME, VALUE) \
    const char* const Driver::OptTable::NAME[] = VALUE;
#include "Options.inc"  // NOLINT
#undef PREFIX

const llvm::opt::OptTable::Info Driver::OptTable::InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
               HELPTEXT, METAVAR) \
    { PREFIX, NAME, HELPTEXT, METAVAR, kOpt_ ## ID, \
      llvm::opt::Option::KIND ## Class, PARAM, FLAGS, kOpt_ ## GROUP, \
      kOpt_ ## ALIAS, ALIASARGS },
#include "Options.inc"  // NOLINT
#undef OPTION
};

Driver::OptTable::OptTable()
    : llvm::opt::OptTable(InfoTable) { }

inline bool ShouldColorize() {
  const char* term = getenv("TERM");
  return term && (0 != strcmp(term, "dumb"));
}

/// ParseProgName - Parse program name
/// This function simplifies cross-compiling by reading triple from the program
/// name. For example, if the program name is `arm-linux-eabi-ld.mcld', we can
/// get the triple is arm-linux-eabi by the program name.
inline std::string ParseProgName(const char* prog_name) {
  static const char* suffixes[] = {"ld", "ld.mcld"};

  std::string name(mcld::sys::fs::Path(prog_name).stem().native());

  for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
    if (name == suffixes[i])
      return std::string();
  }

  llvm::StringRef prog_name_ref(prog_name);
  llvm::StringRef prefix;

  for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
    if (!prog_name_ref.endswith(suffixes[i]))
      continue;

    llvm::StringRef::size_type last_component =
        prog_name_ref.rfind('-', prog_name_ref.size() - strlen(suffixes[i]));
    if (last_component == llvm::StringRef::npos)
      continue;
    llvm::StringRef prefix = prog_name_ref.slice(0, last_component);
    std::string ignored_error;
    if (!mcld::TargetRegistry::lookupTarget(prefix, ignored_error))
      continue;
    return prefix.str();
  }
  return std::string();
}

inline void ParseEmulation(llvm::Triple& triple, const char* emulation) {
  llvm::Triple emu_triple =
      llvm::StringSwitch<llvm::Triple>(emulation)
          .Case("aarch64linux", llvm::Triple("aarch64", "", "linux", "gnu"))
          .Case("armelf_linux_eabi", llvm::Triple("arm", "", "linux", "gnu"))
          .Case("elf_i386", llvm::Triple("i386", "", "", "gnu"))
          .Case("elf_x86_64", llvm::Triple("x86_64", "", "", "gnu"))
          .Case("elf32_x86_64", llvm::Triple("x86_64", "", "", "gnux32"))
          .Case("elf_i386_fbsd", llvm::Triple("i386", "", "freebsd", "gnu"))
          .Case("elf_x86_64_fbsd", llvm::Triple("x86_64", "", "freebsd", "gnu"))
          .Case("elf32ltsmip", llvm::Triple("mipsel", "", "", "gnu"))
          .Case("elf64ltsmip", llvm::Triple("mips64el", "", "", "gnu"))
          .Default(llvm::Triple());

  if (emu_triple.getArch() == llvm::Triple::UnknownArch &&
      emu_triple.getOS() == llvm::Triple::UnknownOS &&
      emu_triple.getEnvironment() == llvm::Triple::UnknownEnvironment)
    mcld::error(mcld::diag::err_invalid_emulation) << emulation << "\n";

  if (emu_triple.getArch() != llvm::Triple::UnknownArch)
    triple.setArch(emu_triple.getArch());

  if (emu_triple.getOS() != llvm::Triple::UnknownOS)
    triple.setOS(emu_triple.getOS());

  if (emu_triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
    triple.setEnvironment(emu_triple.getEnvironment());
}

/// Configure the output filename.
inline bool ConfigureOutputName(llvm::StringRef output_name,
                                mcld::Module& module,
                                mcld::LinkerConfig& config) {
  std::string output(output_name.str());
  if (output.empty()) {
    if (config.targets().triple().getOS() == llvm::Triple::Win32) {
      output.assign("_out");
      switch (config.codeGenType()) {
        case mcld::LinkerConfig::Object: {
          output += ".obj";
          break;
        }
        case mcld::LinkerConfig::DynObj: {
          output += ".dll";
          break;
        }
        case mcld::LinkerConfig::Exec: {
          output += ".exe";
          break;
        }
        case mcld::LinkerConfig::External:
          break;
        default: {
          return false;
          break;
        }
      }  // switch (config.codeGenType())
    } else {
      output.assign("a.out");
    }
  }  // if (output.empty())

  module.setName(output);
  return true;
}

bool InitializeInputs(mcld::IRBuilder& ir_builder,
    std::vector<std::unique_ptr<mcld::InputAction>>& input_actions) {
  for (auto& action : input_actions) {
    assert(action != nullptr);
    action->activate(ir_builder.getInputBuilder());
  }

  if (ir_builder.getInputBuilder().isInGroup()) {
    mcld::fatal(mcld::diag::fatal_forbid_nest_group);
    return false;
  }

  return true;
}

bool Driver::TranslateArguments(llvm::opt::InputArgList& args) {
  //===--------------------------------------------------------------------===//
  // Preference
  //===--------------------------------------------------------------------===//

  // --color=mode
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Color)) {
    bool res = llvm::StringSwitch<bool>(arg->getValue())
                   .Case("never", false)
                   .Case("always", true)
                   .Case("auto", ShouldColorize() &&
                                 llvm::sys::Process::FileDescriptorIsDisplayed(
                                     STDOUT_FILENO))
                   .Default(false);
    config_.options().setColor(res);
    mcld::outs().setColor(res);
    mcld::errs().setColor(res);
  }

  // --trace
  config_.options().setTrace(args.hasArg(kOpt_Trace));

  // --verbose=level
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Verbose)) {
    llvm::StringRef value = arg->getValue();
    int level;
    if (value.getAsInteger(0, level)) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue();
      return false;
    }
    config_.options().setVerbose(level);
  }

  // --error-limit NUMBER
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_ErrorLimit)) {
    llvm::StringRef value = arg->getValue();
    int num;
    if (value.getAsInteger(0, num) || (num < 0)) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue();
      return false;
    }
    config_.options().setMaxErrorNum(num);
  }

  // --warning-limit NUMBER
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_WarningLimit)) {
    llvm::StringRef value = arg->getValue();
    int num;
    if (value.getAsInteger(0, num) || (num < 0)) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue();
      return false;
    }
    config_.options().setMaxWarnNum(num);
  }

  // --warn-shared-textrel
  config_.options().setWarnSharedTextrel(args.hasArg(kOpt_WarnSharedTextrel));

  //===--------------------------------------------------------------------===//
  // Target
  //===--------------------------------------------------------------------===//
  llvm::Triple triple;
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Triple)) {
    // 1. Use the triple from command.
    // -mtriple=value
    triple.setTriple(arg->getValue());
  } else {
    std::string prog_triple = ParseProgName(prog_name_);
    if (!prog_triple.empty()) {
      // 2. Use the triple from the program name prefix.
      triple.setTriple(prog_triple);
    } else {
      // 3. Use the default target triple.
      triple.setTriple(mcld::sys::getDefaultTargetTriple());
    }
  }

  // If a specific emulation was requested, apply it now.
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Emulation)) {
    // -m emulation
    ParseEmulation(triple, arg->getValue());
  } else if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Arch)) {
    // -march=value
    config_.targets().setArch(arg->getValue());
  }

  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_CPU)) {
    config_.targets().setTargetCPU(arg->getValue());
  }

  config_.targets().setTriple(triple);

  // --gpsize=value
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_GPSize)) {
    llvm::StringRef value = arg->getValue();
    int size;
    if (value.getAsInteger(0, size) || (size< 0)) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue() << "\n";
      return false;
    }
    config_.targets().setGPSize(size);
  }

  // --stub-group-size=value
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_StubGroupSize)) {
    llvm::StringRef value = arg->getValue();
    int size;
    if (value.getAsInteger(0, size) || (size< 0)) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue() << "\n";
      return false;
    }
    config_.targets().setStubGroupSize(size);
  }

  // --fix-cortex-a53-835769
  config_.targets().setFixCA53Erratum835769(
      args.hasArg(kOpt_FixCA53Erratum835769));

  // --fix-cortex-a53-843419
  config_.targets().setFixCA53Erratum843419(
      args.hasArg(kOpt_FixCA53Erratum843419));

  //===--------------------------------------------------------------------===//
  // Dynamic
  //===--------------------------------------------------------------------===//

  // --entry=entry
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Entry)) {
    script_.setEntry(arg->getValue());
  }

  // -Bsymbolic
  config_.options().setBsymbolic(args.hasArg(kOpt_Bsymbolic));

  // -Bgroup
  config_.options().setBgroup(args.hasArg(kOpt_Bgroup));

  // -soname=name
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_SOName)) {
    config_.options().setSOName(arg->getValue());
  }

  // --no-undefined
  if (args.hasArg(kOpt_NoUndef)) {
    config_.options().setNoUndefined(true);
  }

  // --allow-multiple-definition
  if (args.hasArg(kOpt_AllowMulDefs)) {
    config_.options().setMulDefs(true);
  }

  // -z options
  for (llvm::opt::Arg* arg : args.filtered(kOpt_Z)) {
    llvm::StringRef value = arg->getValue();
    mcld::ZOption z_opt =
        llvm::StringSwitch<mcld::ZOption>(value)
            .Case("combreloc", mcld::ZOption(mcld::ZOption::CombReloc))
            .Case("nocombreloc", mcld::ZOption(mcld::ZOption::NoCombReloc))
            .Case("defs", mcld::ZOption(mcld::ZOption::Defs))
            .Case("execstack", mcld::ZOption(mcld::ZOption::ExecStack))
            .Case("noexecstack", mcld::ZOption(mcld::ZOption::NoExecStack))
            .Case("initfirst", mcld::ZOption(mcld::ZOption::InitFirst))
            .Case("interpose", mcld::ZOption(mcld::ZOption::InterPose))
            .Case("loadfltr", mcld::ZOption(mcld::ZOption::LoadFltr))
            .Case("muldefs", mcld::ZOption(mcld::ZOption::MulDefs))
            .Case("nocopyreloc", mcld::ZOption(mcld::ZOption::NoCopyReloc))
            .Case("nodefaultlib", mcld::ZOption(mcld::ZOption::NoDefaultLib))
            .Case("nodelete", mcld::ZOption(mcld::ZOption::NoDelete))
            .Case("nodlopen", mcld::ZOption(mcld::ZOption::NoDLOpen))
            .Case("nodump", mcld::ZOption(mcld::ZOption::NoDump))
            .Case("relro", mcld::ZOption(mcld::ZOption::Relro))
            .Case("norelro", mcld::ZOption(mcld::ZOption::NoRelro))
            .Case("lazy", mcld::ZOption(mcld::ZOption::Lazy))
            .Case("now", mcld::ZOption(mcld::ZOption::Now))
            .Case("origin", mcld::ZOption(mcld::ZOption::Origin))
            .Default(mcld::ZOption());

    if (z_opt.kind() == mcld::ZOption::Unknown) {
      if (value.startswith("common-page-size=")) {
        // -z common-page-size=value
        z_opt.setKind(mcld::ZOption::CommPageSize);
        long long unsigned size = 0;
        value.drop_front(17).getAsInteger(0, size);
        z_opt.setPageSize(static_cast<uint64_t>(size));
      } else if (value.startswith("max-page-size=")) {
        // -z max-page-size=value
        z_opt.setKind(mcld::ZOption::MaxPageSize);
        long long unsigned size = 0;
        value.drop_front(14).getAsInteger(0, size);
        z_opt.setPageSize(static_cast<uint64_t>(size));
      }
    }
    config_.options().addZOption(z_opt);
  }

  // --dynamic-linker=file
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Dyld)) {
    config_.options().setDyld(arg->getValue());
  }

  // --enable-new-dtags
  config_.options().setNewDTags(args.hasArg(kOpt_EnableNewDTags));

  // --spare-dyanmic-tags COUNT
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_SpareDTags)) {
    llvm::StringRef value = arg->getValue();
    int num;
    if (value.getAsInteger(0, num) || (num < 0)) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue() << "\n";
      return false;
    }
    config_.options().setNumSpareDTags(num);
  }

  //===--------------------------------------------------------------------===//
  // Output
  //===--------------------------------------------------------------------===//

  // Setup the codegen type.
  if (args.hasArg(kOpt_Shared) || args.hasArg(kOpt_PIE)) {
    // -shared, -pie
    config_.setCodeGenType(mcld::LinkerConfig::DynObj);
  } else if (args.hasArg(kOpt_Relocatable)) {
    // -r
    config_.setCodeGenType(mcld::LinkerConfig::Object);
  } else if (llvm::opt::Arg* arg = args.getLastArg(kOpt_OutputFormat)) {
    // --oformat=value
    llvm::StringRef value = arg->getValue();
    if (value.equals("binary")) {
      config_.setCodeGenType(mcld::LinkerConfig::Binary);
    }
  } else {
    config_.setCodeGenType(mcld::LinkerConfig::Exec);
  }

  // Setup the output filename.
  llvm::StringRef output_name;
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Output)) {
    output_name = arg->getValue();
  }
  if (!ConfigureOutputName(output_name, module_, config_)) {
    mcld::unreachable(mcld::diag::unrecognized_output_file) << module_.name();
    return false;
  } else {
    if (!args.hasArg(kOpt_SOName)) {
      config_.options().setSOName(module_.name());
    }
  }

  // --format=value
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_InputFormat)) {
    llvm::StringRef value = arg->getValue();
    if (value.equals("binary")) {
      config_.options().setBinaryInput();
    }
  }

  // Setup debug info stripping.
  config_.options().setStripDebug(args.hasArg(kOpt_StripDebug) ||
                                  args.hasArg(kOpt_StripAll));

  // Setup symbol stripping mode.
  if (args.hasArg(kOpt_StripAll)) {
    config_.options().setStripSymbols(
        mcld::GeneralOptions::StripSymbolMode::StripAllSymbols);
  } else if (args.hasArg(kOpt_DiscardAll)) {
    config_.options().setStripSymbols(
        mcld::GeneralOptions::StripSymbolMode::StripLocals);
  } else if (args.hasArg(kOpt_DiscardLocals)) {
    config_.options().setStripSymbols(
        mcld::GeneralOptions::StripSymbolMode::StripTemporaries);
  } else {
    config_.options().setStripSymbols(
        mcld::GeneralOptions::StripSymbolMode::KeepAllSymbols);
  }

  // --eh-frame-hdr
  config_.options().setEhFrameHdr(args.hasArg(kOpt_EHFrameHdr));

  // -pie
  config_.options().setPIE(args.hasArg(kOpt_PIE));

  // --nmagic
  config_.options().setNMagic(args.hasArg(kOpt_NMagic));

  // --omagic
  config_.options().setOMagic(args.hasArg(kOpt_OMagic));

  // --hash-style=style
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_HashStyle)) {
    mcld::GeneralOptions::HashStyle style =
        llvm::StringSwitch<mcld::GeneralOptions::HashStyle>(arg->getValue())
            .Case("sysv", mcld::GeneralOptions::HashStyle::SystemV)
            .Case("gnu", mcld::GeneralOptions::HashStyle::GNU)
            .Case("both", mcld::GeneralOptions::HashStyle::Both)
            .Default(mcld::GeneralOptions::HashStyle::Unknown);
    if (style != mcld::GeneralOptions::HashStyle::Unknown) {
      config_.options().setHashStyle(style);
    }
  }

  // --[no]-export-dynamic
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_ExportDynamic,
                                              kOpt_NoExportDynamic)) {
    if (arg->getOption().matches(kOpt_ExportDynamic)) {
      config_.options().setExportDynamic(true);
    } else {
      config_.options().setExportDynamic(false);
    }
  }

  // --no-warn-mismatch
  config_.options().setWarnMismatch(!args.hasArg(kOpt_NoWarnMismatch));

  // --exclude-libs
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_ExcludeLibs)) {
    llvm::StringRef value = arg->getValue();
    do {
      std::pair<llvm::StringRef, llvm::StringRef> res = value.split(',');
      config_.options().excludeLIBS().insert(res.first.str());
      value = res.second;
    } while (!value.empty());
  }

  //===--------------------------------------------------------------------===//
  // Search Path
  //===--------------------------------------------------------------------===//

  // --sysroot
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Sysroot)) {
    mcld::sys::fs::Path path(arg->getValue());
    if (mcld::sys::fs::exists(path) && mcld::sys::fs::is_directory(path)) {
      script_.setSysroot(path);
    }
  }

  // -L searchdir
  for (llvm::opt::Arg* arg : args.filtered(kOpt_LibraryPath)) {
    if (!script_.directories().insert(arg->getValue()))
      mcld::warning(mcld::diag::warn_cannot_open_search_dir) << arg->getValue();
  }

  // -nostdlib
  config_.options().setNoStdlib(args.hasArg(kOpt_NoStdlib));

  // -rpath=path
  for (llvm::opt::Arg* arg : args.filtered(kOpt_RPath)) {
    config_.options().getRpathList().push_back(arg->getValue());
  }

  //===--------------------------------------------------------------------===//
  // Symbol
  //===--------------------------------------------------------------------===//

  // -d/-dc/-dp
  config_.options().setDefineCommon(args.hasArg(kOpt_DefineCommon));

  // -u symbol
  for (llvm::opt::Arg* arg : args.filtered(kOpt_Undefined)) {
    config_.options().getUndefSymList().push_back(arg->getValue());
  }

  //===--------------------------------------------------------------------===//
  // Script
  //===--------------------------------------------------------------------===//

  // --wrap=symbol
  for (llvm::opt::Arg* arg : args.filtered(kOpt_Wrap)) {
    bool exist = false;
    const char* symbol = arg->getValue();
    // symbol -> __wrap_symbol
    mcld::StringEntry<llvm::StringRef>* to_wrap =
        script_.renameMap().insert(symbol, exist);

    std::string to_wrap_str;
    to_wrap_str.append("__wrap_")
               .append(symbol);
    to_wrap->setValue(to_wrap_str);

    if (exist)
      mcld::warning(mcld::diag::rewrap) << symbol << to_wrap_str;

    // __real_symbol -> symbol
    std::string from_real_str;
    to_wrap_str.append("__real_")
               .append(symbol);
    mcld::StringEntry<llvm::StringRef>* from_real =
        script_.renameMap().insert(from_real_str, exist);
    from_real->setValue(symbol);

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

  // --portalbe=symbol
  for (llvm::opt::Arg* arg : args.filtered(kOpt_Portable)) {
    bool exist = false;
    const char* symbol = arg->getValue();
    // symbol -> symbol_portable
    mcld::StringEntry<llvm::StringRef>* to_wrap =
        script_.renameMap().insert(symbol, exist);

    std::string to_wrap_str;
    to_wrap_str.append(symbol)
               .append("_portable");
    to_wrap->setValue(to_wrap_str);

    if (exist)
      mcld::warning(mcld::diag::rewrap) << symbol << to_wrap_str;

    // __real_symbol -> symbol
    std::string from_real_str;
    to_wrap_str.append("__real_")
               .append(symbol);
    mcld::StringEntry<llvm::StringRef>* from_real =
        script_.renameMap().insert(from_real_str, exist);
    from_real->setValue(symbol);

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

  // --section-start=section=addr
  for (llvm::opt::Arg* arg : args.filtered(kOpt_SectionStart)) {
    llvm::StringRef value = arg->getValue();
    const size_t pos = value.find('=');
    uint64_t addr = 0;
    value.substr(pos + 1).getAsInteger(0, addr);
    bool exist = false;
    mcld::StringEntry<uint64_t>* mapping =
        script_.addressMap().insert(value.substr(0, pos), exist);
    mapping->setValue(addr);
  }

  // -Tbss=value
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Tbss)) {
    llvm::StringRef value = arg->getValue();
    uint64_t addr = 0;
    if (value.getAsInteger(0, addr)) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue() << "\n";
      return false;
    }
    bool exist = false;
    mcld::StringEntry<uint64_t>* mapping =
        script_.addressMap().insert(".bss", exist);
    mapping->setValue(addr);
  }

  // -Tdata=value
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Tdata)) {
    llvm::StringRef value = arg->getValue();
    uint64_t addr = 0;
    if (value.getAsInteger(0, addr)) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue() << "\n";
      return false;
    }
    bool exist = false;
    mcld::StringEntry<uint64_t>* mapping =
        script_.addressMap().insert(".data", exist);
    mapping->setValue(addr);
  }

  // -Ttext=value
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_Ttext)) {
    llvm::StringRef value = arg->getValue();
    uint64_t addr = 0;
    if (value.getAsInteger(0, addr)) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue() << "\n";
      return false;
    }
    bool exist = false;
    mcld::StringEntry<uint64_t>* mapping =
        script_.addressMap().insert(".text", exist);
    mapping->setValue(addr);
  }

  //===--------------------------------------------------------------------===//
  // Optimization
  //===--------------------------------------------------------------------===//

  // --[no-]gc-sections
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_GCSections,
                                              kOpt_NoGCSections)) {
    if (arg->getOption().matches(kOpt_GCSections)) {
      config_.options().setGCSections(true);
    } else {
      config_.options().setGCSections(false);
    }
  }

  // --[no-]print-gc-sections
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_PrintGCSections,
                                              kOpt_NoPrintGCSections)) {
    if (arg->getOption().matches(kOpt_PrintGCSections)) {
      config_.options().setPrintGCSections(true);
    } else {
      config_.options().setPrintGCSections(false);
    }
  }

  // --[no-]ld-generated-unwind-info
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_LDGeneratedUnwindInfo,
                                              kOpt_NoLDGeneratedUnwindInfo)) {
    if (arg->getOption().matches(kOpt_LDGeneratedUnwindInfo)) {
      config_.options().setGenUnwindInfo(true);
    } else {
      config_.options().setGenUnwindInfo(false);
    }
  }

  // --icf=mode
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_ICF)) {
    mcld::GeneralOptions::ICF mode =
        llvm::StringSwitch<mcld::GeneralOptions::ICF>(arg->getValue())
            .Case("none", mcld::GeneralOptions::ICF::None)
            .Case("all", mcld::GeneralOptions::ICF::All)
            .Case("safe", mcld::GeneralOptions::ICF::Safe)
            .Default(mcld::GeneralOptions::ICF::Unknown);
    if (mode == mcld::GeneralOptions::ICF::Unknown) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue() << "\n";
      return false;
    }
    config_.options().setICFMode(mode);
  }

  // --icf-iterations
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_ICFIters)) {
    llvm::StringRef value = arg->getValue();
    int num;
    if (value.getAsInteger(0, num) || (num < 0)) {
      mcld::errs() << "Invalid value for" << arg->getOption().getPrefixedName()
                   << ": " << arg->getValue() << "\n";
      return false;
    }
    config_.options().setICFIterations(num);
  }

  // --[no-]print-icf-sections
  if (llvm::opt::Arg* arg = args.getLastArg(kOpt_PrintICFSections,
                                              kOpt_NoPrintICFSections)) {
    if (arg->getOption().matches(kOpt_PrintICFSections)) {
      config_.options().setPrintICFSections(true);
    } else {
      config_.options().setPrintICFSections(false);
    }
  }

  //===--------------------------------------------------------------------===//
  // Positional
  //===--------------------------------------------------------------------===//

  // # of regular objects, script, and namespec.
  size_t input_num = 0;
  typedef std::unique_ptr<mcld::InputAction> Action;

  std::vector<Action> actions;
  Action action;
  actions.reserve(32);

  for (llvm::opt::Arg* arg : args) {
    const unsigned index = arg->getIndex();

    switch (arg->getOption().getID()) {
      // -T script
      case kOpt_Script: {
        const char* value = arg->getValue();
        config_.options().getScriptList().push_back(value);

        // FIXME: Let index of script file be 0.
        action.reset(new mcld::ScriptAction(
            0x0, value, mcld::ScriptFile::LDScript, script_.directories()));
        actions.push_back(std::move(action));

        action.reset(new mcld::ContextAction(0x0));
        actions.push_back(std::move(action));

        action.reset(new mcld::MemoryAreaAction(0x0,
                                                mcld::FileHandle::ReadOnly));
        actions.push_back(std::move(action));

        ++input_num;
        break;
      }

      // --defsym=symbol=expr
      case kOpt_DefSym: {
        std::string expr;
        expr.append(arg->getValue())
            .append(";");
        script_.defsyms().push_back(std::move(expr));
        action.reset(new mcld::DefSymAction(index, script_.defsyms().back()));
        actions.push_back(std::move(action));
        break;
      }

      // -l namespec
      case kOpt_Namespec: {
        action.reset(new mcld::NamespecAction(
            index, arg->getValue(), script_.directories()));
        actions.push_back(std::move(action));

        action.reset(new mcld::ContextAction(index));
        actions.push_back(std::move(action));

        action.reset(new mcld::MemoryAreaAction(index,
                                                mcld::FileHandle::ReadOnly));
        actions.push_back(std::move(action));

        ++input_num;
        break;
      }

      // --whole-archive
      case kOpt_WholeArchive: {
        action.reset(new mcld::WholeArchiveAction(index));
        actions.push_back(std::move(action));
        break;
      }

      // --no-whole-archive
      case kOpt_NoWholeArchive: {
        action.reset(new mcld::NoWholeArchiveAction(index));
        actions.push_back(std::move(action));
        break;
      }

      // --as-needed
      case kOpt_AsNeeded: {
        action.reset(new mcld::AsNeededAction(index));
        actions.push_back(std::move(action));
        break;
      }

      // --no-as-needed
      case kOpt_NoAsNeeded: {
        action.reset(new mcld::NoAsNeededAction(index));
        actions.push_back(std::move(action));
        break;
      }

      // --add-needed
      // FIXME: This is deprecated. Should be --copy-dt-needed-entries.
      case kOpt_AddNeeded:
      case kOpt_CopyDTNeeded: {
        action.reset(new mcld::AddNeededAction(index));
        actions.push_back(std::move(action));
        break;
      }

      // --no-add-needed
      // FIXME: This is deprecated. Should be --no-copy-dt-needed-entries.
      case kOpt_NoAddNeeded:
      case kOpt_NoCopyDTNeeded: {
        action.reset(new mcld::AddNeededAction(index));
        actions.push_back(std::move(action));
        break;
      }

      // -Bdynamic
      case kOpt_Bdynamic: {
        action.reset(new mcld::BDynamicAction(index));
        actions.push_back(std::move(action));
        break;
      }

      // -Bstatic
      case kOpt_Bstatic: {
        action.reset(new mcld::BStaticAction(index));
        actions.push_back(std::move(action));
        break;
      }

      // --start-group
      case kOpt_StartGroup: {
        action.reset(new mcld::StartGroupAction(index));
        actions.push_back(std::move(action));
        break;
      }

      // --end-group
      case kOpt_EndGroup: {
        action.reset(new mcld::EndGroupAction(index));
        actions.push_back(std::move(action));
        break;
      }

      case kOpt_INPUT: {
        action.reset(new mcld::InputFileAction(index, arg->getValue()));
        actions.push_back(std::move(action));

        action.reset(new mcld::ContextAction(index));
        actions.push_back(std::move(action));

        action.reset(new mcld::MemoryAreaAction(index,
                                                mcld::FileHandle::ReadOnly));
        actions.push_back(std::move(action));

        ++input_num;
        break;
      }

      default:
        break;
    }
  }

  if (input_num == 0) {
    mcld::fatal(mcld::diag::err_no_inputs);
    return false;
  }

  // Stable sort
  std::stable_sort(actions.begin(),
                   actions.end(),
                   [] (const Action& X, const Action& Y) {
                     return X->position() < Y->position();
                   });

  if (!InitializeInputs(ir_builder_, actions)) {
    mcld::errs() << "Failed to initialize input tree!\n";
    return false;
  }


  //===--------------------------------------------------------------------===//
  // Unknown
  //===--------------------------------------------------------------------===//
  std::vector<std::string> unknown_args = args.getAllArgValues(kOpt_UNKNOWN);
  for (std::string arg : unknown_args)
    mcld::warning(mcld::diag::warn_unsupported_option) << arg;

  return true;
}

std::unique_ptr<Driver> Driver::Create(llvm::ArrayRef<const char*> argv) {
  // Parse command line options.
  OptTable opt_table;
  unsigned missing_arg_idx;
  unsigned missing_arg_count;
  llvm::opt::InputArgList args =
      opt_table.ParseArgs(argv.slice(1), missing_arg_idx, missing_arg_count);
  if (missing_arg_count > 0) {
    mcld::errs() << "Argument to '" << args.getArgString(missing_arg_idx)
                 << "' is missing (expected " << missing_arg_count
                 << ((missing_arg_count > 1) ? " values" : " value") << ")\n";
    return nullptr;
  }

  std::unique_ptr<Driver> result(new Driver(argv[0]));

  // Return quickly if -help is specified.
  if (args.hasArg(kOpt_Help)) {
    opt_table.PrintHelp(mcld::outs(), argv[0], "MCLinker",
                        /* FlagsToInclude */0, /* FlagsToExclude */0);
    return nullptr;
  }

  // Print version information if requested.
  if (args.hasArg(kOpt_Version)) {
    mcld::outs() << result->config_.options().getVersionString() << "\n";
  }

  // Setup instance from arguments.
  if (!result->TranslateArguments(args)) {
    return nullptr;
  }

  return result;
}

bool Driver::Run() {
  mcld::Initialize();

  if (!linker_.emulate(script_, config_)) {
    mcld::errs() << "Failed to emulate target!\n";
    return false;
  }

  if (!linker_.link(module_, ir_builder_)) {
    mcld::errs() << "Failed to link objects!\n";
    return false;
  }

  if (!linker_.emit(module_, module_.name())) {
    mcld::errs() << "Failed to emit output!\n";
    return false;
  }

  mcld::Finalize();
  return true;
}

}  // anonymous namespace

int main(int argc, char** argv) {
  std::unique_ptr<Driver> driver =
      Driver::Create(llvm::makeArrayRef(argv, argc));

  if ((driver == nullptr) || !driver->Run()) {
    return EXIT_FAILURE;
  } else {
    return EXIT_SUCCESS;
  }
}