Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 1 | //===- Driver.cpp ---------------------------------------------------------===// |
| 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 | [diff] [blame] | 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 |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "lld/Common/Driver.h" |
Sam Clegg | 78f766a | 2018-02-20 21:08:28 | [diff] [blame] | 10 | #include "Config.h" |
Nicholas Wilson | ebda41f | 2018-03-09 16:43:05 | [diff] [blame] | 11 | #include "InputChunks.h" |
Andy Wingo | a56e574 | 2021-02-11 11:15:24 | [diff] [blame] | 12 | #include "InputElement.h" |
Sam Clegg | 0362633 | 2018-01-31 01:45:47 | [diff] [blame] | 13 | #include "MarkLive.h" |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 14 | #include "SymbolTable.h" |
| 15 | #include "Writer.h" |
Rui Ueyama | 3e03944 | 2017-11-28 19:58:45 | [diff] [blame] | 16 | #include "lld/Common/Args.h" |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 17 | #include "lld/Common/ErrorHandler.h" |
Sam Clegg | b576701 | 2020-03-28 00:03:32 | [diff] [blame] | 18 | #include "lld/Common/Filesystem.h" |
Rui Ueyama | 2017d52 | 2017-11-28 20:39:17 | [diff] [blame] | 19 | #include "lld/Common/Memory.h" |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 20 | #include "lld/Common/Reproduce.h" |
Nicholas Wilson | 531769b | 2018-03-13 13:30:04 | [diff] [blame] | 21 | #include "lld/Common/Strings.h" |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 22 | #include "lld/Common/Version.h" |
| 23 | #include "llvm/ADT/Twine.h" |
Arthur Eubanks | e814013 | 2020-12-14 17:56:22 | [diff] [blame] | 24 | #include "llvm/Config/llvm-config.h" |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 25 | #include "llvm/Object/Wasm.h" |
Thomas Lively | 82de51a | 2019-03-26 04:11:05 | [diff] [blame] | 26 | #include "llvm/Option/Arg.h" |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 27 | #include "llvm/Option/ArgList.h" |
| 28 | #include "llvm/Support/CommandLine.h" |
Reid Kleckner | 213aea4 | 2020-03-11 22:39:28 | [diff] [blame] | 29 | #include "llvm/Support/Host.h" |
Reid Kleckner | 932f027 | 2020-05-05 03:03:19 | [diff] [blame] | 30 | #include "llvm/Support/Parallel.h" |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 31 | #include "llvm/Support/Path.h" |
| 32 | #include "llvm/Support/Process.h" |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 33 | #include "llvm/Support/TarWriter.h" |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 34 | #include "llvm/Support/TargetSelect.h" |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 35 | |
Sam Clegg | 0362633 | 2018-01-31 01:45:47 | [diff] [blame] | 36 | #define DEBUG_TYPE "lld" |
| 37 | |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 38 | using namespace llvm; |
Sam Clegg | 45218f4 | 2018-11-27 01:08:16 | [diff] [blame] | 39 | using namespace llvm::object; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 40 | using namespace llvm::sys; |
| 41 | using namespace llvm::wasm; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 42 | |
Fangrui Song | 33c59ab | 2019-10-10 05:25:39 | [diff] [blame] | 43 | namespace lld { |
| 44 | namespace wasm { |
| 45 | Configuration *config; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 46 | |
Rui Ueyama | 39049c0 | 2018-02-23 20:13:38 | [diff] [blame] | 47 | namespace { |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 48 | |
| 49 | // Create enum with OPT_xxx values for each option in Options.td |
| 50 | enum { |
| 51 | OPT_INVALID = 0, |
| 52 | #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, |
| 53 | #include "Options.inc" |
| 54 | #undef OPTION |
| 55 | }; |
| 56 | |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 57 | // This function is called on startup. We need this for LTO since |
| 58 | // LTO calls LLVM functions to compile bitcode files to native code. |
| 59 | // Technically this can be delayed until we read bitcode files, but |
| 60 | // we don't bother to do lazily because the initialization is fast. |
| 61 | static void initLLVM() { |
| 62 | InitializeAllTargets(); |
| 63 | InitializeAllTargetMCs(); |
| 64 | InitializeAllAsmPrinters(); |
| 65 | InitializeAllAsmParsers(); |
| 66 | } |
| 67 | |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 68 | class LinkerDriver { |
| 69 | public: |
Reshabh Sharma | fdd6ed8 | 2020-12-18 06:39:01 | [diff] [blame] | 70 | void linkerMain(ArrayRef<const char *> argsArr); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 71 | |
| 72 | private: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 73 | void createFiles(opt::InputArgList &args); |
| 74 | void addFile(StringRef path); |
| 75 | void addLibrary(StringRef name); |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 76 | |
| 77 | // True if we are in --whole-archive and --no-whole-archive. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 78 | bool inWholeArchive = false; |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 79 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 80 | std::vector<InputFile *> files; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 81 | }; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 82 | } // anonymous namespace |
| 83 | |
Rui Ueyama | b11386f | 2019-11-15 05:06:57 | [diff] [blame] | 84 | bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS, |
| 85 | raw_ostream &stderrOS) { |
James Y Knight | d3fec7f | 2019-11-20 15:08:18 | [diff] [blame] | 86 | lld::stdoutOS = &stdoutOS; |
| 87 | lld::stderrOS = &stderrOS; |
| 88 | |
Alexandre Ganea | f2efb57 | 2020-09-24 19:00:43 | [diff] [blame] | 89 | errorHandler().cleanupCallback = []() { freeArena(); }; |
| 90 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 91 | errorHandler().logName = args::getFilenameWithoutExe(args[0]); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 92 | errorHandler().errorLimitExceededMsg = |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 93 | "too many errors emitted, stopping now (use " |
| 94 | "-error-limit=0 to see all errors)"; |
James Y Knight | d3fec7f | 2019-11-20 15:08:18 | [diff] [blame] | 95 | stderrOS.enable_colors(stderrOS.has_colors()); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 96 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 97 | config = make<Configuration>(); |
| 98 | symtab = make<SymbolTable>(); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 99 | |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 100 | initLLVM(); |
Reshabh Sharma | fdd6ed8 | 2020-12-18 06:39:01 | [diff] [blame] | 101 | LinkerDriver().linkerMain(args); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 102 | |
| 103 | // Exit immediately if we don't need to return to the caller. |
| 104 | // This saves time because the overhead of calling destructors |
| 105 | // for all globally-allocated objects is not negligible. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 106 | if (canExitEarly) |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 107 | exitLld(errorCount() ? 1 : 0); |
| 108 | |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 109 | return !errorCount(); |
| 110 | } |
| 111 | |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 112 | // Create prefix string literals used in Options.td |
| 113 | #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; |
| 114 | #include "Options.inc" |
| 115 | #undef PREFIX |
| 116 | |
| 117 | // Create table mapping all options defined in Options.td |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 118 | static const opt::OptTable::Info optInfo[] = { |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 119 | #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ |
| 120 | {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ |
| 121 | X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, |
| 122 | #include "Options.inc" |
| 123 | #undef OPTION |
| 124 | }; |
| 125 | |
Benjamin Kramer | 5455038 | 2018-05-15 22:01:54 | [diff] [blame] | 126 | namespace { |
Rui Ueyama | 39049c0 | 2018-02-23 20:13:38 | [diff] [blame] | 127 | class WasmOptTable : public llvm::opt::OptTable { |
| 128 | public: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 129 | WasmOptTable() : OptTable(optInfo) {} |
| 130 | opt::InputArgList parse(ArrayRef<const char *> argv); |
Rui Ueyama | 39049c0 | 2018-02-23 20:13:38 | [diff] [blame] | 131 | }; |
Benjamin Kramer | 5455038 | 2018-05-15 22:01:54 | [diff] [blame] | 132 | } // namespace |
Rui Ueyama | 39049c0 | 2018-02-23 20:13:38 | [diff] [blame] | 133 | |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 134 | // Set color diagnostics according to -color-diagnostics={auto,always,never} |
| 135 | // or -no-color-diagnostics flags. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 136 | static void handleColorDiagnostics(opt::InputArgList &args) { |
| 137 | auto *arg = args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 138 | OPT_no_color_diagnostics); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 139 | if (!arg) |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 140 | return; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 141 | if (arg->getOption().getID() == OPT_color_diagnostics) { |
James Y Knight | d3fec7f | 2019-11-20 15:08:18 | [diff] [blame] | 142 | lld::errs().enable_colors(true); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 143 | } else if (arg->getOption().getID() == OPT_no_color_diagnostics) { |
James Y Knight | d3fec7f | 2019-11-20 15:08:18 | [diff] [blame] | 144 | lld::errs().enable_colors(false); |
Nico Weber | cac2b33 | 2018-05-10 18:19:02 | [diff] [blame] | 145 | } else { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 146 | StringRef s = arg->getValue(); |
| 147 | if (s == "always") |
James Y Knight | d3fec7f | 2019-11-20 15:08:18 | [diff] [blame] | 148 | lld::errs().enable_colors(true); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 149 | else if (s == "never") |
James Y Knight | d3fec7f | 2019-11-20 15:08:18 | [diff] [blame] | 150 | lld::errs().enable_colors(false); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 151 | else if (s != "auto") |
| 152 | error("unknown option: --color-diagnostics=" + s); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 153 | } |
| 154 | } |
| 155 | |
Sam Clegg | 928e9e1 | 2020-03-04 19:29:45 | [diff] [blame] | 156 | static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &args) { |
| 157 | if (auto *arg = args.getLastArg(OPT_rsp_quoting)) { |
| 158 | StringRef s = arg->getValue(); |
| 159 | if (s != "windows" && s != "posix") |
| 160 | error("invalid response file quoting: " + s); |
| 161 | if (s == "windows") |
| 162 | return cl::TokenizeWindowsCommandLine; |
| 163 | return cl::TokenizeGNUCommandLine; |
| 164 | } |
| 165 | if (Triple(sys::getProcessTriple()).isOSWindows()) |
| 166 | return cl::TokenizeWindowsCommandLine; |
| 167 | return cl::TokenizeGNUCommandLine; |
| 168 | } |
| 169 | |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 170 | // Find a file by concatenating given paths. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 171 | static Optional<std::string> findFile(StringRef path1, const Twine &path2) { |
| 172 | SmallString<128> s; |
| 173 | path::append(s, path1, path2); |
| 174 | if (fs::exists(s)) |
Jonas Devlieghere | 3e24242 | 2020-01-30 05:30:21 | [diff] [blame] | 175 | return std::string(s); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 176 | return None; |
| 177 | } |
| 178 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 179 | opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> argv) { |
| 180 | SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size()); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 181 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 182 | unsigned missingIndex; |
| 183 | unsigned missingCount; |
Sam Clegg | e9ce661 | 2018-05-30 03:51:56 | [diff] [blame] | 184 | |
Sam Clegg | 928e9e1 | 2020-03-04 19:29:45 | [diff] [blame] | 185 | // We need to get the quoting style for response files before parsing all |
| 186 | // options so we parse here before and ignore all the options but |
| 187 | // --rsp-quoting. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 188 | opt::InputArgList args = this->ParseArgs(vec, missingIndex, missingCount); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 189 | |
Sam Clegg | 928e9e1 | 2020-03-04 19:29:45 | [diff] [blame] | 190 | // Expand response files (arguments in the form of @<filename>) |
| 191 | // and then parse the argument again. |
| 192 | cl::ExpandResponseFiles(saver, getQuotingStyle(args), vec); |
| 193 | args = this->ParseArgs(vec, missingIndex, missingCount); |
| 194 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 195 | handleColorDiagnostics(args); |
| 196 | for (auto *arg : args.filtered(OPT_UNKNOWN)) |
| 197 | error("unknown argument: " + arg->getAsString(args)); |
| 198 | return args; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 199 | } |
| 200 | |
Sam Clegg | 31efdcd | 2018-01-11 22:31:35 | [diff] [blame] | 201 | // Currently we allow a ".imports" to live alongside a library. This can |
| 202 | // be used to specify a list of symbols which can be undefined at link |
| 203 | // time (imported from the environment. For example libc.a include an |
| 204 | // import file that lists the syscall functions it relies on at runtime. |
| 205 | // In the long run this information would be better stored as a symbol |
| 206 | // attribute/flag in the object file itself. |
| 207 | // See: https://github.com/WebAssembly/tool-conventions/issues/35 |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 208 | static void readImportFile(StringRef filename) { |
| 209 | if (Optional<MemoryBufferRef> buf = readFile(filename)) |
| 210 | for (StringRef sym : args::getLines(*buf)) |
| 211 | config->allowUndefinedSymbols.insert(sym); |
Sam Clegg | 31efdcd | 2018-01-11 22:31:35 | [diff] [blame] | 212 | } |
| 213 | |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 214 | // Returns slices of MB by parsing MB as an archive file. |
| 215 | // Each slice consists of a member file in the archive. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 216 | std::vector<MemoryBufferRef> static getArchiveMembers(MemoryBufferRef mb) { |
| 217 | std::unique_ptr<Archive> file = |
| 218 | CHECK(Archive::create(mb), |
| 219 | mb.getBufferIdentifier() + ": failed to parse archive"); |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 220 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 221 | std::vector<MemoryBufferRef> v; |
| 222 | Error err = Error::success(); |
Fangrui Song | 681b1be | 2020-01-01 23:28:48 | [diff] [blame] | 223 | for (const Archive::Child &c : file->children(err)) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 224 | MemoryBufferRef mbref = |
| 225 | CHECK(c.getMemoryBufferRef(), |
| 226 | mb.getBufferIdentifier() + |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 227 | ": could not get the buffer for a child of the archive"); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 228 | v.push_back(mbref); |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 229 | } |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 230 | if (err) |
| 231 | fatal(mb.getBufferIdentifier() + |
| 232 | ": Archive::children failed: " + toString(std::move(err))); |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 233 | |
| 234 | // Take ownership of memory buffers created for members of thin archives. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 235 | for (std::unique_ptr<MemoryBuffer> &mb : file->takeThinBuffers()) |
| 236 | make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 237 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 238 | return v; |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 239 | } |
| 240 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 241 | void LinkerDriver::addFile(StringRef path) { |
| 242 | Optional<MemoryBufferRef> buffer = readFile(path); |
| 243 | if (!buffer.hasValue()) |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 244 | return; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 245 | MemoryBufferRef mbref = *buffer; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 246 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 247 | switch (identify_magic(mbref.getBuffer())) { |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 248 | case file_magic::archive: { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 249 | SmallString<128> importFile = path; |
| 250 | path::replace_extension(importFile, ".imports"); |
| 251 | if (fs::exists(importFile)) |
| 252 | readImportFile(importFile.str()); |
Sam Clegg | 61d70e4 | 2019-06-25 17:49:35 | [diff] [blame] | 253 | |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 254 | // Handle -whole-archive. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 255 | if (inWholeArchive) { |
Sam Clegg | b3b4cda | 2020-10-13 03:45:20 | [diff] [blame] | 256 | for (MemoryBufferRef &m : getArchiveMembers(mbref)) { |
| 257 | auto *object = createObjectFile(m, path); |
| 258 | // Mark object as live; object members are normally not |
| 259 | // live by default but -whole-archive is designed to treat |
| 260 | // them as such. |
| 261 | object->markLive(); |
| 262 | files.push_back(object); |
| 263 | } |
| 264 | |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 265 | return; |
| 266 | } |
| 267 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 268 | std::unique_ptr<Archive> file = |
| 269 | CHECK(Archive::create(mbref), path + ": failed to parse archive"); |
Sam Clegg | 61d70e4 | 2019-06-25 17:49:35 | [diff] [blame] | 270 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 271 | if (!file->isEmpty() && !file->hasSymbolTable()) { |
| 272 | error(mbref.getBufferIdentifier() + |
Sam Clegg | 61d70e4 | 2019-06-25 17:49:35 | [diff] [blame] | 273 | ": archive has no index; run ranlib to add one"); |
| 274 | } |
Sam Clegg | 31efdcd | 2018-01-11 22:31:35 | [diff] [blame] | 275 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 276 | files.push_back(make<ArchiveFile>(mbref)); |
Sam Clegg | 31efdcd | 2018-01-11 22:31:35 | [diff] [blame] | 277 | return; |
| 278 | } |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 279 | case file_magic::bitcode: |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 280 | case file_magic::wasm_object: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 281 | files.push_back(createObjectFile(mbref)); |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 282 | break; |
| 283 | default: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 284 | error("unknown file type: " + mbref.getBufferIdentifier()); |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 285 | } |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 286 | } |
| 287 | |
| 288 | // Add a given library by searching it from input search paths. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 289 | void LinkerDriver::addLibrary(StringRef name) { |
| 290 | for (StringRef dir : config->searchPaths) { |
| 291 | if (Optional<std::string> s = findFile(dir, "lib" + name + ".a")) { |
| 292 | addFile(*s); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 293 | return; |
| 294 | } |
| 295 | } |
| 296 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 297 | error("unable to find library -l" + name); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 298 | } |
| 299 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 300 | void LinkerDriver::createFiles(opt::InputArgList &args) { |
| 301 | for (auto *arg : args) { |
| 302 | switch (arg->getOption().getID()) { |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 303 | case OPT_l: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 304 | addLibrary(arg->getValue()); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 305 | break; |
| 306 | case OPT_INPUT: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 307 | addFile(arg->getValue()); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 308 | break; |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 309 | case OPT_whole_archive: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 310 | inWholeArchive = true; |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 311 | break; |
| 312 | case OPT_no_whole_archive: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 313 | inWholeArchive = false; |
Sam Clegg | 8adf7ac | 2018-07-23 23:51:19 | [diff] [blame] | 314 | break; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 315 | } |
| 316 | } |
Sam Clegg | b576701 | 2020-03-28 00:03:32 | [diff] [blame] | 317 | if (files.empty() && errorCount() == 0) |
| 318 | error("no input files"); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 319 | } |
| 320 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 321 | static StringRef getEntry(opt::InputArgList &args) { |
| 322 | auto *arg = args.getLastArg(OPT_entry, OPT_no_entry); |
| 323 | if (!arg) { |
| 324 | if (args.hasArg(OPT_relocatable)) |
Sam Clegg | 09137be | 2019-04-04 18:40:51 | [diff] [blame] | 325 | return ""; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 326 | if (args.hasArg(OPT_shared)) |
Sam Clegg | 09137be | 2019-04-04 18:40:51 | [diff] [blame] | 327 | return "__wasm_call_ctors"; |
| 328 | return "_start"; |
| 329 | } |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 330 | if (arg->getOption().getID() == OPT_no_entry) |
Sam Clegg | 2c096ba | 2017-12-08 17:58:25 | [diff] [blame] | 331 | return ""; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 332 | return arg->getValue(); |
Sam Clegg | 2c096ba | 2017-12-08 17:58:25 | [diff] [blame] | 333 | } |
| 334 | |
Sam Clegg | 206884b | 2020-05-01 16:14:59 | [diff] [blame] | 335 | // Determines what we should do if there are remaining unresolved |
| 336 | // symbols after the name resolution. |
| 337 | static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) { |
| 338 | UnresolvedPolicy errorOrWarn = args.hasFlag(OPT_error_unresolved_symbols, |
| 339 | OPT_warn_unresolved_symbols, true) |
| 340 | ? UnresolvedPolicy::ReportError |
| 341 | : UnresolvedPolicy::Warn; |
| 342 | |
| 343 | if (auto *arg = args.getLastArg(OPT_unresolved_symbols)) { |
| 344 | StringRef s = arg->getValue(); |
| 345 | if (s == "ignore-all") |
| 346 | return UnresolvedPolicy::Ignore; |
| 347 | if (s == "import-functions") |
| 348 | return UnresolvedPolicy::ImportFuncs; |
| 349 | if (s == "report-all") |
| 350 | return errorOrWarn; |
| 351 | error("unknown --unresolved-symbols value: " + s); |
| 352 | } |
| 353 | |
| 354 | // Legacy --allow-undefined flag which is equivalent to |
| 355 | // --unresolve-symbols=ignore-all |
| 356 | if (args.hasArg(OPT_allow_undefined)) |
| 357 | return UnresolvedPolicy::ImportFuncs; |
| 358 | |
| 359 | return errorOrWarn; |
| 360 | } |
| 361 | |
Sam Clegg | a1282a3 | 2019-05-08 16:20:05 | [diff] [blame] | 362 | // Initializes Config members by the command line options. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 363 | static void readConfigs(opt::InputArgList &args) { |
Sam Clegg | 2513407 | 2020-10-07 21:48:37 | [diff] [blame] | 364 | config->bsymbolic = args.hasArg(OPT_Bsymbolic); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 365 | config->checkFeatures = |
| 366 | args.hasFlag(OPT_check_features, OPT_no_check_features, true); |
| 367 | config->compressRelocations = args.hasArg(OPT_compress_relocations); |
| 368 | config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true); |
| 369 | config->disableVerify = args.hasArg(OPT_disable_verify); |
| 370 | config->emitRelocs = args.hasArg(OPT_emit_relocs); |
Dan Gohman | 46a3268 | 2020-06-12 19:05:40 | [diff] [blame] | 371 | config->experimentalPic = args.hasArg(OPT_experimental_pic); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 372 | config->entry = getEntry(args); |
| 373 | config->exportAll = args.hasArg(OPT_export_all); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 374 | config->exportTable = args.hasArg(OPT_export_table); |
Jacob Gravelle | 92ed86d | 2019-08-27 22:58:21 | [diff] [blame] | 375 | config->growableTable = args.hasArg(OPT_growable_table); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 376 | errorHandler().fatalWarnings = |
| 377 | args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); |
| 378 | config->importMemory = args.hasArg(OPT_import_memory); |
| 379 | config->sharedMemory = args.hasArg(OPT_shared_memory); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 380 | config->importTable = args.hasArg(OPT_import_table); |
| 381 | config->ltoo = args::getInteger(args, OPT_lto_O, 2); |
| 382 | config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1); |
Arthur Eubanks | e814013 | 2020-12-14 17:56:22 | [diff] [blame] | 383 | config->ltoNewPassManager = |
Arthur Eubanks | a231786 | 2020-12-14 23:03:28 | [diff] [blame] | 384 | args.hasFlag(OPT_no_lto_legacy_pass_manager, OPT_lto_legacy_pass_manager, |
Arthur Eubanks | e814013 | 2020-12-14 17:56:22 | [diff] [blame] | 385 | LLVM_ENABLE_NEW_PASS_MANAGER); |
Arthur Eubanks | 1314a49 | 2020-12-01 20:22:27 | [diff] [blame] | 386 | config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager); |
Sam Clegg | cc2da55 | 2020-03-27 23:52:27 | [diff] [blame] | 387 | config->mapFile = args.getLastArgValue(OPT_Map); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 388 | config->optimize = args::getInteger(args, OPT_O, 0); |
| 389 | config->outputFile = args.getLastArgValue(OPT_o); |
| 390 | config->relocatable = args.hasArg(OPT_relocatable); |
| 391 | config->gcSections = |
| 392 | args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !config->relocatable); |
| 393 | config->mergeDataSegments = |
| 394 | args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments, |
| 395 | !config->relocatable); |
| 396 | config->pie = args.hasFlag(OPT_pie, OPT_no_pie, false); |
| 397 | config->printGcSections = |
| 398 | args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); |
| 399 | config->saveTemps = args.hasArg(OPT_save_temps); |
| 400 | config->searchPaths = args::getStrings(args, OPT_L); |
| 401 | config->shared = args.hasArg(OPT_shared); |
| 402 | config->stripAll = args.hasArg(OPT_strip_all); |
| 403 | config->stripDebug = args.hasArg(OPT_strip_debug); |
| 404 | config->stackFirst = args.hasArg(OPT_stack_first); |
| 405 | config->trace = args.hasArg(OPT_trace); |
| 406 | config->thinLTOCacheDir = args.getLastArgValue(OPT_thinlto_cache_dir); |
| 407 | config->thinLTOCachePolicy = CHECK( |
| 408 | parseCachePruningPolicy(args.getLastArgValue(OPT_thinlto_cache_policy)), |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 409 | "--thinlto-cache-policy: invalid cache policy"); |
Sam Clegg | 206884b | 2020-05-01 16:14:59 | [diff] [blame] | 410 | config->unresolvedSymbols = getUnresolvedSymbolPolicy(args); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 411 | errorHandler().verbose = args.hasArg(OPT_verbose); |
| 412 | LLVM_DEBUG(errorHandler().verbose = true); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 413 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 414 | config->initialMemory = args::getInteger(args, OPT_initial_memory, 0); |
| 415 | config->globalBase = args::getInteger(args, OPT_global_base, 1024); |
| 416 | config->maxMemory = args::getInteger(args, OPT_max_memory, 0); |
| 417 | config->zStackSize = |
| 418 | args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize); |
Thomas Lively | 82de51a | 2019-03-26 04:11:05 | [diff] [blame] | 419 | |
Sam Clegg | e8e914e | 2019-08-19 16:34:51 | [diff] [blame] | 420 | // Default value of exportDynamic depends on `-shared` |
| 421 | config->exportDynamic = |
| 422 | args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, config->shared); |
| 423 | |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 424 | // Parse wasm32/64. |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 425 | if (auto *arg = args.getLastArg(OPT_m)) { |
| 426 | StringRef s = arg->getValue(); |
| 427 | if (s == "wasm32") |
| 428 | config->is64 = false; |
| 429 | else if (s == "wasm64") |
| 430 | config->is64 = true; |
| 431 | else |
| 432 | error("invalid target architecture: " + s); |
| 433 | } |
| 434 | |
Fangrui Song | eb4663d | 2020-03-17 19:40:19 | [diff] [blame] | 435 | // --threads= takes a positive integer and provides the default value for |
| 436 | // --thinlto-jobs=. |
| 437 | if (auto *arg = args.getLastArg(OPT_threads)) { |
| 438 | StringRef v(arg->getValue()); |
| 439 | unsigned threads = 0; |
| 440 | if (!llvm::to_integer(v, threads, 0) || threads == 0) |
| 441 | error(arg->getSpelling() + ": expected a positive integer, but got '" + |
| 442 | arg->getValue() + "'"); |
| 443 | parallel::strategy = hardware_concurrency(threads); |
| 444 | config->thinLTOJobs = v; |
| 445 | } |
| 446 | if (auto *arg = args.getLastArg(OPT_thinlto_jobs)) |
| 447 | config->thinLTOJobs = arg->getValue(); |
| 448 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 449 | if (auto *arg = args.getLastArg(OPT_features)) { |
| 450 | config->features = |
Thomas Lively | 82de51a | 2019-03-26 04:11:05 | [diff] [blame] | 451 | llvm::Optional<std::vector<std::string>>(std::vector<std::string>()); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 452 | for (StringRef s : arg->getValues()) |
Benjamin Kramer | adcd026 | 2020-01-28 19:23:46 | [diff] [blame] | 453 | config->features->push_back(std::string(s)); |
Thomas Lively | 82de51a | 2019-03-26 04:11:05 | [diff] [blame] | 454 | } |
Sam Clegg | cc2da55 | 2020-03-27 23:52:27 | [diff] [blame] | 455 | |
| 456 | if (args.hasArg(OPT_print_map)) |
| 457 | config->mapFile = "-"; |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 458 | } |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 459 | |
Sam Clegg | a1282a3 | 2019-05-08 16:20:05 | [diff] [blame] | 460 | // Some Config members do not directly correspond to any particular |
| 461 | // command line options, but computed based on other Config values. |
| 462 | // This function initialize such members. See Config.h for the details |
| 463 | // of these values. |
| 464 | static void setConfigs() { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 465 | config->isPic = config->pie || config->shared; |
Sam Clegg | a1282a3 | 2019-05-08 16:20:05 | [diff] [blame] | 466 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 467 | if (config->isPic) { |
| 468 | if (config->exportTable) |
Sam Clegg | a1282a3 | 2019-05-08 16:20:05 | [diff] [blame] | 469 | error("-shared/-pie is incompatible with --export-table"); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 470 | config->importTable = true; |
Sam Clegg | a1282a3 | 2019-05-08 16:20:05 | [diff] [blame] | 471 | } |
| 472 | |
Andy Wingo | 48219d0 | 2021-02-16 12:28:44 | [diff] [blame] | 473 | if (config->relocatable) { |
| 474 | if (config->exportTable) |
| 475 | error("--relocatable is incompatible with --export-table"); |
| 476 | if (config->growableTable) |
| 477 | error("--relocatable is incompatible with --growable-table"); |
| 478 | // Ignore any --import-table, as it's redundant. |
| 479 | config->importTable = true; |
| 480 | } |
| 481 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 482 | if (config->shared) { |
| 483 | config->importMemory = true; |
Sam Clegg | 206884b | 2020-05-01 16:14:59 | [diff] [blame] | 484 | config->unresolvedSymbols = UnresolvedPolicy::ImportFuncs; |
Sam Clegg | a1282a3 | 2019-05-08 16:20:05 | [diff] [blame] | 485 | } |
| 486 | } |
| 487 | |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 488 | // Some command line options or some combinations of them are not allowed. |
| 489 | // This function checks for such errors. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 490 | static void checkOptions(opt::InputArgList &args) { |
| 491 | if (!config->stripDebug && !config->stripAll && config->compressRelocations) |
Sam Clegg | 30161dc | 2018-08-17 19:42:46 | [diff] [blame] | 492 | error("--compress-relocations is incompatible with output debug" |
| 493 | " information. Please pass --strip-debug or --strip-all"); |
Sam Clegg | fb983cd | 2018-05-18 23:28:05 | [diff] [blame] | 494 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 495 | if (config->ltoo > 3) |
| 496 | error("invalid optimization level for LTO: " + Twine(config->ltoo)); |
| 497 | if (config->ltoPartitions == 0) |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 498 | error("--lto-partitions: number of threads must be > 0"); |
Alexandre Ganea | 0915825 | 2020-03-27 14:20:39 | [diff] [blame] | 499 | if (!get_threadpool_strategy(config->thinLTOJobs)) |
| 500 | error("--thinlto-jobs: invalid job count: " + config->thinLTOJobs); |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 501 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 502 | if (config->pie && config->shared) |
Sam Clegg | bfb7534 | 2018-11-15 00:37:21 | [diff] [blame] | 503 | error("-shared and -pie may not be used together"); |
| 504 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 505 | if (config->outputFile.empty()) |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 506 | error("no output file specified"); |
| 507 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 508 | if (config->importTable && config->exportTable) |
Rui Ueyama | 0961218 | 2018-03-30 16:06:14 | [diff] [blame] | 509 | error("--import-table and --export-table may not be used together"); |
| 510 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 511 | if (config->relocatable) { |
| 512 | if (!config->entry.empty()) |
Sam Clegg | 0362633 | 2018-01-31 01:45:47 | [diff] [blame] | 513 | error("entry point specified for relocatable output file"); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 514 | if (config->gcSections) |
Sam Clegg | 0362633 | 2018-01-31 01:45:47 | [diff] [blame] | 515 | error("-r and --gc-sections may not be used together"); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 516 | if (config->compressRelocations) |
Sam Clegg | 30161dc | 2018-08-17 19:42:46 | [diff] [blame] | 517 | error("-r -and --compress-relocations may not be used together"); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 518 | if (args.hasArg(OPT_undefined)) |
Sam Clegg | 0362633 | 2018-01-31 01:45:47 | [diff] [blame] | 519 | error("-r -and --undefined may not be used together"); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 520 | if (config->pie) |
Sam Clegg | bfb7534 | 2018-11-15 00:37:21 | [diff] [blame] | 521 | error("-r and -pie may not be used together"); |
Thomas Lively | 6474d1b | 2020-04-14 02:16:20 | [diff] [blame] | 522 | if (config->sharedMemory) |
| 523 | error("-r and --shared-memory may not be used together"); |
Sam Clegg | 0362633 | 2018-01-31 01:45:47 | [diff] [blame] | 524 | } |
Dan Gohman | 46a3268 | 2020-06-12 19:05:40 | [diff] [blame] | 525 | |
| 526 | // To begin to prepare for Module Linking-style shared libraries, start |
| 527 | // warning about uses of `-shared` and related flags outside of Experimental |
| 528 | // mode, to give anyone using them a heads-up that they will be changing. |
| 529 | // |
| 530 | // Also, warn about flags which request explicit exports. |
| 531 | if (!config->experimentalPic) { |
| 532 | // -shared will change meaning when Module Linking is implemented. |
| 533 | if (config->shared) { |
| 534 | warn("creating shared libraries, with -shared, is not yet stable"); |
| 535 | } |
| 536 | |
| 537 | // -pie will change meaning when Module Linking is implemented. |
| 538 | if (config->pie) { |
| 539 | warn("creating PIEs, with -pie, is not yet stable"); |
| 540 | } |
| 541 | } |
Sam Clegg | 2513407 | 2020-10-07 21:48:37 | [diff] [blame] | 542 | |
| 543 | if (config->bsymbolic && !config->shared) { |
| 544 | warn("-Bsymbolic is only meaningful when combined with -shared"); |
| 545 | } |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 546 | } |
| 547 | |
| 548 | // Force Sym to be entered in the output. Used for -u or equivalent. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 549 | static Symbol *handleUndefined(StringRef name) { |
| 550 | Symbol *sym = symtab->find(name); |
| 551 | if (!sym) |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 552 | return nullptr; |
| 553 | |
| 554 | // Since symbol S may not be used inside the program, LTO may |
| 555 | // eliminate it. Mark the symbol as "used" to prevent it. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 556 | sym->isUsedInRegularObj = true; |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 557 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 558 | if (auto *lazySym = dyn_cast<LazySymbol>(sym)) |
| 559 | lazySym->fetch(); |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 560 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 561 | return sym; |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 562 | } |
| 563 | |
Sam Clegg | 9cd9858 | 2019-12-20 01:23:59 | [diff] [blame] | 564 | static void handleLibcall(StringRef name) { |
| 565 | Symbol *sym = symtab->find(name); |
| 566 | if (!sym) |
| 567 | return; |
| 568 | |
| 569 | if (auto *lazySym = dyn_cast<LazySymbol>(sym)) { |
| 570 | MemoryBufferRef mb = lazySym->getMemberBuffer(); |
| 571 | if (isBitcode(mb)) |
| 572 | lazySym->fetch(); |
| 573 | } |
| 574 | } |
| 575 | |
Sam Clegg | 2dad4e2 | 2018-11-15 18:15:54 | [diff] [blame] | 576 | static UndefinedGlobal * |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 577 | createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) { |
Sam Clegg | f6f4b98 | 2019-09-23 21:28:29 | [diff] [blame] | 578 | auto *sym = cast<UndefinedGlobal>(symtab->addUndefinedGlobal( |
Sam Clegg | bd48127 | 2020-02-06 05:18:55 | [diff] [blame] | 579 | name, None, None, WASM_SYMBOL_UNDEFINED, nullptr, type)); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 580 | config->allowUndefinedSymbols.insert(sym->getName()); |
| 581 | sym->isUsedInRegularObj = true; |
| 582 | return sym; |
Sam Clegg | 2dad4e2 | 2018-11-15 18:15:54 | [diff] [blame] | 583 | } |
| 584 | |
Sam Clegg | 29a3056 | 2020-11-10 01:52:39 | [diff] [blame] | 585 | static InputGlobal *createGlobal(StringRef name, bool isMutable) { |
Guanzhong Chen | 5204f76 | 2019-07-19 23:34:16 | [diff] [blame] | 586 | llvm::wasm::WasmGlobal wasmGlobal; |
Wouter van Oortmerssen | 29f8c9f | 2020-07-06 20:34:16 | [diff] [blame] | 587 | if (config->is64.getValueOr(false)) { |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 588 | wasmGlobal.Type = {WASM_TYPE_I64, isMutable}; |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 589 | wasmGlobal.InitExpr.Opcode = WASM_OPCODE_I64_CONST; |
Sam Clegg | 29a3056 | 2020-11-10 01:52:39 | [diff] [blame] | 590 | wasmGlobal.InitExpr.Value.Int64 = 0; |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 591 | } else { |
| 592 | wasmGlobal.Type = {WASM_TYPE_I32, isMutable}; |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 593 | wasmGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; |
Sam Clegg | 29a3056 | 2020-11-10 01:52:39 | [diff] [blame] | 594 | wasmGlobal.InitExpr.Value.Int32 = 0; |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 595 | } |
Guanzhong Chen | 5204f76 | 2019-07-19 23:34:16 | [diff] [blame] | 596 | wasmGlobal.SymbolName = name; |
Sam Clegg | 29a3056 | 2020-11-10 01:52:39 | [diff] [blame] | 597 | return make<InputGlobal>(wasmGlobal, nullptr); |
| 598 | } |
| 599 | |
| 600 | static GlobalSymbol *createGlobalVariable(StringRef name, bool isMutable) { |
| 601 | InputGlobal *g = createGlobal(name, isMutable); |
| 602 | return symtab->addSyntheticGlobal(name, WASM_SYMBOL_VISIBILITY_HIDDEN, g); |
| 603 | } |
| 604 | |
| 605 | static GlobalSymbol *createOptionalGlobal(StringRef name, bool isMutable) { |
| 606 | InputGlobal *g = createGlobal(name, isMutable); |
Sam Clegg | 88e4056 | 2021-02-09 01:12:23 | [diff] [blame] | 607 | return symtab->addOptionalGlobalSymbol(name, g); |
Guanzhong Chen | 5204f76 | 2019-07-19 23:34:16 | [diff] [blame] | 608 | } |
| 609 | |
Sam Clegg | 2dad4e2 | 2018-11-15 18:15:54 | [diff] [blame] | 610 | // Create ABI-defined synthetic symbols |
| 611 | static void createSyntheticSymbols() { |
Sam Clegg | dbfea28 | 2019-08-08 23:56:21 | [diff] [blame] | 612 | if (config->relocatable) |
| 613 | return; |
| 614 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 615 | static WasmSignature nullSignature = {{}, {}}; |
Guanzhong Chen | 42bba4b | 2019-07-16 22:00:45 | [diff] [blame] | 616 | static WasmSignature i32ArgSignature = {{}, {ValType::I32}}; |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 617 | static WasmSignature i64ArgSignature = {{}, {ValType::I64}}; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 618 | static llvm::wasm::WasmGlobalType globalTypeI32 = {WASM_TYPE_I32, false}; |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 619 | static llvm::wasm::WasmGlobalType globalTypeI64 = {WASM_TYPE_I64, false}; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 620 | static llvm::wasm::WasmGlobalType mutableGlobalTypeI32 = {WASM_TYPE_I32, |
Sam Clegg | 2dad4e2 | 2018-11-15 18:15:54 | [diff] [blame] | 621 | true}; |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 622 | static llvm::wasm::WasmGlobalType mutableGlobalTypeI64 = {WASM_TYPE_I64, |
| 623 | true}; |
Sam Clegg | dbfea28 | 2019-08-08 23:56:21 | [diff] [blame] | 624 | WasmSym::callCtors = symtab->addSyntheticFunction( |
| 625 | "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, |
| 626 | make<SyntheticFunction>(nullSignature, "__wasm_call_ctors")); |
Sam Clegg | 2dad4e2 | 2018-11-15 18:15:54 | [diff] [blame] | 627 | |
Sam Clegg | dbfea28 | 2019-08-08 23:56:21 | [diff] [blame] | 628 | if (config->isPic) { |
Wouter van Oortmerssen | 29f8c9f | 2020-07-06 20:34:16 | [diff] [blame] | 629 | WasmSym::stackPointer = |
| 630 | createUndefinedGlobal("__stack_pointer", config->is64.getValueOr(false) |
| 631 | ? &mutableGlobalTypeI64 |
| 632 | : &mutableGlobalTypeI32); |
Sam Clegg | fd11ce3 | 2019-07-11 13:13:25 | [diff] [blame] | 633 | // For PIC code, we import two global variables (__memory_base and |
| 634 | // __table_base) from the environment and use these as the offset at |
| 635 | // which to load our static data and function table. |
| 636 | // See: |
| 637 | // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md |
Wouter van Oortmerssen | b9a539c | 2020-06-15 22:31:10 | [diff] [blame] | 638 | WasmSym::memoryBase = createUndefinedGlobal( |
Wouter van Oortmerssen | 29f8c9f | 2020-07-06 20:34:16 | [diff] [blame] | 639 | "__memory_base", |
| 640 | config->is64.getValueOr(false) ? &globalTypeI64 : &globalTypeI32); |
Sam Clegg | fd11ce3 | 2019-07-11 13:13:25 | [diff] [blame] | 641 | WasmSym::tableBase = createUndefinedGlobal("__table_base", &globalTypeI32); |
| 642 | WasmSym::memoryBase->markLive(); |
| 643 | WasmSym::tableBase->markLive(); |
Sam Clegg | 2dad4e2 | 2018-11-15 18:15:54 | [diff] [blame] | 644 | } else { |
Sam Clegg | 2dad4e2 | 2018-11-15 18:15:54 | [diff] [blame] | 645 | // For non-PIC code |
Sam Clegg | 29a3056 | 2020-11-10 01:52:39 | [diff] [blame] | 646 | WasmSym::stackPointer = createGlobalVariable("__stack_pointer", true); |
Sam Clegg | ad1cc14 | 2019-08-08 18:22:03 | [diff] [blame] | 647 | WasmSym::stackPointer->markLive(); |
Sam Clegg | 2dad4e2 | 2018-11-15 18:15:54 | [diff] [blame] | 648 | } |
| 649 | |
Sam Clegg | 07b6aeb | 2020-12-18 18:02:29 | [diff] [blame] | 650 | if (config->sharedMemory && !config->relocatable) { |
Sam Clegg | 29a3056 | 2020-11-10 01:52:39 | [diff] [blame] | 651 | WasmSym::tlsBase = createGlobalVariable("__tls_base", true); |
| 652 | WasmSym::tlsSize = createGlobalVariable("__tls_size", false); |
| 653 | WasmSym::tlsAlign = createGlobalVariable("__tls_align", false); |
Guanzhong Chen | 42bba4b | 2019-07-16 22:00:45 | [diff] [blame] | 654 | WasmSym::initTLS = symtab->addSyntheticFunction( |
| 655 | "__wasm_init_tls", WASM_SYMBOL_VISIBILITY_HIDDEN, |
Wouter van Oortmerssen | 29f8c9f | 2020-07-06 20:34:16 | [diff] [blame] | 656 | make<SyntheticFunction>( |
| 657 | config->is64.getValueOr(false) ? i64ArgSignature : i32ArgSignature, |
| 658 | "__wasm_init_tls")); |
Guanzhong Chen | 42bba4b | 2019-07-16 22:00:45 | [diff] [blame] | 659 | } |
Sam Clegg | caa0db1 | 2019-08-08 16:58:36 | [diff] [blame] | 660 | } |
Guanzhong Chen | 42bba4b | 2019-07-16 22:00:45 | [diff] [blame] | 661 | |
Sam Clegg | caa0db1 | 2019-08-08 16:58:36 | [diff] [blame] | 662 | static void createOptionalSymbols() { |
Sam Clegg | dbfea28 | 2019-08-08 23:56:21 | [diff] [blame] | 663 | if (config->relocatable) |
| 664 | return; |
| 665 | |
| 666 | WasmSym::dsoHandle = symtab->addOptionalDataSymbol("__dso_handle"); |
Sam Clegg | caa0db1 | 2019-08-08 16:58:36 | [diff] [blame] | 667 | |
Guanzhong Chen | c5ccbf5 | 2019-08-08 22:40:04 | [diff] [blame] | 668 | if (!config->shared) |
Sam Clegg | caa0db1 | 2019-08-08 16:58:36 | [diff] [blame] | 669 | WasmSym::dataEnd = symtab->addOptionalDataSymbol("__data_end"); |
Guanzhong Chen | c5ccbf5 | 2019-08-08 22:40:04 | [diff] [blame] | 670 | |
| 671 | if (!config->isPic) { |
Sam Clegg | caa0db1 | 2019-08-08 16:58:36 | [diff] [blame] | 672 | WasmSym::globalBase = symtab->addOptionalDataSymbol("__global_base"); |
| 673 | WasmSym::heapBase = symtab->addOptionalDataSymbol("__heap_base"); |
Sam Clegg | 7185a73 | 2019-08-13 17:02:02 | [diff] [blame] | 674 | WasmSym::definedMemoryBase = symtab->addOptionalDataSymbol("__memory_base"); |
| 675 | WasmSym::definedTableBase = symtab->addOptionalDataSymbol("__table_base"); |
Sam Clegg | caa0db1 | 2019-08-08 16:58:36 | [diff] [blame] | 676 | } |
Sam Clegg | 29a3056 | 2020-11-10 01:52:39 | [diff] [blame] | 677 | |
| 678 | // For non-shared memory programs we still need to define __tls_base since we |
| 679 | // allow object files built with TLS to be linked into single threaded |
| 680 | // programs, and such object files can contains refernced to this symbol. |
| 681 | // |
| 682 | // However, in this case __tls_base is immutable and points directly to the |
| 683 | // start of the `.tdata` static segment. |
| 684 | // |
| 685 | // __tls_size and __tls_align are not needed in this case since they are only |
| 686 | // needed for __wasm_init_tls (which we do not create in this case). |
| 687 | if (!config->sharedMemory) |
| 688 | WasmSym::tlsBase = createOptionalGlobal("__tls_base", false); |
Sam Clegg | 2dad4e2 | 2018-11-15 18:15:54 | [diff] [blame] | 689 | } |
| 690 | |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 691 | // Reconstructs command line arguments so that so that you can re-run |
| 692 | // the same command with the same inputs. This is for --reproduce. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 693 | static std::string createResponseFile(const opt::InputArgList &args) { |
| 694 | SmallString<0> data; |
| 695 | raw_svector_ostream os(data); |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 696 | |
| 697 | // Copy the command line to the output while rewriting paths. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 698 | for (auto *arg : args) { |
| 699 | switch (arg->getOption().getID()) { |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 700 | case OPT_reproduce: |
| 701 | break; |
| 702 | case OPT_INPUT: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 703 | os << quote(relativeToRoot(arg->getValue())) << "\n"; |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 704 | break; |
| 705 | case OPT_o: |
| 706 | // If -o path contains directories, "lld @response.txt" will likely |
| 707 | // fail because the archive we are creating doesn't contain empty |
| 708 | // directories for the output path (-o doesn't create directories). |
| 709 | // Strip directories to prevent the issue. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 710 | os << "-o " << quote(sys::path::filename(arg->getValue())) << "\n"; |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 711 | break; |
| 712 | default: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 713 | os << toString(*arg) << "\n"; |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 714 | } |
| 715 | } |
Benjamin Kramer | adcd026 | 2020-01-28 19:23:46 | [diff] [blame] | 716 | return std::string(data.str()); |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 717 | } |
| 718 | |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 719 | // The --wrap option is a feature to rename symbols so that you can write |
| 720 | // wrappers for existing functions. If you pass `-wrap=foo`, all |
| 721 | // occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are |
| 722 | // expected to write `wrap_foo` function as a wrapper). The original |
| 723 | // symbol becomes accessible as `real_foo`, so you can call that from your |
| 724 | // wrapper. |
| 725 | // |
| 726 | // This data structure is instantiated for each -wrap option. |
| 727 | struct WrappedSymbol { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 728 | Symbol *sym; |
| 729 | Symbol *real; |
| 730 | Symbol *wrap; |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 731 | }; |
| 732 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 733 | static Symbol *addUndefined(StringRef name) { |
Sam Clegg | bd48127 | 2020-02-06 05:18:55 | [diff] [blame] | 734 | return symtab->addUndefinedFunction(name, None, None, WASM_SYMBOL_UNDEFINED, |
Sam Clegg | f6f4b98 | 2019-09-23 21:28:29 | [diff] [blame] | 735 | nullptr, nullptr, false); |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 736 | } |
| 737 | |
| 738 | // Handles -wrap option. |
| 739 | // |
| 740 | // This function instantiates wrapper symbols. At this point, they seem |
| 741 | // like they are not being used at all, so we explicitly set some flags so |
| 742 | // that LTO won't eliminate them. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 743 | static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &args) { |
| 744 | std::vector<WrappedSymbol> v; |
| 745 | DenseSet<StringRef> seen; |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 746 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 747 | for (auto *arg : args.filtered(OPT_wrap)) { |
| 748 | StringRef name = arg->getValue(); |
| 749 | if (!seen.insert(name).second) |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 750 | continue; |
| 751 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 752 | Symbol *sym = symtab->find(name); |
| 753 | if (!sym) |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 754 | continue; |
| 755 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 756 | Symbol *real = addUndefined(saver.save("__real_" + name)); |
| 757 | Symbol *wrap = addUndefined(saver.save("__wrap_" + name)); |
| 758 | v.push_back({sym, real, wrap}); |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 759 | |
| 760 | // We want to tell LTO not to inline symbols to be overwritten |
| 761 | // because LTO doesn't know the final symbol contents after renaming. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 762 | real->canInline = false; |
| 763 | sym->canInline = false; |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 764 | |
| 765 | // Tell LTO not to eliminate these symbols. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 766 | sym->isUsedInRegularObj = true; |
| 767 | wrap->isUsedInRegularObj = true; |
| 768 | real->isUsedInRegularObj = false; |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 769 | } |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 770 | return v; |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 771 | } |
| 772 | |
| 773 | // Do renaming for -wrap by updating pointers to symbols. |
| 774 | // |
| 775 | // When this function is executed, only InputFiles and symbol table |
| 776 | // contain pointers to symbol objects. We visit them to replace pointers, |
| 777 | // so that wrapped symbols are swapped as instructed by the command line. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 778 | static void wrapSymbols(ArrayRef<WrappedSymbol> wrapped) { |
| 779 | DenseMap<Symbol *, Symbol *> map; |
| 780 | for (const WrappedSymbol &w : wrapped) { |
| 781 | map[w.sym] = w.wrap; |
| 782 | map[w.real] = w.sym; |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 783 | } |
| 784 | |
| 785 | // Update pointers in input files. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 786 | parallelForEach(symtab->objectFiles, [&](InputFile *file) { |
| 787 | MutableArrayRef<Symbol *> syms = file->getMutableSymbols(); |
| 788 | for (size_t i = 0, e = syms.size(); i != e; ++i) |
| 789 | if (Symbol *s = map.lookup(syms[i])) |
| 790 | syms[i] = s; |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 791 | }); |
| 792 | |
| 793 | // Update pointers in the symbol table. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 794 | for (const WrappedSymbol &w : wrapped) |
| 795 | symtab->wrap(w.sym, w.real, w.wrap); |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 796 | } |
| 797 | |
Reshabh Sharma | fdd6ed8 | 2020-12-18 06:39:01 | [diff] [blame] | 798 | void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 799 | WasmOptTable parser; |
| 800 | opt::InputArgList args = parser.parse(argsArr.slice(1)); |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 801 | |
| 802 | // Handle --help |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 803 | if (args.hasArg(OPT_help)) { |
Rui Ueyama | b11386f | 2019-11-15 05:06:57 | [diff] [blame] | 804 | parser.PrintHelp(lld::outs(), |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 805 | (std::string(argsArr[0]) + " [options] file...").c_str(), |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 806 | "LLVM Linker", false); |
| 807 | return; |
| 808 | } |
| 809 | |
| 810 | // Handle --version |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 811 | if (args.hasArg(OPT_version) || args.hasArg(OPT_v)) { |
Rui Ueyama | b11386f | 2019-11-15 05:06:57 | [diff] [blame] | 812 | lld::outs() << getLLDVersion() << "\n"; |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 813 | return; |
| 814 | } |
| 815 | |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 816 | // Handle --reproduce |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 817 | if (auto *arg = args.getLastArg(OPT_reproduce)) { |
| 818 | StringRef path = arg->getValue(); |
| 819 | Expected<std::unique_ptr<TarWriter>> errOrWriter = |
| 820 | TarWriter::create(path, path::stem(path)); |
| 821 | if (errOrWriter) { |
| 822 | tar = std::move(*errOrWriter); |
| 823 | tar->append("response.txt", createResponseFile(args)); |
| 824 | tar->append("version.txt", getLLDVersion() + "\n"); |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 825 | } else { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 826 | error("--reproduce: " + toString(errOrWriter.takeError())); |
Rui Ueyama | 35150bb | 2019-05-21 11:52:14 | [diff] [blame] | 827 | } |
| 828 | } |
| 829 | |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 830 | // Parse and evaluate -mllvm options. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 831 | std::vector<const char *> v; |
| 832 | v.push_back("wasm-ld (LLVM option parsing)"); |
| 833 | for (auto *arg : args.filtered(OPT_mllvm)) |
| 834 | v.push_back(arg->getValue()); |
Alexandre Ganea | f2efb57 | 2020-09-24 19:00:43 | [diff] [blame] | 835 | cl::ResetAllOptionOccurrences(); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 836 | cl::ParseCommandLineOptions(v.size(), v.data()); |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 837 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 838 | errorHandler().errorLimit = args::getInteger(args, OPT_error_limit, 20); |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 839 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 840 | readConfigs(args); |
Sam Clegg | b576701 | 2020-03-28 00:03:32 | [diff] [blame] | 841 | |
| 842 | createFiles(args); |
| 843 | if (errorCount()) |
| 844 | return; |
| 845 | |
Sam Clegg | a1282a3 | 2019-05-08 16:20:05 | [diff] [blame] | 846 | setConfigs(); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 847 | checkOptions(args); |
Sam Clegg | b576701 | 2020-03-28 00:03:32 | [diff] [blame] | 848 | if (errorCount()) |
| 849 | return; |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 850 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 851 | if (auto *arg = args.getLastArg(OPT_allow_undefined_file)) |
| 852 | readImportFile(arg->getValue()); |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 853 | |
Sam Clegg | b576701 | 2020-03-28 00:03:32 | [diff] [blame] | 854 | // Fail early if the output file or map file is not writable. If a user has a |
| 855 | // long link, e.g. due to a large LTO link, they do not wish to run it and |
| 856 | // find that it failed because there was a mistake in their command-line. |
| 857 | if (auto e = tryCreateFile(config->outputFile)) |
| 858 | error("cannot open output file " + config->outputFile + ": " + e.message()); |
Sam Clegg | cc2da55 | 2020-03-27 23:52:27 | [diff] [blame] | 859 | if (auto e = tryCreateFile(config->mapFile)) |
| 860 | error("cannot open map file " + config->mapFile + ": " + e.message()); |
Sam Clegg | b576701 | 2020-03-28 00:03:32 | [diff] [blame] | 861 | if (errorCount()) |
Sam Clegg | d5f6506 | 2018-11-15 18:09:41 | [diff] [blame] | 862 | return; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 863 | |
Sam Clegg | 1f3f774 | 2019-02-06 02:35:18 | [diff] [blame] | 864 | // Handle --trace-symbol. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 865 | for (auto *arg : args.filtered(OPT_trace_symbol)) |
| 866 | symtab->trace(arg->getValue()); |
Sam Clegg | 1f3f774 | 2019-02-06 02:35:18 | [diff] [blame] | 867 | |
Sam Clegg | a6f4064 | 2021-04-05 15:00:30 | [diff] [blame^] | 868 | for (auto *arg : args.filtered(OPT_export_if_defined)) |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 869 | config->exportedSymbols.insert(arg->getValue()); |
Sam Clegg | 7d4ec5a | 2019-05-31 22:51:59 | [diff] [blame] | 870 | |
Sam Clegg | a6f4064 | 2021-04-05 15:00:30 | [diff] [blame^] | 871 | for (auto *arg : args.filtered(OPT_export)) { |
| 872 | config->exportedSymbols.insert(arg->getValue()); |
| 873 | config->requiredExports.push_back(arg->getValue()); |
| 874 | } |
| 875 | |
Sam Clegg | dbfea28 | 2019-08-08 23:56:21 | [diff] [blame] | 876 | createSyntheticSymbols(); |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 877 | |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 878 | // Add all files to the symbol table. This will add almost all |
| 879 | // symbols that we need to the symbol table. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 880 | for (InputFile *f : files) |
| 881 | symtab->addFile(f); |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 882 | if (errorCount()) |
| 883 | return; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 884 | |
Sam Clegg | 47e2b6b | 2018-08-04 00:04:06 | [diff] [blame] | 885 | // Handle the `--undefined <sym>` options. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 886 | for (auto *arg : args.filtered(OPT_undefined)) |
| 887 | handleUndefined(arg->getValue()); |
Sam Clegg | 47e2b6b | 2018-08-04 00:04:06 | [diff] [blame] | 888 | |
Sam Clegg | 7d4ec5a | 2019-05-31 22:51:59 | [diff] [blame] | 889 | // Handle the `--export <sym>` options |
| 890 | // This works like --undefined but also exports the symbol if its found |
Sam Clegg | a6f4064 | 2021-04-05 15:00:30 | [diff] [blame^] | 891 | for (auto &iter : config->exportedSymbols) |
| 892 | handleUndefined(iter.first()); |
Sam Clegg | 7d4ec5a | 2019-05-31 22:51:59 | [diff] [blame] | 893 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 894 | Symbol *entrySym = nullptr; |
| 895 | if (!config->relocatable && !config->entry.empty()) { |
| 896 | entrySym = handleUndefined(config->entry); |
| 897 | if (entrySym && entrySym->isDefined()) |
| 898 | entrySym->forceExport = true; |
Sam Clegg | 09137be | 2019-04-04 18:40:51 | [diff] [blame] | 899 | else |
Kazuaki Ishizaki | 7c5fcb3 | 2020-04-01 16:21:08 | [diff] [blame] | 900 | error("entry symbol not defined (pass --no-entry to suppress): " + |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 901 | config->entry); |
Sam Clegg | 47e2b6b | 2018-08-04 00:04:06 | [diff] [blame] | 902 | } |
| 903 | |
Dan Gohman | 6cd8511 | 2020-10-01 00:21:57 | [diff] [blame] | 904 | // If the user code defines a `__wasm_call_dtors` function, remember it so |
| 905 | // that we can call it from the command export wrappers. Unlike |
| 906 | // `__wasm_call_ctors` which we synthesize, `__wasm_call_dtors` is defined |
| 907 | // by libc/etc., because destructors are registered dynamically with |
| 908 | // `__cxa_atexit` and friends. |
| 909 | if (!config->relocatable && !config->shared && |
| 910 | !WasmSym::callCtors->isUsedInRegularObj && |
| 911 | WasmSym::callCtors->getName() != config->entry && |
| 912 | !config->exportedSymbols.count(WasmSym::callCtors->getName())) { |
| 913 | if (Symbol *callDtors = handleUndefined("__wasm_call_dtors")) { |
| 914 | if (auto *callDtorsFunc = dyn_cast<DefinedFunction>(callDtors)) { |
| 915 | if (callDtorsFunc->signature && |
| 916 | (!callDtorsFunc->signature->Params.empty() || |
| 917 | !callDtorsFunc->signature->Returns.empty())) { |
| 918 | error("__wasm_call_dtors must have no argument or return values"); |
| 919 | } |
| 920 | WasmSym::callDtors = callDtorsFunc; |
| 921 | } else { |
| 922 | error("__wasm_call_dtors must be a function"); |
| 923 | } |
| 924 | } |
| 925 | } |
| 926 | |
Sam Clegg | 040ef10 | 2019-08-27 04:27:57 | [diff] [blame] | 927 | createOptionalSymbols(); |
| 928 | |
Sam Clegg | 47e2b6b | 2018-08-04 00:04:06 | [diff] [blame] | 929 | if (errorCount()) |
| 930 | return; |
| 931 | |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 932 | // Create wrapped symbols for -wrap option. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 933 | std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args); |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 934 | |
Sam Clegg | 9cd9858 | 2019-12-20 01:23:59 | [diff] [blame] | 935 | // If any of our inputs are bitcode files, the LTO code generator may create |
| 936 | // references to certain library functions that might not be explicit in the |
| 937 | // bitcode file's symbol table. If any of those library functions are defined |
| 938 | // in a bitcode file in an archive member, we need to arrange to use LTO to |
| 939 | // compile those archive members by adding them to the link beforehand. |
| 940 | // |
| 941 | // We only need to add libcall symbols to the link before LTO if the symbol's |
| 942 | // definition is in bitcode. Any other required libcall symbols will be added |
| 943 | // to the link after LTO when we add the LTO object file to the link. |
| 944 | if (!symtab->bitcodeFiles.empty()) |
| 945 | for (auto *s : lto::LTO::getRuntimeLibcallSymbols()) |
| 946 | handleLibcall(s); |
| 947 | if (errorCount()) |
| 948 | return; |
| 949 | |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 950 | // Do link-time optimization if given files are LLVM bitcode files. |
| 951 | // This compiles bitcode files into real object files. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 952 | symtab->addCombinedLTOObject(); |
Sam Clegg | c729c1b | 2018-05-30 18:07:52 | [diff] [blame] | 953 | if (errorCount()) |
| 954 | return; |
| 955 | |
Sam Clegg | 6540e57 | 2019-02-20 23:19:31 | [diff] [blame] | 956 | // Resolve any variant symbols that were created due to signature |
| 957 | // mismatchs. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 958 | symtab->handleSymbolVariants(); |
Sam Clegg | 6540e57 | 2019-02-20 23:19:31 | [diff] [blame] | 959 | if (errorCount()) |
| 960 | return; |
| 961 | |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 962 | // Apply symbol renames for -wrap. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 963 | if (!wrapped.empty()) |
| 964 | wrapSymbols(wrapped); |
Sam Clegg | a5ca34e | 2019-05-24 14:14:25 | [diff] [blame] | 965 | |
Sam Clegg | a6f4064 | 2021-04-05 15:00:30 | [diff] [blame^] | 966 | for (auto &iter : config->exportedSymbols) { |
| 967 | Symbol *sym = symtab->find(iter.first()); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 968 | if (sym && sym->isDefined()) |
| 969 | sym->forceExport = true; |
Sam Clegg | 6540e57 | 2019-02-20 23:19:31 | [diff] [blame] | 970 | } |
| 971 | |
Sam Clegg | e1617d2 | 2021-02-12 16:59:21 | [diff] [blame] | 972 | if (!config->relocatable && !config->isPic) { |
Sam Clegg | 6540e57 | 2019-02-20 23:19:31 | [diff] [blame] | 973 | // Add synthetic dummies for weak undefined functions. Must happen |
| 974 | // after LTO otherwise functions may not yet have signatures. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 975 | symtab->handleWeakUndefines(); |
Sam Clegg | 6540e57 | 2019-02-20 23:19:31 | [diff] [blame] | 976 | } |
| 977 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 978 | if (entrySym) |
| 979 | entrySym->setHidden(false); |
Sam Clegg | 0f0a428 | 2018-01-20 01:44:45 | [diff] [blame] | 980 | |
Sam Clegg | 2c096ba | 2017-12-08 17:58:25 | [diff] [blame] | 981 | if (errorCount()) |
| 982 | return; |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 983 | |
Sam Clegg | 0362633 | 2018-01-31 01:45:47 | [diff] [blame] | 984 | // Do size optimizations: garbage collection |
Sam Clegg | ffd0aaf | 2018-06-22 15:13:10 | [diff] [blame] | 985 | markLive(); |
Sam Clegg | 0362633 | 2018-01-31 01:45:47 | [diff] [blame] | 986 | |
Andy Wingo | e638d8b | 2021-03-03 10:13:25 | [diff] [blame] | 987 | // Provide the indirect function table if needed. |
| 988 | WasmSym::indirectFunctionTable = |
| 989 | symtab->resolveIndirectFunctionTable(/*required =*/false); |
Andy Wingo | 6339382 | 2021-01-14 09:15:56 | [diff] [blame] | 990 | |
Andy Wingo | 48219d0 | 2021-02-16 12:28:44 | [diff] [blame] | 991 | if (errorCount()) |
| 992 | return; |
Andy Wingo | 6339382 | 2021-01-14 09:15:56 | [diff] [blame] | 993 | |
Sam Clegg | c94d393 | 2017-11-17 18:14:09 | [diff] [blame] | 994 | // Write the result to the file. |
| 995 | writeResult(); |
| 996 | } |
Fangrui Song | 33c59ab | 2019-10-10 05:25:39 | [diff] [blame] | 997 | |
| 998 | } // namespace wasm |
| 999 | } // namespace lld |