1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072 |
- //===- 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;
- }
- }
|