1 //===- MinGW/Driver.cpp ---------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // MinGW is a GNU development environment for Windows. It consists of GNU 10 // tools such as GCC and GNU ld. Unlike Cygwin, there's no POSIX-compatible 11 // layer, as it aims to be a native development toolchain. 12 // 13 // lld/MinGW is a drop-in replacement for GNU ld/MinGW. 14 // 15 // Being a native development tool, a MinGW linker is not very different from 16 // Microsoft link.exe, so a MinGW linker can be implemented as a thin wrapper 17 // for lld/COFF. This driver takes Unix-ish command line options, translates 18 // them to Windows-ish ones, and then passes them to lld/COFF. 19 // 20 // When this driver calls the lld/COFF driver, it passes a hidden option 21 // "-lldmingw" along with other user-supplied options, to run the lld/COFF 22 // linker in "MinGW mode". 23 // 24 // There are subtle differences between MS link.exe and GNU ld/MinGW, and GNU 25 // ld/MinGW implements a few GNU-specific features. Such features are directly 26 // implemented in lld/COFF and enabled only when the linker is running in MinGW 27 // mode. 28 // 29 //===----------------------------------------------------------------------===// 30 31 #include "lld/Common/Driver.h" 32 #include "lld/Common/ErrorHandler.h" 33 #include "llvm/ADT/ArrayRef.h" 34 #include "llvm/ADT/Optional.h" 35 #include "llvm/ADT/StringExtras.h" 36 #include "llvm/ADT/StringRef.h" 37 #include "llvm/Option/Arg.h" 38 #include "llvm/Option/ArgList.h" 39 #include "llvm/Option/Option.h" 40 #include "llvm/Support/CommandLine.h" 41 #include "llvm/Support/FileSystem.h" 42 #include "llvm/Support/Path.h" 43 44 #if !defined(_MSC_VER) && !defined(__MINGW32__) 45 #include <unistd.h> 46 #endif 47 48 using namespace lld; 49 using namespace llvm; 50 51 // Create OptTable 52 enum { 53 OPT_INVALID = 0, 54 #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, 55 #include "Options.inc" 56 #undef OPTION 57 }; 58 59 // Create prefix string literals used in Options.td 60 #define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE; 61 #include "Options.inc" 62 #undef PREFIX 63 64 // Create table mapping all options defined in Options.td 65 static const opt::OptTable::Info InfoTable[] = { 66 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ 67 {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ 68 X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, 69 #include "Options.inc" 70 #undef OPTION 71 }; 72 73 namespace { 74 class MinGWOptTable : public opt::OptTable { 75 public: 76 MinGWOptTable() : OptTable(InfoTable, false) {} 77 opt::InputArgList parse(ArrayRef<const char *> Argv); 78 }; 79 } // namespace 80 81 opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> Argv) { 82 unsigned MissingIndex; 83 unsigned MissingCount; 84 85 SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); 86 opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); 87 88 if (MissingCount) 89 fatal(StringRef(Args.getArgString(MissingIndex)) + ": missing argument"); 90 for (auto *Arg : Args.filtered(OPT_UNKNOWN)) 91 fatal("unknown argument: " + Arg->getSpelling()); 92 if (!Args.hasArg(OPT_INPUT) && !Args.hasArg(OPT_l)) 93 fatal("no input files"); 94 return Args; 95 } 96 97 // Find a file by concatenating given paths. 98 static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) { 99 SmallString<128> S; 100 sys::path::append(S, Path1, Path2); 101 if (sys::fs::exists(S)) 102 return S.str().str(); 103 return None; 104 } 105 106 // This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths. 107 static std::string 108 searchLibrary(StringRef Name, ArrayRef<StringRef> SearchPaths, bool BStatic) { 109 if (Name.startswith(":")) { 110 for (StringRef Dir : SearchPaths) 111 if (Optional<std::string> S = findFile(Dir, Name.substr(1))) 112 return *S; 113 fatal("unable to find library -l" + Name); 114 } 115 116 for (StringRef Dir : SearchPaths) { 117 if (!BStatic) 118 if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".dll.a")) 119 return *S; 120 if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) 121 return *S; 122 } 123 fatal("unable to find library -l" + Name); 124 } 125 126 // Convert Unix-ish command line arguments to Windows-ish ones and 127 // then call coff::link. 128 bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) { 129 MinGWOptTable Parser; 130 opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); 131 132 std::vector<std::string> LinkArgs; 133 auto Add = [&](const Twine &S) { LinkArgs.push_back(S.str()); }; 134 135 Add("lld-link"); 136 Add("-lldmingw"); 137 138 if (auto *A = Args.getLastArg(OPT_entry)) { 139 StringRef S = A->getValue(); 140 if (Args.getLastArgValue(OPT_m) == "i386pe" && S.startswith("_")) 141 Add("-entry:" + S.substr(1)); 142 else 143 Add("-entry:" + S); 144 } 145 146 if (auto *A = Args.getLastArg(OPT_subs)) 147 Add("-subsystem:" + StringRef(A->getValue())); 148 if (auto *A = Args.getLastArg(OPT_out_implib)) 149 Add("-implib:" + StringRef(A->getValue())); 150 if (auto *A = Args.getLastArg(OPT_stack)) 151 Add("-stack:" + StringRef(A->getValue())); 152 if (auto *A = Args.getLastArg(OPT_output_def)) 153 Add("-output-def:" + StringRef(A->getValue())); 154 if (auto *A = Args.getLastArg(OPT_image_base)) 155 Add("-base:" + StringRef(A->getValue())); 156 if (auto *A = Args.getLastArg(OPT_map)) 157 Add("-lldmap:" + StringRef(A->getValue())); 158 159 if (auto *A = Args.getLastArg(OPT_o)) 160 Add("-out:" + StringRef(A->getValue())); 161 else if (Args.hasArg(OPT_shared)) 162 Add("-out:a.dll"); 163 else 164 Add("-out:a.exe"); 165 166 if (auto *A = Args.getLastArg(OPT_pdb)) { 167 Add("-debug"); 168 Add("-pdb:" + StringRef(A->getValue())); 169 } else if (Args.hasArg(OPT_strip_debug)) { 170 Add("-debug:symtab"); 171 } else if (!Args.hasArg(OPT_strip_all)) { 172 Add("-debug:dwarf"); 173 } 174 175 if (Args.hasArg(OPT_shared)) 176 Add("-dll"); 177 if (Args.hasArg(OPT_verbose)) 178 Add("-verbose"); 179 if (Args.hasArg(OPT_exclude_all_symbols)) 180 Add("-exclude-all-symbols"); 181 if (Args.hasArg(OPT_export_all_symbols)) 182 Add("-export-all-symbols"); 183 if (Args.hasArg(OPT_large_address_aware)) 184 Add("-largeaddressaware"); 185 if (Args.hasArg(OPT_kill_at)) 186 Add("-kill-at"); 187 if (Args.hasArg(OPT_appcontainer)) 188 Add("-appcontainer"); 189 190 if (Args.getLastArgValue(OPT_m) != "thumb2pe" && 191 Args.getLastArgValue(OPT_m) != "arm64pe" && !Args.hasArg(OPT_dynamicbase)) 192 Add("-dynamicbase:no"); 193 194 if (Args.hasFlag(OPT_no_insert_timestamp, OPT_insert_timestamp, false)) 195 Add("-timestamp:0"); 196 197 if (Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false)) 198 Add("-opt:ref"); 199 else 200 Add("-opt:noref"); 201 202 if (auto *A = Args.getLastArg(OPT_icf)) { 203 StringRef S = A->getValue(); 204 if (S == "all") 205 Add("-opt:icf"); 206 else if (S == "safe" || S == "none") 207 Add("-opt:noicf"); 208 else 209 fatal("unknown parameter: --icf=" + S); 210 } else { 211 Add("-opt:noicf"); 212 } 213 214 if (auto *A = Args.getLastArg(OPT_m)) { 215 StringRef S = A->getValue(); 216 if (S == "i386pe") 217 Add("-machine:x86"); 218 else if (S == "i386pep") 219 Add("-machine:x64"); 220 else if (S == "thumb2pe") 221 Add("-machine:arm"); 222 else if (S == "arm64pe") 223 Add("-machine:arm64"); 224 else 225 fatal("unknown parameter: -m" + S); 226 } 227 228 for (auto *A : Args.filtered(OPT_mllvm)) 229 Add("-mllvm:" + StringRef(A->getValue())); 230 231 for (auto *A : Args.filtered(OPT_Xlink)) 232 Add(A->getValue()); 233 234 if (Args.getLastArgValue(OPT_m) == "i386pe") 235 Add("-alternatename:__image_base__=___ImageBase"); 236 else 237 Add("-alternatename:__image_base__=__ImageBase"); 238 239 for (auto *A : Args.filtered(OPT_require_defined)) 240 Add("-include:" + StringRef(A->getValue())); 241 242 std::vector<StringRef> SearchPaths; 243 for (auto *A : Args.filtered(OPT_L)) { 244 SearchPaths.push_back(A->getValue()); 245 Add("-libpath:" + StringRef(A->getValue())); 246 } 247 248 StringRef Prefix = ""; 249 bool Static = false; 250 for (auto *A : Args) { 251 switch (A->getOption().getUnaliasedOption().getID()) { 252 case OPT_INPUT: 253 if (StringRef(A->getValue()).endswith_lower(".def")) 254 Add("-def:" + StringRef(A->getValue())); 255 else 256 Add(Prefix + StringRef(A->getValue())); 257 break; 258 case OPT_l: 259 Add(Prefix + searchLibrary(A->getValue(), SearchPaths, Static)); 260 break; 261 case OPT_whole_archive: 262 Prefix = "-wholearchive:"; 263 break; 264 case OPT_no_whole_archive: 265 Prefix = ""; 266 break; 267 case OPT_Bstatic: 268 Static = true; 269 break; 270 case OPT_Bdynamic: 271 Static = false; 272 break; 273 } 274 } 275 276 if (Args.hasArg(OPT_verbose) || Args.hasArg(OPT__HASH_HASH_HASH)) 277 outs() << llvm::join(LinkArgs, " ") << "\n"; 278 279 if (Args.hasArg(OPT__HASH_HASH_HASH)) 280 return true; 281 282 // Repack vector of strings to vector of const char pointers for coff::link. 283 std::vector<const char *> Vec; 284 for (const std::string &S : LinkArgs) 285 Vec.push_back(S.c_str()); 286 return coff::link(Vec, true); 287 } 288