Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 1 | //===- MinGW/Driver.cpp ---------------------------------------------------===// |
| 2 | // |
| 3 | // The LLVM Linker |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | /// |
| 10 | /// GNU ld style linker driver for COFF currently supporting mingw-w64. |
| 11 | /// |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
Rui Ueyama | 6cb7141 | 2017-10-02 22:05:46 | [diff] [blame] | 14 | #include "lld/Common/Driver.h" |
Rui Ueyama | 338c4b2 | 2017-12-12 20:34:38 | [diff] [blame] | 15 | #include "lld/Common/ErrorHandler.h" |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 16 | #include "llvm/ADT/ArrayRef.h" |
| 17 | #include "llvm/ADT/Optional.h" |
Martin Storsjo | a79762a | 2017-09-11 20:43:39 | [diff] [blame] | 18 | #include "llvm/ADT/StringExtras.h" |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 19 | #include "llvm/ADT/StringRef.h" |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 20 | #include "llvm/Option/Arg.h" |
| 21 | #include "llvm/Option/ArgList.h" |
| 22 | #include "llvm/Option/Option.h" |
| 23 | #include "llvm/Support/CommandLine.h" |
| 24 | #include "llvm/Support/FileSystem.h" |
| 25 | #include "llvm/Support/Path.h" |
| 26 | |
| 27 | #if !defined(_MSC_VER) && !defined(__MINGW32__) |
| 28 | #include <unistd.h> |
| 29 | #endif |
| 30 | |
| 31 | using namespace lld; |
| 32 | using namespace llvm; |
| 33 | |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 34 | // Create OptTable |
| 35 | enum { |
| 36 | OPT_INVALID = 0, |
| 37 | #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, |
| 38 | #include "Options.inc" |
| 39 | #undef OPTION |
| 40 | }; |
| 41 | |
| 42 | // Create prefix string literals used in Options.td |
Rui Ueyama | c16fd25 | 2017-09-11 22:04:13 | [diff] [blame] | 43 | #define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 44 | #include "Options.inc" |
| 45 | #undef PREFIX |
| 46 | |
| 47 | // Create table mapping all options defined in Options.td |
| 48 | static const opt::OptTable::Info InfoTable[] = { |
| 49 | #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ |
| 50 | {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ |
| 51 | X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, |
| 52 | #include "Options.inc" |
| 53 | #undef OPTION |
| 54 | }; |
| 55 | |
Rui Ueyama | c16fd25 | 2017-09-11 22:04:13 | [diff] [blame] | 56 | namespace { |
Rui Ueyama | 4474796 | 2017-09-11 22:04:25 | [diff] [blame] | 57 | class MinGWOptTable : public opt::OptTable { |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 58 | public: |
Rui Ueyama | 4474796 | 2017-09-11 22:04:25 | [diff] [blame] | 59 | MinGWOptTable() : OptTable(InfoTable, false) {} |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 60 | opt::InputArgList parse(ArrayRef<const char *> Argv); |
| 61 | }; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 62 | } // namespace |
| 63 | |
Rui Ueyama | d2da71f | 2017-09-11 22:04:37 | [diff] [blame] | 64 | opt::InputArgList MinGWOptTable::parse(ArrayRef<const char *> Argv) { |
| 65 | unsigned MissingIndex; |
| 66 | unsigned MissingCount; |
| 67 | |
| 68 | SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); |
| 69 | opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); |
| 70 | |
| 71 | if (MissingCount) |
Rui Ueyama | 338c4b2 | 2017-12-12 20:34:38 | [diff] [blame] | 72 | fatal(StringRef(Args.getArgString(MissingIndex)) + ": missing argument"); |
Rui Ueyama | d2da71f | 2017-09-11 22:04:37 | [diff] [blame] | 73 | for (auto *Arg : Args.filtered(OPT_UNKNOWN)) |
Rui Ueyama | 338c4b2 | 2017-12-12 20:34:38 | [diff] [blame] | 74 | fatal("unknown argument: " + Arg->getSpelling()); |
Rui Ueyama | a835bab | 2017-09-13 20:30:59 | [diff] [blame] | 75 | if (!Args.hasArg(OPT_INPUT) && !Args.hasArg(OPT_l)) |
Rui Ueyama | 338c4b2 | 2017-12-12 20:34:38 | [diff] [blame] | 76 | fatal("no input files"); |
Rui Ueyama | d2da71f | 2017-09-11 22:04:37 | [diff] [blame] | 77 | return Args; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 78 | } |
| 79 | |
| 80 | // Find a file by concatenating given paths. |
| 81 | static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) { |
| 82 | SmallString<128> S; |
| 83 | sys::path::append(S, Path1, Path2); |
| 84 | if (sys::fs::exists(S)) |
| 85 | return S.str().str(); |
| 86 | return None; |
| 87 | } |
| 88 | |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 89 | // This is for -lfoo. We'll look for libfoo.dll.a or libfoo.a from search paths. |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 90 | static std::string |
| 91 | searchLibrary(StringRef Name, ArrayRef<StringRef> SearchPaths, bool BStatic) { |
| 92 | if (Name.startswith(":")) { |
| 93 | for (StringRef Dir : SearchPaths) |
| 94 | if (Optional<std::string> S = findFile(Dir, Name.substr(1))) |
| 95 | return *S; |
Rui Ueyama | 338c4b2 | 2017-12-12 20:34:38 | [diff] [blame] | 96 | fatal("unable to find library -l" + Name); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 97 | } |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 98 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 99 | for (StringRef Dir : SearchPaths) { |
| 100 | if (!BStatic) |
| 101 | if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".dll.a")) |
| 102 | return *S; |
| 103 | if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) |
| 104 | return *S; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 105 | } |
Rui Ueyama | 338c4b2 | 2017-12-12 20:34:38 | [diff] [blame] | 106 | fatal("unable to find library -l" + Name); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 107 | } |
| 108 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 109 | // Convert Unix-ish command line arguments to Windows-ish ones and |
| 110 | // then call coff::link. |
Rui Ueyama | 95114b4 | 2017-09-11 22:04:01 | [diff] [blame] | 111 | bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) { |
Rui Ueyama | 4474796 | 2017-09-11 22:04:25 | [diff] [blame] | 112 | MinGWOptTable Parser; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 113 | opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 114 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 115 | std::vector<std::string> LinkArgs; |
| 116 | auto Add = [&](const Twine &S) { LinkArgs.push_back(S.str()); }; |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 117 | |
Martin Storsjo | a79762a | 2017-09-11 20:43:39 | [diff] [blame] | 118 | Add("lld-link"); |
Martin Storsjo | 31fe4cd | 2017-09-13 19:29:39 | [diff] [blame] | 119 | Add("-lldmingw"); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 120 | |
Martin Storsjo | 6d8dace | 2017-09-12 19:23:54 | [diff] [blame] | 121 | if (auto *A = Args.getLastArg(OPT_entry)) { |
| 122 | StringRef S = A->getValue(); |
| 123 | if (Args.getLastArgValue(OPT_m) == "i386pe" && S.startswith("_")) |
| 124 | Add("-entry:" + S.substr(1)); |
| 125 | else |
| 126 | Add("-entry:" + S); |
| 127 | } |
| 128 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 129 | if (auto *A = Args.getLastArg(OPT_subs)) |
| 130 | Add("-subsystem:" + StringRef(A->getValue())); |
Rui Ueyama | c3e4602 | 2017-09-11 20:54:51 | [diff] [blame] | 131 | if (auto *A = Args.getLastArg(OPT_out_implib)) |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 132 | Add("-implib:" + StringRef(A->getValue())); |
| 133 | if (auto *A = Args.getLastArg(OPT_stack)) |
| 134 | Add("-stack:" + StringRef(A->getValue())); |
Martin Storsjo | a84a477 | 2017-10-12 05:37:18 | [diff] [blame] | 135 | if (auto *A = Args.getLastArg(OPT_output_def)) |
| 136 | Add("-output-def:" + StringRef(A->getValue())); |
Martin Storsjo | e916868 | 2017-11-15 08:18:15 | [diff] [blame] | 137 | if (auto *A = Args.getLastArg(OPT_image_base)) |
| 138 | Add("-base:" + StringRef(A->getValue())); |
Martin Storsjo | 0366155 | 2018-05-15 21:12:29 | [diff] [blame] | 139 | if (auto *A = Args.getLastArg(OPT_map)) |
| 140 | Add("-lldmap:" + StringRef(A->getValue())); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 141 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 142 | if (auto *A = Args.getLastArg(OPT_o)) |
| 143 | Add("-out:" + StringRef(A->getValue())); |
| 144 | else if (Args.hasArg(OPT_shared)) |
| 145 | Add("-out:a.dll"); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 146 | else |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 147 | Add("-out:a.exe"); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 148 | |
Martin Storsjo | b7d5011 | 2018-05-15 06:34:18 | [diff] [blame] | 149 | if (auto *A = Args.getLastArg(OPT_pdb)) { |
| 150 | Add("-debug"); |
| 151 | Add("-pdb:" + StringRef(A->getValue())); |
Martin Storsjo | c082674 | 2018-06-29 06:08:31 | [diff] [blame] | 152 | } else if (Args.hasArg(OPT_strip_debug)) { |
| 153 | Add("-debug:symtab"); |
Martin Storsjo | b7d5011 | 2018-05-15 06:34:18 | [diff] [blame] | 154 | } else if (!Args.hasArg(OPT_strip_all)) { |
| 155 | Add("-debug:dwarf"); |
| 156 | } |
| 157 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 158 | if (Args.hasArg(OPT_shared)) |
| 159 | Add("-dll"); |
Rui Ueyama | 7d306a5 | 2017-09-13 19:40:07 | [diff] [blame] | 160 | if (Args.hasArg(OPT_verbose)) |
| 161 | Add("-verbose"); |
Martin Storsjo | a84a477 | 2017-10-12 05:37:18 | [diff] [blame] | 162 | if (Args.hasArg(OPT_export_all_symbols)) |
| 163 | Add("-export-all-symbols"); |
Martin Storsjo | 3c8d4b5 | 2017-11-15 08:18:06 | [diff] [blame] | 164 | if (Args.hasArg(OPT_large_address_aware)) |
| 165 | Add("-largeaddressaware"); |
Martin Storsjo | fb36e6e | 2018-03-14 20:17:24 | [diff] [blame] | 166 | if (Args.hasArg(OPT_kill_at)) |
| 167 | Add("-kill-at"); |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 168 | |
Martin Storsjo | 71663a2 | 2017-12-12 19:39:18 | [diff] [blame] | 169 | if (Args.getLastArgValue(OPT_m) != "thumb2pe" && |
| 170 | Args.getLastArgValue(OPT_m) != "arm64pe" && !Args.hasArg(OPT_dynamicbase)) |
| 171 | Add("-dynamicbase:no"); |
Martin Storsjo | 094d8c0 | 2017-11-15 08:18:11 | [diff] [blame] | 172 | |
Martin Storsjo | b190fd2 | 2017-11-15 08:18:20 | [diff] [blame] | 173 | if (Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false)) |
| 174 | Add("-opt:ref"); |
| 175 | else |
| 176 | Add("-opt:noref"); |
| 177 | |
| 178 | if (auto *A = Args.getLastArg(OPT_icf)) { |
| 179 | StringRef S = A->getValue(); |
| 180 | if (S == "all") |
| 181 | Add("-opt:icf"); |
| 182 | else if (S == "safe" || S == "none") |
| 183 | Add("-opt:noicf"); |
| 184 | else |
Rui Ueyama | 338c4b2 | 2017-12-12 20:34:38 | [diff] [blame] | 185 | fatal("unknown parameter: --icf=" + S); |
Martin Storsjo | b190fd2 | 2017-11-15 08:18:20 | [diff] [blame] | 186 | } else { |
| 187 | Add("-opt:noicf"); |
| 188 | } |
| 189 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 190 | if (auto *A = Args.getLastArg(OPT_m)) { |
| 191 | StringRef S = A->getValue(); |
| 192 | if (S == "i386pe") |
| 193 | Add("-machine:x86"); |
| 194 | else if (S == "i386pep") |
| 195 | Add("-machine:x64"); |
| 196 | else if (S == "thumb2pe") |
| 197 | Add("-machine:arm"); |
| 198 | else if (S == "arm64pe") |
| 199 | Add("-machine:arm64"); |
| 200 | else |
Rui Ueyama | 338c4b2 | 2017-12-12 20:34:38 | [diff] [blame] | 201 | fatal("unknown parameter: -m" + S); |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 202 | } |
| 203 | |
Martell Malone | 0d17638 | 2017-09-11 21:36:37 | [diff] [blame] | 204 | for (auto *A : Args.filtered(OPT_mllvm)) |
| 205 | Add("-mllvm:" + StringRef(A->getValue())); |
| 206 | |
Martin Storsjo | 107b548 | 2017-11-03 07:18:37 | [diff] [blame] | 207 | for (auto *A : Args.filtered(OPT_Xlink)) |
| 208 | Add(A->getValue()); |
| 209 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 210 | if (Args.getLastArgValue(OPT_m) == "i386pe") |
| 211 | Add("-alternatename:__image_base__=___ImageBase"); |
| 212 | else |
| 213 | Add("-alternatename:__image_base__=__ImageBase"); |
| 214 | |
Martin Storsjo | db62913 | 2018-09-10 17:41:40 | [diff] [blame^] | 215 | for (auto *A : Args.filtered(OPT_require_defined)) |
| 216 | Add("-include:" + StringRef(A->getValue())); |
| 217 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 218 | std::vector<StringRef> SearchPaths; |
| 219 | for (auto *A : Args.filtered(OPT_L)) |
| 220 | SearchPaths.push_back(A->getValue()); |
| 221 | |
Martin Storsjo | 32e1626 | 2017-09-13 07:28:09 | [diff] [blame] | 222 | StringRef Prefix = ""; |
Martin Storsjo | 2ba37d4 | 2017-09-13 19:29:44 | [diff] [blame] | 223 | bool Static = false; |
| 224 | for (auto *A : Args) { |
Rui Ueyama | 9c37d8c | 2017-09-13 19:44:36 | [diff] [blame] | 225 | switch (A->getOption().getUnaliasedOption().getID()) { |
Martin Storsjo | 32e1626 | 2017-09-13 07:28:09 | [diff] [blame] | 226 | case OPT_INPUT: |
Rui Ueyama | b359263 | 2017-09-14 18:33:09 | [diff] [blame] | 227 | if (StringRef(A->getValue()).endswith_lower(".def")) |
Martin Storsjo | 064b0fa | 2017-09-13 07:28:13 | [diff] [blame] | 228 | Add("-def:" + StringRef(A->getValue())); |
| 229 | else |
| 230 | Add(Prefix + StringRef(A->getValue())); |
Martin Storsjo | 32e1626 | 2017-09-13 07:28:09 | [diff] [blame] | 231 | break; |
| 232 | case OPT_l: |
Martin Storsjo | 2ba37d4 | 2017-09-13 19:29:44 | [diff] [blame] | 233 | Add(Prefix + searchLibrary(A->getValue(), SearchPaths, Static)); |
Martin Storsjo | 32e1626 | 2017-09-13 07:28:09 | [diff] [blame] | 234 | break; |
| 235 | case OPT_whole_archive: |
| 236 | Prefix = "-wholearchive:"; |
| 237 | break; |
| 238 | case OPT_no_whole_archive: |
| 239 | Prefix = ""; |
| 240 | break; |
Martin Storsjo | 2ba37d4 | 2017-09-13 19:29:44 | [diff] [blame] | 241 | case OPT_Bstatic: |
| 242 | Static = true; |
| 243 | break; |
| 244 | case OPT_Bdynamic: |
| 245 | Static = false; |
| 246 | break; |
Martin Storsjo | 32e1626 | 2017-09-13 07:28:09 | [diff] [blame] | 247 | } |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 248 | } |
| 249 | |
Martin Storsjo | a79762a | 2017-09-11 20:43:39 | [diff] [blame] | 250 | if (Args.hasArg(OPT_verbose) || Args.hasArg(OPT__HASH_HASH_HASH)) |
| 251 | outs() << llvm::join(LinkArgs, " ") << "\n"; |
| 252 | |
| 253 | if (Args.hasArg(OPT__HASH_HASH_HASH)) |
| 254 | return true; |
| 255 | |
Rui Ueyama | 5941b0b | 2017-09-11 20:14:47 | [diff] [blame] | 256 | // Repack vector of strings to vector of const char pointers for coff::link. |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 257 | std::vector<const char *> Vec; |
| 258 | for (const std::string &S : LinkArgs) |
| 259 | Vec.push_back(S.c_str()); |
Rui Ueyama | 6f4e255 | 2017-10-23 20:03:32 | [diff] [blame] | 260 | return coff::link(Vec, true); |
Martell Malone | 894dbbe | 2017-09-11 17:02:59 | [diff] [blame] | 261 | } |