Index: lld/include/lld/Driver/Driver.h =================================================================== --- lld/include/lld/Driver/Driver.h +++ lld/include/lld/Driver/Driver.h @@ -17,6 +17,8 @@ namespace coff { bool link(llvm::ArrayRef Args, llvm::raw_ostream &Diag = llvm::errs()); +bool ldshim(llvm::ArrayRef Args, + llvm::raw_ostream &Diag = llvm::errs()); } namespace elf { Index: lld/lib/CMakeLists.txt =================================================================== --- lld/lib/CMakeLists.txt +++ lld/lib/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(Core) add_subdirectory(Driver) add_subdirectory(ReaderWriter) +add_subdirectory(Shim) Index: lld/lib/Shim/CMakeLists.txt =================================================================== --- /dev/null +++ lld/lib/Shim/CMakeLists.txt @@ -0,0 +1,20 @@ +set(LLVM_TARGET_DEFINITIONS COFFLdOptions.td) +tablegen(LLVM COFFLdOptions.inc -gen-opt-parser-defs) +add_public_tablegen_target(ShimOptionsTableGen) + +if(NOT LLD_BUILT_STANDALONE) + set(tablegen_deps intrinsics_gen) +endif() + +add_lld_library(lldCOFFShim + COFFLdShim.cpp + + LINK_LIBS + lldConfig + lldCore + ${LLVM_PTHREAD_LIB} + + DEPENDS + ShimOptionsTableGen + ${tablegen_deps} + ) Index: lld/lib/Shim/COFFLdOptions.td =================================================================== --- /dev/null +++ lld/lib/Shim/COFFLdOptions.td @@ -0,0 +1,32 @@ +include "llvm/Option/OptParser.td" + +class F: Flag<["--", "-"], name>; +class J: Joined<["--", "-"], name>; +class S: Separate<["--", "-"], name>; + +def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"">, + HelpText<"Add a directory to the library search path">; +def entry: S<"entry">, MetaVarName<"">, + HelpText<"Name of entry point symbol">; +def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; +def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"">, + HelpText<"Path to file to write output">; +def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"">, + HelpText<"Root name of library to use">; +def shared: F<"shared">, HelpText<"Build a shared object">; +def subs : Separate<["--"], "subsystem">, HelpText<"Specify subsystem">; +def stack: Flag<["--"], "stack">, Alias; +def outlib : Separate<["--"], "out-implib">, HelpText<"Import library name">; + +// Currently stubs to avoid errors +def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">; +def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">; +def major_image_version : Separate<["--"], "major-image-version">; +def minor_image_version : Separate<["--"], "minor-image-version">; +def O: Joined<["-"], "O">, HelpText<"Optimize output file size">; +def v: Flag<["-"], "v">, HelpText<"Display the version number">; +def verbose: F<"verbose">, HelpText<"Verbose mode">; +def version: F<"version">, HelpText<"Display the version number and exit">; + +// Alias +def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias; Index: lld/lib/Shim/COFFLdShim.cpp =================================================================== --- /dev/null +++ lld/lib/Shim/COFFLdShim.cpp @@ -0,0 +1,228 @@ +//===- lib/Driver/COFFLdShim.cpp ------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// ld shim around the COFF link frontend. +/// +//===----------------------------------------------------------------------===// + +#include "lld/Driver/Driver.h" +#include "lld/Driver/Driver.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.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/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/StringSaver.h" + +using namespace lld; +using namespace llvm; +using namespace llvm::opt; +using namespace llvm::sys; + +namespace { + +// Create enum with OPT_xxx values for each option in COFFLdOptions.td +enum { + OPT_INVALID = 0, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELP, META) \ + OPT_##ID, +#include "COFFLdOptions.inc" +#undef OPTION +}; + +// Create prefix string literals used in COFFLdOptions.td +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "COFFLdOptions.inc" +#undef PREFIX + +// Create table mapping all options defined in COFFLdOptions.td +static const llvm::opt::OptTable::Info infoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) \ + {PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS}, +#include "COFFLdOptions.inc" +#undef OPTION +}; + +// Create OptTable class for parsing actual command line arguments +class COFFLdOptTable : public llvm::opt::OptTable { +public: + COFFLdOptTable() : OptTable(infoTable) {} +}; + +} // end anonymous namespace + +namespace lld { +namespace coff { + +static SmallVector LinkArgs; +static std::vector SearchPaths; +static llvm::StringRef Sysroot; + +static void error(const Twine &Msg) { + llvm::errs() << Msg << "\n"; + exit(1); +} + +// Find a file by concatenating given paths. If a resulting path +// starts with "=", the character is replaced with a --sysroot value. +static Optional findFile(StringRef Path1, const Twine &Path2) { + SmallString<128> S; + if (Path1.startswith("=")) + path::append(S, Sysroot, Path1.substr(1), Path2); + else + path::append(S, Path1, Path2); + if (fs::exists(S)) { + return S.str().str(); + } + return None; +} + +Optional findFromSearchPaths(StringRef Path) { + for (StringRef Dir : SearchPaths) + if (Optional S = findFile(Dir, Path)) + return S; + return None; +} + +// This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from +// search paths. +Optional searchLibrary(StringRef Name, bool IgnoreShared = false) { + if (Name.startswith(":")) + return findFromSearchPaths(Name.substr(1)); + for (StringRef Dir : SearchPaths) { + if (!IgnoreShared) + if (Optional S = findFile(Dir, "lib" + Name + ".dll.a")) + return S; + if (Optional S = findFile(Dir, "lib" + Name + ".a")) + return S; + } + return None; +} + +void addFile(StringRef Path) { + std::string *P = new std::string(Path); + LinkArgs.push_back(P->c_str()); +} + +// Add a given library by searching it from input search paths. +void addLibrary(StringRef Name) { + if (Optional Path = searchLibrary(Name)) { + addFile(*Path); + } else + error("unable to find library -l" + Name); +} + +void createFiles(opt::InputArgList &Args) { + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { + case OPT_l: + addLibrary(Arg->getValue()); + break; + case OPT_INPUT: + addFile(Arg->getValue()); + break; + } + } + // Let the Link Driver handle this error? + //if (Files.empty() && ErrorCount == 0) + // error("no input files"); +} + +static StringRef getString(opt::InputArgList &Args, unsigned Key, + StringRef Default = "") { + if (auto *Arg = Args.getLastArg(Key)) + return Arg->getValue(); + return Default; +} + +static std::vector getArgs(opt::InputArgList &Args, int Id) { + std::vector V; + for (auto *Arg : Args.filtered(Id)) + V.push_back(Arg->getValue()); + return V; +} + +static bool directMap(opt::InputArgList &Args, unsigned Key, StringRef outArg) { + StringRef S = getString(Args, Key); + if(S.size()) { + std::string *a = new std::string(Twine("-" + outArg+ ":" + S).str()); + LinkArgs.push_back(a->c_str()); + return true; + } + return false; +} + +static bool directMapValue(opt::InputArgList &Args, unsigned Key, StringRef cmpArg, + StringRef outArg, StringRef outValueArg) { + StringRef S = getString(Args, Key); + if(S == cmpArg) { + std::string *a = new std::string(Twine("-" + outArg+ ":" + outValueArg).str()); + LinkArgs.push_back(a->c_str()); + return true; + } + return false; +} + +bool ldshim(ArrayRef Args, raw_ostream &Diag) { + + // Parse command line options using COFFLdOptions.td + COFFLdOptTable table; + unsigned missingIndex; + unsigned missingCount; + llvm::opt::InputArgList parsedArgs = + table.ParseArgs(Args.slice(1), missingIndex, missingCount); + if (missingCount) { + llvm::outs() << "error: missing arg value for '" + << parsedArgs.getArgString(missingIndex) << "' expected " + << missingCount << " argument(s).\n"; + return false; + } + + for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) { + llvm::outs() << "warning: ignoring unknown argument: " + << unknownArg->getAsString(parsedArgs) << "\n"; + } + + // Add Arg0 for lld-link + LinkArgs.push_back(Args[0]); + + // We could possibly use StringSwitch within a function for MACHINE + directMapValue(parsedArgs, OPT_m, "i386pe", "MACHINE", "X86"); + directMapValue(parsedArgs, OPT_m, "i386pe", "MACHINE", "X64"); + directMapValue(parsedArgs, OPT_m, "thumb2pe", "MACHINE", "ARM"); + + directMap(parsedArgs, OPT_o, "OUT"); + directMap(parsedArgs, OPT_entry, "ENTRY"); + directMap(parsedArgs, OPT_subs, "SUBSYSTEM"); + directMap(parsedArgs, OPT_shared, "DLL"); + directMap(parsedArgs, OPT_outlib, "IMPLIB"); + directMap(parsedArgs, OPT_stack, "STACK"); + + SearchPaths = getArgs(parsedArgs, OPT_L); + createFiles(parsedArgs); + + // handle __image_base__ + LinkArgs.push_back("/alternatename:__image_base__=__ImageBase"); + return coff::link(LinkArgs); +} + +} // namespace coff +} // namespace lld Index: lld/tools/lld/CMakeLists.txt =================================================================== --- lld/tools/lld/CMakeLists.txt +++ lld/tools/lld/CMakeLists.txt @@ -10,6 +10,7 @@ lldDriver lldCOFF lldELF + lldCOFFShim ) install(TARGETS lld Index: lld/tools/lld/lld.cpp =================================================================== --- lld/tools/lld/lld.cpp +++ lld/tools/lld/lld.cpp @@ -49,6 +49,24 @@ .Default(Invalid); } +static bool isPETarget(const std::vector &V) { + for (auto It = V.begin(); It != V.end(); It++) { + if (*It == StringRef("-m")) { + It++; + if (It == V.end()) + return false; + if (*It == StringRef("i386pe")) + return true; + if (*It == StringRef("i386pep")) + return true; + if (*It == StringRef("thumb2pe")) + return true; + return false; + } + } + return false; +} + static Flavor parseProgname(StringRef Progname) { #if __APPLE__ // Use Darwin driver for "ld" on Darwin. @@ -99,9 +117,13 @@ llvm_shutdown_obj Shutdown; std::vector Args(Argv, Argv + Argc); + switch (parseFlavor(Args)) { case Gnu: - return !elf::link(Args, true); + if (isPETarget(Args)) + return !coff::ldshim(Args); + else + return !elf::link(Args, true); case WinLink: return !coff::link(Args); case Darwin: