Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [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 |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 9 | #include "Driver.h" |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 10 | #include "COFFLinkerContext.h" |
Rui Ueyama | 1d99ab3 | 2016-09-15 22:24:51 | [diff] [blame] | 11 | #include "Config.h" |
Nico Weber | 1dc2123 | 2019-06-12 11:32:43 | [diff] [blame] | 12 | #include "DebugTypes.h" |
Sam Clegg | f187c4d | 2018-02-20 22:09:59 | [diff] [blame] | 13 | #include "ICF.h" |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 14 | #include "InputFiles.h" |
Sam Clegg | f187c4d | 2018-02-20 22:09:59 | [diff] [blame] | 15 | #include "MarkLive.h" |
Martin Storsjo | e1f894d | 2017-10-19 19:49:38 | [diff] [blame] | 16 | #include "MinGW.h" |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 17 | #include "SymbolTable.h" |
Rui Ueyama | 685c41c | 2015-08-05 23:43:53 | [diff] [blame] | 18 | #include "Symbols.h" |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 19 | #include "Writer.h" |
Rui Ueyama | 57175aa | 2018-01-27 00:34:46 | [diff] [blame] | 20 | #include "lld/Common/Args.h" |
Fangrui Song | 6b9a80d | 2022-12-28 18:46:45 | [diff] [blame] | 21 | #include "lld/Common/CommonLinkerContext.h" |
Rui Ueyama | 3f85170 | 2017-10-02 21:00:41 | [diff] [blame] | 22 | #include "lld/Common/Driver.h" |
Rui Ueyama | 7fd99fc | 2019-03-11 16:30:55 | [diff] [blame] | 23 | #include "lld/Common/Filesystem.h" |
Zachary Turner | 727f153 | 2018-01-17 19:16:26 | [diff] [blame] | 24 | #include "lld/Common/Timer.h" |
Rui Ueyama | a4cf97b | 2017-10-23 14:57:53 | [diff] [blame] | 25 | #include "lld/Common/Version.h" |
serge-sans-paille | f06d487 | 2022-03-09 21:27:35 | [diff] [blame] | 26 | #include "llvm/ADT/IntrusiveRefCntPtr.h" |
Saleem Abdulrasool | a2cca7e | 2016-08-08 22:02:44 | [diff] [blame] | 27 | #include "llvm/ADT/StringSwitch.h" |
Zachary Turner | 264b5d9 | 2017-06-07 03:48:56 | [diff] [blame] | 28 | #include "llvm/BinaryFormat/Magic.h" |
Arthur Eubanks | fed7565 | 2020-12-08 18:21:17 | [diff] [blame] | 29 | #include "llvm/Config/llvm-config.h" |
Steven Wu | dd63b9f | 2019-09-16 18:49:57 | [diff] [blame] | 30 | #include "llvm/LTO/LTO.h" |
Rui Ueyama | e1bf136 | 2017-03-16 21:19:36 | [diff] [blame] | 31 | #include "llvm/Object/ArchiveWriter.h" |
Reid Kleckner | 146eb7a | 2017-06-02 17:53:06 | [diff] [blame] | 32 | #include "llvm/Object/COFFImportFile.h" |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 33 | #include "llvm/Option/Arg.h" |
| 34 | #include "llvm/Option/ArgList.h" |
| 35 | #include "llvm/Option/Option.h" |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 36 | #include "llvm/Support/BinaryStreamReader.h" |
Reid Kleckner | 4c1a1d3 | 2019-11-14 23:15:48 | [diff] [blame] | 37 | #include "llvm/Support/CommandLine.h" |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 38 | #include "llvm/Support/Debug.h" |
Peter Collingbourne | ab03802 | 2018-08-23 17:44:42 | [diff] [blame] | 39 | #include "llvm/Support/LEB128.h" |
Rui Ueyama | e6a33e1 | 2019-08-07 10:16:21 | [diff] [blame] | 40 | #include "llvm/Support/MathExtras.h" |
Reid Kleckner | 932f027 | 2020-05-05 03:03:19 | [diff] [blame] | 41 | #include "llvm/Support/Parallel.h" |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 42 | #include "llvm/Support/Path.h" |
Rui Ueyama | 54b71da | 2015-05-31 19:17:12 | [diff] [blame] | 43 | #include "llvm/Support/Process.h" |
Rui Ueyama | 7f1f912 | 2017-01-06 02:33:53 | [diff] [blame] | 44 | #include "llvm/Support/TarWriter.h" |
Peter Collingbourne | 60c1616 | 2015-06-01 20:10:10 | [diff] [blame] | 45 | #include "llvm/Support/TargetSelect.h" |
Nikita Popov | 49ae2dc | 2024-06-20 15:41:35 | [diff] [blame] | 46 | #include "llvm/Support/TimeProfiler.h" |
serge-sans-paille | f06d487 | 2022-03-09 21:27:35 | [diff] [blame] | 47 | #include "llvm/Support/VirtualFileSystem.h" |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 48 | #include "llvm/Support/raw_ostream.h" |
Archibald Elliott | 62c7f03 | 2023-02-07 12:21:51 | [diff] [blame] | 49 | #include "llvm/TargetParser/Triple.h" |
Peter Collingbourne | c6f07c4 | 2017-05-13 22:06:46 | [diff] [blame] | 50 | #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" |
Rui Ueyama | 2bf6a12 | 2015-06-14 21:50:50 | [diff] [blame] | 51 | #include <algorithm> |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 52 | #include <future> |
Sam Clegg | f187c4d | 2018-02-20 22:09:59 | [diff] [blame] | 53 | #include <memory> |
Kazu Hirata | fd8d0b0 | 2022-11-27 04:53:26 | [diff] [blame] | 54 | #include <optional> |
Ivan Tadeu Ferreira Antunes Filho | 73fd9d3 | 2023-04-04 16:57:53 | [diff] [blame] | 55 | #include <tuple> |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 56 | |
Fangrui Song | 982575fd | 2024-12-04 04:51:50 | [diff] [blame] | 57 | using namespace lld; |
| 58 | using namespace lld::coff; |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 59 | using namespace llvm; |
Reid Kleckner | 146eb7a | 2017-06-02 17:53:06 | [diff] [blame] | 60 | using namespace llvm::object; |
Rui Ueyama | 84936e0 | 2015-07-07 23:39:18 | [diff] [blame] | 61 | using namespace llvm::COFF; |
Nico Weber | e6d1f26 | 2021-02-22 19:29:55 | [diff] [blame] | 62 | using namespace llvm::sys; |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 63 | |
Fangrui Song | 982575fd | 2024-12-04 04:51:50 | [diff] [blame] | 64 | COFFSyncStream::COFFSyncStream(COFFLinkerContext &ctx, DiagLevel level) |
| 65 | : SyncStream(ctx.e, level), ctx(ctx) {} |
| 66 | |
| 67 | COFFSyncStream coff::Log(COFFLinkerContext &ctx) { |
| 68 | return {ctx, DiagLevel::Log}; |
| 69 | } |
| 70 | COFFSyncStream coff::Msg(COFFLinkerContext &ctx) { |
| 71 | return {ctx, DiagLevel::Msg}; |
| 72 | } |
| 73 | COFFSyncStream coff::Warn(COFFLinkerContext &ctx) { |
| 74 | return {ctx, DiagLevel::Warn}; |
| 75 | } |
| 76 | COFFSyncStream coff::Err(COFFLinkerContext &ctx) { |
| 77 | return {ctx, DiagLevel::Err}; |
| 78 | } |
| 79 | COFFSyncStream coff::Fatal(COFFLinkerContext &ctx) { |
| 80 | return {ctx, DiagLevel::Fatal}; |
| 81 | } |
| 82 | uint64_t coff::errCount(COFFLinkerContext &ctx) { return ctx.e.errorCount; } |
| 83 | |
Nico Weber | 7c26641 | 2022-08-08 15:32:26 | [diff] [blame] | 84 | namespace lld::coff { |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 85 | |
Alexandre Ganea | 83d59e0 | 2022-01-20 19:53:18 | [diff] [blame] | 86 | bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, |
| 87 | llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { |
Alexandre Ganea | 6f2e92c | 2023-06-19 11:32:34 | [diff] [blame] | 88 | // This driver-specific context will be freed later by unsafeLldMain(). |
Alexandre Ganea | 83d59e0 | 2022-01-20 19:53:18 | [diff] [blame] | 89 | auto *ctx = new COFFLinkerContext; |
James Y Knight | d3fec7f | 2019-11-20 15:08:18 | [diff] [blame] | 90 | |
Alexandre Ganea | 83d59e0 | 2022-01-20 19:53:18 | [diff] [blame] | 91 | ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); |
| 92 | ctx->e.logName = args::getFilenameWithoutExe(args[0]); |
| 93 | ctx->e.errorLimitExceededMsg = "too many errors emitted, stopping now" |
| 94 | " (use /errorlimit:0 to see all errors)"; |
Alexandre Ganea | f2efb57 | 2020-09-24 19:00:43 | [diff] [blame] | 95 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 96 | ctx->driver.linkerMain(args); |
Rui Ueyama | 6f4e255 | 2017-10-23 20:03:32 | [diff] [blame] | 97 | |
Fangrui Song | 982575fd | 2024-12-04 04:51:50 | [diff] [blame] | 98 | return errCount(*ctx) == 0; |
Rui Ueyama | a9cbbf8 | 2015-05-31 19:17:09 | [diff] [blame] | 99 | } |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 100 | |
Bob Haarman | 5011b83 | 2019-07-11 18:48:58 | [diff] [blame] | 101 | // Parse options of the form "old;new". |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 102 | static std::pair<StringRef, StringRef> |
| 103 | getOldNewOptions(COFFLinkerContext &ctx, opt::InputArgList &args, unsigned id) { |
Bob Haarman | 5011b83 | 2019-07-11 18:48:58 | [diff] [blame] | 104 | auto *arg = args.getLastArg(id); |
| 105 | if (!arg) |
| 106 | return {"", ""}; |
| 107 | |
| 108 | StringRef s = arg->getValue(); |
| 109 | std::pair<StringRef, StringRef> ret = s.split(';'); |
| 110 | if (ret.second.empty()) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 111 | Err(ctx) << arg->getSpelling() << " expects 'old;new' format, but got " |
| 112 | << s; |
Bob Haarman | 5011b83 | 2019-07-11 18:48:58 | [diff] [blame] | 113 | return ret; |
| 114 | } |
| 115 | |
Ivan Tadeu Ferreira Antunes Filho | 73fd9d3 | 2023-04-04 16:57:53 | [diff] [blame] | 116 | // Parse options of the form "old;new[;extra]". |
| 117 | static std::tuple<StringRef, StringRef, StringRef> |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 118 | getOldNewOptionsExtra(COFFLinkerContext &ctx, opt::InputArgList &args, |
| 119 | unsigned id) { |
| 120 | auto [oldDir, second] = getOldNewOptions(ctx, args, id); |
Ivan Tadeu Ferreira Antunes Filho | 73fd9d3 | 2023-04-04 16:57:53 | [diff] [blame] | 121 | auto [newDir, extraDir] = second.split(';'); |
| 122 | return {oldDir, newDir, extraDir}; |
| 123 | } |
| 124 | |
Rui Ueyama | f95ed69 | 2019-11-13 04:53:15 | [diff] [blame] | 125 | // Drop directory components and replace extension with |
| 126 | // ".exe", ".dll" or ".sys". |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 127 | static std::string getOutputPath(StringRef path, bool isDll, bool isDriver) { |
Rui Ueyama | f95ed69 | 2019-11-13 04:53:15 | [diff] [blame] | 128 | StringRef ext = ".exe"; |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 129 | if (isDll) |
Rui Ueyama | f95ed69 | 2019-11-13 04:53:15 | [diff] [blame] | 130 | ext = ".dll"; |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 131 | else if (isDriver) |
Rui Ueyama | f95ed69 | 2019-11-13 04:53:15 | [diff] [blame] | 132 | ext = ".sys"; |
| 133 | |
| 134 | return (sys::path::stem(path) + ext).str(); |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 135 | } |
| 136 | |
Martin Storsjo | cdf126e | 2019-04-15 10:57:44 | [diff] [blame] | 137 | // Returns true if S matches /crtend.?\.o$/. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 138 | static bool isCrtend(StringRef s) { |
Kazu Hirata | 9ed46fb | 2024-09-23 03:45:25 | [diff] [blame] | 139 | if (!s.consume_back(".o")) |
Martin Storsjo | cdf126e | 2019-04-15 10:57:44 | [diff] [blame] | 140 | return false; |
Fangrui Song | 8d85c96 | 2023-06-05 21:36:19 | [diff] [blame] | 141 | if (s.ends_with("crtend")) |
Martin Storsjo | cdf126e | 2019-04-15 10:57:44 | [diff] [blame] | 142 | return true; |
Fangrui Song | 8d85c96 | 2023-06-05 21:36:19 | [diff] [blame] | 143 | return !s.empty() && s.drop_back().ends_with("crtend"); |
Martin Storsjo | cdf126e | 2019-04-15 10:57:44 | [diff] [blame] | 144 | } |
| 145 | |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 146 | // ErrorOr is not default constructible, so it cannot be used as the type |
| 147 | // parameter of a future. |
| 148 | // FIXME: We could open the file in createFutureForFile and avoid needing to |
| 149 | // return an error here, but for the moment that would cost us a file descriptor |
| 150 | // (a limited resource on Windows) for the duration that the future is pending. |
Rui Ueyama | 68b9f45 | 2019-04-01 00:11:24 | [diff] [blame] | 151 | using MBErrPair = std::pair<std::unique_ptr<MemoryBuffer>, std::error_code>; |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 152 | |
| 153 | // Create a std::future that opens and maps a file using the best strategy for |
| 154 | // the host platform. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 155 | static std::future<MBErrPair> createFutureForFile(std::string path) { |
Jeremy Drake | 7a7da69 | 2021-07-07 18:45:00 | [diff] [blame] | 156 | #if _WIN64 |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 157 | // On Windows, file I/O is relatively slow so it is best to do this |
Jeremy Drake | 7a7da69 | 2021-07-07 18:45:00 | [diff] [blame] | 158 | // asynchronously. But 32-bit has issues with potentially launching tons |
| 159 | // of threads |
Rui Ueyama | 77565f7 | 2019-07-11 06:56:44 | [diff] [blame] | 160 | auto strategy = std::launch::async; |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 161 | #else |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 162 | auto strategy = std::launch::deferred; |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 163 | #endif |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 164 | return std::async(strategy, [=]() { |
Abhina Sreeskantharajan | c83cd8f | 2021-03-25 13:47:25 | [diff] [blame] | 165 | auto mbOrErr = MemoryBuffer::getFile(path, /*IsText=*/false, |
| 166 | /*RequiresNullTerminator=*/false); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 167 | if (!mbOrErr) |
| 168 | return MBErrPair{nullptr, mbOrErr.getError()}; |
| 169 | return MBErrPair{std::move(*mbOrErr), std::error_code()}; |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 170 | }); |
| 171 | } |
| 172 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 173 | llvm::Triple::ArchType LinkerDriver::getArch() { |
Jacek Caban | ff56584 | 2024-04-04 12:25:54 | [diff] [blame] | 174 | return getMachineArchType(ctx.config.machine); |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 175 | } |
| 176 | |
Jacek Caban | 1bd5f34 | 2025-01-16 11:55:12 | [diff] [blame] | 177 | std::vector<Chunk *> LinkerDriver::getChunks() const { |
| 178 | std::vector<Chunk *> res; |
| 179 | for (ObjFile *file : ctx.objFileInstances) { |
| 180 | ArrayRef<Chunk *> v = file->getChunks(); |
| 181 | res.insert(res.end(), v.begin(), v.end()); |
| 182 | } |
| 183 | return res; |
| 184 | } |
| 185 | |
Jacek Caban | 8435225 | 2025-01-01 18:42:49 | [diff] [blame] | 186 | static bool compatibleMachineType(COFFLinkerContext &ctx, MachineTypes mt) { |
| 187 | if (mt == IMAGE_FILE_MACHINE_UNKNOWN) |
| 188 | return true; |
| 189 | switch (ctx.config.machine) { |
| 190 | case ARM64: |
| 191 | return mt == ARM64 || mt == ARM64X; |
| 192 | case ARM64EC: |
| 193 | return isArm64EC(mt) || mt == AMD64; |
| 194 | case ARM64X: |
| 195 | return isAnyArm64(mt) || mt == AMD64; |
| 196 | case IMAGE_FILE_MACHINE_UNKNOWN: |
| 197 | return true; |
| 198 | default: |
| 199 | return ctx.config.machine == mt; |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | void LinkerDriver::addFile(InputFile *file) { |
| 204 | Log(ctx) << "Reading " << toString(file); |
| 205 | if (file->lazy) { |
| 206 | if (auto *f = dyn_cast<BitcodeFile>(file)) |
| 207 | f->parseLazy(); |
| 208 | else |
| 209 | cast<ObjFile>(file)->parseLazy(); |
| 210 | } else { |
| 211 | file->parse(); |
| 212 | if (auto *f = dyn_cast<ObjFile>(file)) { |
| 213 | ctx.objFileInstances.push_back(f); |
| 214 | } else if (auto *f = dyn_cast<BitcodeFile>(file)) { |
| 215 | if (ltoCompilationDone) { |
| 216 | Err(ctx) << "LTO object file " << toString(file) |
| 217 | << " linked in after " |
| 218 | "doing LTO compilation."; |
| 219 | } |
Jacek Caban | b068f2f | 2025-01-17 10:36:12 | [diff] [blame] | 220 | f->symtab.bitcodeFileInstances.push_back(f); |
Jacek Caban | 8435225 | 2025-01-01 18:42:49 | [diff] [blame] | 221 | } else if (auto *f = dyn_cast<ImportFile>(file)) { |
| 222 | ctx.importFileInstances.push_back(f); |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | MachineTypes mt = file->getMachineType(); |
| 227 | // The ARM64EC target must be explicitly specified and cannot be inferred. |
| 228 | if (mt == ARM64EC && |
| 229 | (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN || |
| 230 | (ctx.config.machineInferred && |
| 231 | (ctx.config.machine == ARM64 || ctx.config.machine == AMD64)))) { |
| 232 | Err(ctx) << toString(file) |
| 233 | << ": machine type arm64ec is ambiguous and cannot be " |
| 234 | "inferred, use /machine:arm64ec or /machine:arm64x"; |
| 235 | return; |
| 236 | } |
| 237 | if (!compatibleMachineType(ctx, mt)) { |
| 238 | Err(ctx) << toString(file) << ": machine type " << machineToStr(mt) |
| 239 | << " conflicts with " << machineToStr(ctx.config.machine); |
| 240 | return; |
| 241 | } |
| 242 | if (ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN && |
| 243 | mt != IMAGE_FILE_MACHINE_UNKNOWN) { |
| 244 | ctx.config.machineInferred = true; |
| 245 | setMachine(mt); |
| 246 | } |
| 247 | |
| 248 | parseDirectives(file); |
| 249 | } |
| 250 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 251 | MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) { |
| 252 | MemoryBufferRef mbref = *mb; |
| 253 | make<std::unique_ptr<MemoryBuffer>>(std::move(mb)); // take ownership |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 254 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 255 | if (ctx.driver.tar) |
| 256 | ctx.driver.tar->append(relativeToRoot(mbref.getBufferIdentifier()), |
| 257 | mbref.getBuffer()); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 258 | return mbref; |
Rui Ueyama | 2bf6a12 | 2015-06-14 21:50:50 | [diff] [blame] | 259 | } |
Rui Ueyama | 711cd2d | 2015-05-31 21:17:10 | [diff] [blame] | 260 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 261 | void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb, |
Bob Haarman | 7dc5e7a0 | 2019-09-03 20:32:16 | [diff] [blame] | 262 | bool wholeArchive, bool lazy) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 263 | StringRef filename = mb->getBufferIdentifier(); |
Rui Ueyama | cdd5fb5 | 2018-03-01 23:11:30 | [diff] [blame] | 264 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 265 | MemoryBufferRef mbref = takeBuffer(std::move(mb)); |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 266 | |
Rui Ueyama | 711cd2d | 2015-05-31 21:17:10 | [diff] [blame] | 267 | // File type is detected by contents, not by file extension. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 268 | switch (identify_magic(mbref.getBuffer())) { |
Peter Collingbourne | 9362ac6 | 2017-10-16 23:15:04 | [diff] [blame] | 269 | case file_magic::windows_resource: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 270 | resources.push_back(mbref); |
Peter Collingbourne | 9362ac6 | 2017-10-16 23:15:04 | [diff] [blame] | 271 | break; |
Peter Collingbourne | 9362ac6 | 2017-10-16 23:15:04 | [diff] [blame] | 272 | case file_magic::archive: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 273 | if (wholeArchive) { |
| 274 | std::unique_ptr<Archive> file = |
| 275 | CHECK(Archive::create(mbref), filename + ": failed to parse archive"); |
Martin Storsjo | 90b4388 | 2019-08-01 18:47:27 | [diff] [blame] | 276 | Archive *archive = file.get(); |
| 277 | make<std::unique_ptr<Archive>>(std::move(file)); // take ownership |
Martin Storsjo | 8278ba5 | 2017-09-13 07:28:03 | [diff] [blame] | 278 | |
Rui Ueyama | 89efb03 | 2019-09-10 11:50:26 | [diff] [blame] | 279 | int memberIndex = 0; |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 280 | for (MemoryBufferRef m : getArchiveMembers(ctx, archive)) |
Rui Ueyama | 89efb03 | 2019-09-10 11:50:26 | [diff] [blame] | 281 | addArchiveBuffer(m, "<whole-archive>", filename, memberIndex++); |
Martin Storsjo | 8278ba5 | 2017-09-13 07:28:03 | [diff] [blame] | 282 | return; |
| 283 | } |
Jacek Caban | 8435225 | 2025-01-01 18:42:49 | [diff] [blame] | 284 | addFile(make<ArchiveFile>(ctx, mbref)); |
Peter Collingbourne | 9362ac6 | 2017-10-16 23:15:04 | [diff] [blame] | 285 | break; |
Peter Collingbourne | 9362ac6 | 2017-10-16 23:15:04 | [diff] [blame] | 286 | case file_magic::bitcode: |
Jacek Caban | b068f2f | 2025-01-17 10:36:12 | [diff] [blame] | 287 | addFile(BitcodeFile::create(ctx, mbref, "", 0, lazy)); |
Peter Collingbourne | 9362ac6 | 2017-10-16 23:15:04 | [diff] [blame] | 288 | break; |
Rui Ueyama | cdd5fb5 | 2018-03-01 23:11:30 | [diff] [blame] | 289 | case file_magic::coff_object: |
| 290 | case file_magic::coff_import_library: |
Jacek Caban | 8435225 | 2025-01-01 18:42:49 | [diff] [blame] | 291 | addFile(ObjFile::create(ctx, mbref, lazy)); |
Peter Collingbourne | 9362ac6 | 2017-10-16 23:15:04 | [diff] [blame] | 292 | break; |
Alexandre Ganea | 9c78db6 | 2019-06-03 12:39:47 | [diff] [blame] | 293 | case file_magic::pdb: |
Jacek Caban | 8435225 | 2025-01-01 18:42:49 | [diff] [blame] | 294 | addFile(make<PDBInputFile>(ctx, mbref)); |
Alexandre Ganea | 9c78db6 | 2019-06-03 12:39:47 | [diff] [blame] | 295 | break; |
Rui Ueyama | cdd5fb5 | 2018-03-01 23:11:30 | [diff] [blame] | 296 | case file_magic::coff_cl_gl_object: |
Fangrui Song | 982575fd | 2024-12-04 04:51:50 | [diff] [blame] | 297 | Err(ctx) << filename |
| 298 | << ": is not a native COFF file. Recompile without /GL"; |
Rui Ueyama | cdd5fb5 | 2018-03-01 23:11:30 | [diff] [blame] | 299 | break; |
| 300 | case file_magic::pecoff_executable: |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 301 | if (ctx.config.mingw) { |
Jacek Caban | 8435225 | 2025-01-01 18:42:49 | [diff] [blame] | 302 | addFile(make<DLLFile>(ctx.symtab, mbref)); |
Martin Storsjö | a9ff1ce | 2021-06-16 13:59:46 | [diff] [blame] | 303 | break; |
| 304 | } |
Kazu Hirata | ed1539c | 2023-05-16 17:12:42 | [diff] [blame] | 305 | if (filename.ends_with_insensitive(".dll")) { |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 306 | Err(ctx) << filename |
| 307 | << ": bad file type. Did you specify a DLL instead of an " |
| 308 | "import library?"; |
Rui Ueyama | cdd5fb5 | 2018-03-01 23:11:30 | [diff] [blame] | 309 | break; |
| 310 | } |
Fangrui Song | ec04e45 | 2022-08-07 00:02:35 | [diff] [blame] | 311 | [[fallthrough]]; |
Rui Ueyama | cdd5fb5 | 2018-03-01 23:11:30 | [diff] [blame] | 312 | default: |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 313 | Err(ctx) << mbref.getBufferIdentifier() << ": unknown file type"; |
Rui Ueyama | cdd5fb5 | 2018-03-01 23:11:30 | [diff] [blame] | 314 | break; |
Peter Collingbourne | 9362ac6 | 2017-10-16 23:15:04 | [diff] [blame] | 315 | } |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 316 | } |
| 317 | |
Bob Haarman | 7dc5e7a0 | 2019-09-03 20:32:16 | [diff] [blame] | 318 | void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) { |
Benjamin Kramer | adcd026 | 2020-01-28 19:23:46 | [diff] [blame] | 319 | auto future = std::make_shared<std::future<MBErrPair>>( |
| 320 | createFutureForFile(std::string(path))); |
| 321 | std::string pathStr = std::string(path); |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 322 | enqueueTask([=]() { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 323 | llvm::TimeTraceScope timeScope("File: ", path); |
Arthur Eubanks | c8ea669 | 2023-05-31 15:52:21 | [diff] [blame] | 324 | auto [mb, ec] = future->get(); |
| 325 | if (ec) { |
| 326 | // Retry reading the file (synchronously) now that we may have added |
| 327 | // winsysroot search paths from SymbolTable::addFile(). |
| 328 | // Retrying synchronously is important for keeping the order of inputs |
| 329 | // consistent. |
| 330 | // This makes it so that if the user passes something in the winsysroot |
| 331 | // before something we can find with an architecture, we won't find the |
| 332 | // winsysroot file. |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 333 | if (std::optional<StringRef> retryPath = findFileIfNew(pathStr)) { |
Arthur Eubanks | c8ea669 | 2023-05-31 15:52:21 | [diff] [blame] | 334 | auto retryMb = MemoryBuffer::getFile(*retryPath, /*IsText=*/false, |
| 335 | /*RequiresNullTerminator=*/false); |
| 336 | ec = retryMb.getError(); |
| 337 | if (!ec) |
| 338 | mb = std::move(*retryMb); |
Arthur Eubanks | ec1998c | 2023-06-05 21:32:55 | [diff] [blame] | 339 | } else { |
| 340 | // We've already handled this file. |
| 341 | return; |
Arthur Eubanks | c8ea669 | 2023-05-31 15:52:21 | [diff] [blame] | 342 | } |
| 343 | } |
| 344 | if (ec) { |
| 345 | std::string msg = "could not open '" + pathStr + "': " + ec.message(); |
Nico Weber | 9b2830b | 2019-05-23 17:58:33 | [diff] [blame] | 346 | // Check if the filename is a typo for an option flag. OptTable thinks |
| 347 | // that all args that are not known options and that start with / are |
| 348 | // filenames, but e.g. `/nodefaultlibs` is more likely a typo for |
| 349 | // the option `/nodefaultlib` than a reference to a file in the root |
| 350 | // directory. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 351 | std::string nearest; |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 352 | if (ctx.optTable.findNearest(pathStr, nearest) > 1) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 353 | Err(ctx) << msg; |
Nico Weber | 9b2830b | 2019-05-23 17:58:33 | [diff] [blame] | 354 | else |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 355 | Err(ctx) << msg << "; did you mean '" << nearest << "'"; |
Nico Weber | 9b2830b | 2019-05-23 17:58:33 | [diff] [blame] | 356 | } else |
Arthur Eubanks | c8ea669 | 2023-05-31 15:52:21 | [diff] [blame] | 357 | ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy); |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 358 | }); |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 359 | } |
| 360 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 361 | void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName, |
| 362 | StringRef parentName, |
| 363 | uint64_t offsetInArchive) { |
| 364 | file_magic magic = identify_magic(mb.getBuffer()); |
| 365 | if (magic == file_magic::coff_import_library) { |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 366 | InputFile *imp = make<ImportFile>(ctx, mb); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 367 | imp->parentName = parentName; |
Jacek Caban | 8435225 | 2025-01-01 18:42:49 | [diff] [blame] | 368 | addFile(imp); |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 369 | return; |
| 370 | } |
| 371 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 372 | InputFile *obj; |
| 373 | if (magic == file_magic::coff_object) { |
Jacek Caban | 9c8214f | 2024-12-17 18:26:13 | [diff] [blame] | 374 | obj = ObjFile::create(ctx, mb); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 375 | } else if (magic == file_magic::bitcode) { |
Jacek Caban | b068f2f | 2025-01-17 10:36:12 | [diff] [blame] | 376 | obj = BitcodeFile::create(ctx, mb, parentName, offsetInArchive, |
| 377 | /*lazy=*/false); |
Pengxuan Zheng | c951edb | 2022-08-09 00:49:08 | [diff] [blame] | 378 | } else if (magic == file_magic::coff_cl_gl_object) { |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 379 | Err(ctx) << mb.getBufferIdentifier() |
| 380 | << ": is not a native COFF file. Recompile without /GL?"; |
Pengxuan Zheng | c951edb | 2022-08-09 00:49:08 | [diff] [blame] | 381 | return; |
Bob Haarman | ac8f7fc | 2017-04-05 00:43:54 | [diff] [blame] | 382 | } else { |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 383 | Err(ctx) << "unknown file type: " << mb.getBufferIdentifier(); |
Bob Haarman | ac8f7fc | 2017-04-05 00:43:54 | [diff] [blame] | 384 | return; |
| 385 | } |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 386 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 387 | obj->parentName = parentName; |
Jacek Caban | 8435225 | 2025-01-01 18:42:49 | [diff] [blame] | 388 | addFile(obj); |
Fangrui Song | 982575fd | 2024-12-04 04:51:50 | [diff] [blame] | 389 | Log(ctx) << "Loaded " << obj << " for " << symName; |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 390 | } |
| 391 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 392 | void LinkerDriver::enqueueArchiveMember(const Archive::Child &c, |
Nico Weber | cb2c500 | 2019-07-19 13:29:10 | [diff] [blame] | 393 | const Archive::Symbol &sym, |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 394 | StringRef parentName) { |
Bob Haarman | 3edf63c | 2019-02-08 21:59:35 | [diff] [blame] | 395 | |
Nico Weber | cb2c500 | 2019-07-19 13:29:10 | [diff] [blame] | 396 | auto reportBufferError = [=](Error &&e, StringRef childName) { |
Fangrui Song | 982575fd | 2024-12-04 04:51:50 | [diff] [blame] | 397 | Fatal(ctx) << "could not get the buffer for the member defining symbol " |
| 398 | << &sym << ": " << parentName << "(" << childName |
| 399 | << "): " << std::move(e); |
Bob Haarman | 3edf63c | 2019-02-08 21:59:35 | [diff] [blame] | 400 | }; |
| 401 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 402 | if (!c.getParent()->isThin()) { |
| 403 | uint64_t offsetInArchive = c.getChildOffset(); |
| 404 | Expected<MemoryBufferRef> mbOrErr = c.getMemoryBufferRef(); |
| 405 | if (!mbOrErr) |
| 406 | reportBufferError(mbOrErr.takeError(), check(c.getFullName())); |
| 407 | MemoryBufferRef mb = mbOrErr.get(); |
Bob Haarman | 8b1ec79 | 2019-04-15 19:48:32 | [diff] [blame] | 408 | enqueueTask([=]() { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 409 | llvm::TimeTraceScope timeScope("Archive: ", mb.getBufferIdentifier()); |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 410 | ctx.driver.addArchiveBuffer(mb, toCOFFString(ctx, sym), parentName, |
| 411 | offsetInArchive); |
Bob Haarman | 8b1ec79 | 2019-04-15 19:48:32 | [diff] [blame] | 412 | }); |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 413 | return; |
| 414 | } |
| 415 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 416 | std::string childName = |
| 417 | CHECK(c.getFullName(), |
| 418 | "could not get the filename for the member defining symbol " + |
| 419 | toCOFFString(ctx, sym)); |
Matheus Izvekov | a5e280b | 2023-09-21 11:16:11 | [diff] [blame] | 420 | auto future = |
| 421 | std::make_shared<std::future<MBErrPair>>(createFutureForFile(childName)); |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 422 | enqueueTask([=]() { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 423 | auto mbOrErr = future->get(); |
| 424 | if (mbOrErr.second) |
| 425 | reportBufferError(errorCodeToError(mbOrErr.second), childName); |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 426 | llvm::TimeTraceScope timeScope("Archive: ", |
| 427 | mbOrErr.first->getBufferIdentifier()); |
Amy Huang | 227d859 | 2019-09-12 22:04:56 | [diff] [blame] | 428 | // Pass empty string as archive name so that the original filename is |
| 429 | // used as the buffer identifier. |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 430 | ctx.driver.addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)), |
| 431 | toCOFFString(ctx, sym), "", |
| 432 | /*OffsetInArchive=*/0); |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 433 | }); |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 434 | } |
| 435 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 436 | bool LinkerDriver::isDecorated(StringRef sym) { |
Fangrui Song | 8d85c96 | 2023-06-05 21:36:19 | [diff] [blame] | 437 | return sym.starts_with("@") || sym.contains("@@") || sym.starts_with("?") || |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 438 | (!ctx.config.mingw && sym.contains('@')); |
Rui Ueyama | f10a320 | 2015-08-31 08:43:21 | [diff] [blame] | 439 | } |
| 440 | |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 441 | // Parses .drectve section contents and returns a list of files |
| 442 | // specified by /defaultlib. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 443 | void LinkerDriver::parseDirectives(InputFile *file) { |
| 444 | StringRef s = file->getDirectives(); |
| 445 | if (s.empty()) |
Alexandre Ganea | d8ec810 | 2019-03-06 20:18:38 | [diff] [blame] | 446 | return; |
| 447 | |
Fangrui Song | 982575fd | 2024-12-04 04:51:50 | [diff] [blame] | 448 | Log(ctx) << "Directives: " << file << ": " << s; |
Alexandre Ganea | d8ec810 | 2019-03-06 20:18:38 | [diff] [blame] | 449 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 450 | ArgParser parser(ctx); |
Nico Weber | a05cbb8 | 2017-09-05 23:46:45 | [diff] [blame] | 451 | // .drectve is always tokenized using Windows shell rules. |
Rui Ueyama | 5fa0d6e | 2018-01-09 20:36:42 | [diff] [blame] | 452 | // /EXPORT: option can appear too many times, processing in fastpath. |
Reid Kleckner | 01b5f52 | 2020-04-25 00:26:17 | [diff] [blame] | 453 | ParsedDirectives directives = parser.parseDirectives(s); |
Rui Ueyama | 5fa0d6e | 2018-01-09 20:36:42 | [diff] [blame] | 454 | |
Reid Kleckner | 01b5f52 | 2020-04-25 00:26:17 | [diff] [blame] | 455 | for (StringRef e : directives.exports) { |
Rui Ueyama | 5fa0d6e | 2018-01-09 20:36:42 | [diff] [blame] | 456 | // If a common header file contains dllexported function |
| 457 | // declarations, many object files may end up with having the |
| 458 | // same /EXPORT options. In order to save cost of parsing them, |
| 459 | // we dedup them first. |
Jacek Caban | 455b3d6 | 2025-01-21 09:41:15 | [diff] [blame] | 460 | if (!file->symtab.directivesExports.insert(e).second) |
Rui Ueyama | 5fa0d6e | 2018-01-09 20:36:42 | [diff] [blame] | 461 | continue; |
| 462 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 463 | Export exp = parseExport(e); |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 464 | if (ctx.config.machine == I386 && ctx.config.mingw) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 465 | if (!isDecorated(exp.name)) |
Alexandre Ganea | 83d59e0 | 2022-01-20 19:53:18 | [diff] [blame] | 466 | exp.name = saver().save("_" + exp.name); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 467 | if (!exp.extName.empty() && !isDecorated(exp.extName)) |
Alexandre Ganea | 83d59e0 | 2022-01-20 19:53:18 | [diff] [blame] | 468 | exp.extName = saver().save("_" + exp.extName); |
Rui Ueyama | 5fa0d6e | 2018-01-09 20:36:42 | [diff] [blame] | 469 | } |
Alexandre Ganea | adcdc9c | 2023-06-13 19:12:55 | [diff] [blame] | 470 | exp.source = ExportSource::Directives; |
Jacek Caban | 455b3d6 | 2025-01-21 09:41:15 | [diff] [blame] | 471 | file->symtab.exports.push_back(exp); |
Rui Ueyama | 5fa0d6e | 2018-01-09 20:36:42 | [diff] [blame] | 472 | } |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 473 | |
Reid Kleckner | 01b5f52 | 2020-04-25 00:26:17 | [diff] [blame] | 474 | // Handle /include: in bulk. |
| 475 | for (StringRef inc : directives.includes) |
Jacek Caban | 251ef3f | 2025-01-13 22:16:57 | [diff] [blame] | 476 | file->symtab.addGCRoot(inc); |
Reid Kleckner | 01b5f52 | 2020-04-25 00:26:17 | [diff] [blame] | 477 | |
Martin Storsjö | 5d513ef | 2022-07-17 21:11:37 | [diff] [blame] | 478 | // Handle /exclude-symbols: in bulk. |
| 479 | for (StringRef e : directives.excludes) { |
| 480 | SmallVector<StringRef, 2> vec; |
| 481 | e.split(vec, ','); |
| 482 | for (StringRef sym : vec) |
Jacek Caban | f22af59 | 2025-01-15 14:21:06 | [diff] [blame] | 483 | excludedSymbols.insert(file->symtab.mangle(sym)); |
Martin Storsjö | 5d513ef | 2022-07-17 21:11:37 | [diff] [blame] | 484 | } |
| 485 | |
Nico Weber | 400a1de | 2021-08-24 14:19:21 | [diff] [blame] | 486 | // https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=msvc-160 |
Reid Kleckner | 01b5f52 | 2020-04-25 00:26:17 | [diff] [blame] | 487 | for (auto *arg : directives.args) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 488 | switch (arg->getOption().getID()) { |
Martin Storsjo | d2752aa | 2017-08-14 19:07:27 | [diff] [blame] | 489 | case OPT_aligncomm: |
Jacek Caban | f2473bc | 2025-03-03 21:48:20 | [diff] [blame] | 490 | file->symtab.parseAligncomm(arg->getValue()); |
Martin Storsjo | d2752aa | 2017-08-14 19:07:27 | [diff] [blame] | 491 | break; |
Rui Ueyama | 562daa8 | 2015-06-18 21:50:38 | [diff] [blame] | 492 | case OPT_alternatename: |
Jacek Caban | 8616c87 | 2025-02-21 11:52:28 | [diff] [blame] | 493 | file->symtab.parseAlternateName(arg->getValue()); |
Rui Ueyama | 562daa8 | 2015-06-18 21:50:38 | [diff] [blame] | 494 | break; |
| 495 | case OPT_defaultlib: |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 496 | if (std::optional<StringRef> path = findLibIfNew(arg->getValue())) |
Bob Haarman | 7dc5e7a0 | 2019-09-03 20:32:16 | [diff] [blame] | 497 | enqueuePath(*path, false, false); |
Rui Ueyama | 562daa8 | 2015-06-18 21:50:38 | [diff] [blame] | 498 | break; |
Rui Ueyama | 215286f | 2017-11-29 20:46:13 | [diff] [blame] | 499 | case OPT_entry: |
Martin Storsjö | cb248f8 | 2024-06-24 17:02:39 | [diff] [blame] | 500 | if (!arg->getValue()[0]) |
Fangrui Song | 982575fd | 2024-12-04 04:51:50 | [diff] [blame] | 501 | Fatal(ctx) << "missing entry point symbol name"; |
Jacek Caban | d004947 | 2025-01-16 11:53:48 | [diff] [blame] | 502 | ctx.forEachSymtab([&](SymbolTable &symtab) { |
| 503 | symtab.entry = symtab.addGCRoot(symtab.mangle(arg->getValue()), true); |
| 504 | }); |
Rui Ueyama | 215286f | 2017-11-29 20:46:13 | [diff] [blame] | 505 | break; |
Rui Ueyama | 562daa8 | 2015-06-18 21:50:38 | [diff] [blame] | 506 | case OPT_failifmismatch: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 507 | checkFailIfMismatch(arg->getValue(), file); |
Rui Ueyama | 562daa8 | 2015-06-18 21:50:38 | [diff] [blame] | 508 | break; |
Rui Ueyama | 08d5e18 | 2015-06-18 23:20:11 | [diff] [blame] | 509 | case OPT_incl: |
Jacek Caban | 251ef3f | 2025-01-13 22:16:57 | [diff] [blame] | 510 | file->symtab.addGCRoot(arg->getValue()); |
Rui Ueyama | 08d5e18 | 2015-06-18 23:20:11 | [diff] [blame] | 511 | break; |
Nico Weber | 400a1de | 2021-08-24 14:19:21 | [diff] [blame] | 512 | case OPT_manifestdependency: |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 513 | ctx.config.manifestDependencies.insert(arg->getValue()); |
Nico Weber | 400a1de | 2021-08-24 14:19:21 | [diff] [blame] | 514 | break; |
Rui Ueyama | ce86c99 | 2015-06-18 23:22:39 | [diff] [blame] | 515 | case OPT_merge: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 516 | parseMerge(arg->getValue()); |
Rui Ueyama | ce86c99 | 2015-06-18 23:22:39 | [diff] [blame] | 517 | break; |
| 518 | case OPT_nodefaultlib: |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 519 | ctx.config.noDefaultLibs.insert(findLib(arg->getValue()).lower()); |
Rui Ueyama | ce86c99 | 2015-06-18 23:22:39 | [diff] [blame] | 520 | break; |
Qfrost | 3f55853 | 2023-01-02 09:20:15 | [diff] [blame] | 521 | case OPT_release: |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 522 | ctx.config.writeCheckSum = true; |
Qfrost | 3f55853 | 2023-01-02 09:20:15 | [diff] [blame] | 523 | break; |
Rui Ueyama | 440138c | 2016-06-20 03:39:39 | [diff] [blame] | 524 | case OPT_section: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 525 | parseSection(arg->getValue()); |
Rui Ueyama | 440138c | 2016-06-20 03:39:39 | [diff] [blame] | 526 | break; |
Alex Reinking | 7ac3fcc | 2021-05-05 22:54:17 | [diff] [blame] | 527 | case OPT_stack: |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 528 | parseNumbers(arg->getValue(), &ctx.config.stackReserve, |
| 529 | &ctx.config.stackCommit); |
Alex Reinking | 7ac3fcc | 2021-05-05 22:54:17 | [diff] [blame] | 530 | break; |
Martin Storsjö | 45c4c54 | 2020-10-03 22:29:45 | [diff] [blame] | 531 | case OPT_subsystem: { |
| 532 | bool gotVersion = false; |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 533 | parseSubsystem(arg->getValue(), &ctx.config.subsystem, |
| 534 | &ctx.config.majorSubsystemVersion, |
| 535 | &ctx.config.minorSubsystemVersion, &gotVersion); |
Martin Storsjö | 45c4c54 | 2020-10-03 22:29:45 | [diff] [blame] | 536 | if (gotVersion) { |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 537 | ctx.config.majorOSVersion = ctx.config.majorSubsystemVersion; |
| 538 | ctx.config.minorOSVersion = ctx.config.minorSubsystemVersion; |
Martin Storsjö | 45c4c54 | 2020-10-03 22:29:45 | [diff] [blame] | 539 | } |
Rui Ueyama | 215286f | 2017-11-29 20:46:13 | [diff] [blame] | 540 | break; |
Martin Storsjö | 45c4c54 | 2020-10-03 22:29:45 | [diff] [blame] | 541 | } |
Nico Weber | e7a67bf | 2019-07-09 13:30:03 | [diff] [blame] | 542 | // Only add flags here that link.exe accepts in |
| 543 | // `#pragma comment(linker, "/flag")`-generated sections. |
Rui Ueyama | 3c4737d | 2015-08-11 16:46:08 | [diff] [blame] | 544 | case OPT_editandcontinue: |
Rui Ueyama | 31e66e3 | 2015-09-03 16:20:47 | [diff] [blame] | 545 | case OPT_guardsym: |
Rui Ueyama | 43238317 | 2015-07-29 21:01:15 | [diff] [blame] | 546 | case OPT_throwingnew: |
Alvin Wong | 8fa0cfe | 2023-04-23 15:58:24 | [diff] [blame] | 547 | case OPT_inferasanlibs: |
| 548 | case OPT_inferasanlibs_no: |
Rui Ueyama | 4668263 | 2015-07-29 20:29:15 | [diff] [blame] | 549 | break; |
Rui Ueyama | 562daa8 | 2015-06-18 21:50:38 | [diff] [blame] | 550 | default: |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 551 | Err(ctx) << arg->getSpelling() << " is not allowed in .drectve (" |
| 552 | << toString(file) << ")"; |
Rui Ueyama | d7c2f58 | 2015-05-31 21:04:56 | [diff] [blame] | 553 | } |
| 554 | } |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 555 | } |
| 556 | |
Rui Ueyama | 54b71da | 2015-05-31 19:17:12 | [diff] [blame] | 557 | // Find file from search paths. You can omit ".obj", this function takes |
| 558 | // care of that. Note that the returned path is not guaranteed to exist. |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 559 | StringRef LinkerDriver::findFile(StringRef filename) { |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 560 | auto getFilename = [this](StringRef filename) -> StringRef { |
| 561 | if (ctx.config.vfs) |
| 562 | if (auto statOrErr = ctx.config.vfs->status(filename)) |
Alex Brachet | fd9962e | 2022-07-11 21:31:01 | [diff] [blame] | 563 | return saver().save(statOrErr->getName()); |
| 564 | return filename; |
| 565 | }; |
| 566 | |
Tobias Hieta | b6c2f10 | 2023-07-14 07:40:35 | [diff] [blame] | 567 | if (sys::path::is_absolute(filename)) |
Alex Brachet | fd9962e | 2022-07-11 21:31:01 | [diff] [blame] | 568 | return getFilename(filename); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 569 | bool hasExt = filename.contains('.'); |
| 570 | for (StringRef dir : searchPaths) { |
| 571 | SmallString<128> path = dir; |
| 572 | sys::path::append(path, filename); |
Alex Brachet | fd9962e | 2022-07-11 21:31:01 | [diff] [blame] | 573 | path = SmallString<128>{getFilename(path.str())}; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 574 | if (sys::fs::exists(path.str())) |
Alexandre Ganea | 83d59e0 | 2022-01-20 19:53:18 | [diff] [blame] | 575 | return saver().save(path.str()); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 576 | if (!hasExt) { |
| 577 | path.append(".obj"); |
Alex Brachet | fd9962e | 2022-07-11 21:31:01 | [diff] [blame] | 578 | path = SmallString<128>{getFilename(path.str())}; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 579 | if (sys::fs::exists(path.str())) |
Alexandre Ganea | 83d59e0 | 2022-01-20 19:53:18 | [diff] [blame] | 580 | return saver().save(path.str()); |
Rui Ueyama | 54b71da | 2015-05-31 19:17:12 | [diff] [blame] | 581 | } |
| 582 | } |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 583 | return filename; |
Rui Ueyama | 54b71da | 2015-05-31 19:17:12 | [diff] [blame] | 584 | } |
| 585 | |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 586 | static std::optional<sys::fs::UniqueID> getUniqueID(StringRef path) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 587 | sys::fs::UniqueID ret; |
| 588 | if (sys::fs::getUniqueID(path, ret)) |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 589 | return std::nullopt; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 590 | return ret; |
Rui Ueyama | 4eed6cc | 2018-06-12 21:47:31 | [diff] [blame] | 591 | } |
| 592 | |
Rui Ueyama | d21b00b | 2015-05-31 19:17:14 | [diff] [blame] | 593 | // Resolves a file path. This never returns the same path |
Kazu Hirata | d6684f2 | 2022-12-11 01:04:56 | [diff] [blame] | 594 | // (in that case, it returns std::nullopt). |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 595 | std::optional<StringRef> LinkerDriver::findFileIfNew(StringRef filename) { |
| 596 | StringRef path = findFile(filename); |
Rui Ueyama | 4eed6cc | 2018-06-12 21:47:31 | [diff] [blame] | 597 | |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 598 | if (std::optional<sys::fs::UniqueID> id = getUniqueID(path)) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 599 | bool seen = !visitedFiles.insert(*id).second; |
| 600 | if (seen) |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 601 | return std::nullopt; |
Rui Ueyama | 4eed6cc | 2018-06-12 21:47:31 | [diff] [blame] | 602 | } |
| 603 | |
Kazu Hirata | ed1539c | 2023-05-16 17:12:42 | [diff] [blame] | 604 | if (path.ends_with_insensitive(".lib")) |
Pengxuan Zheng | 9db61c3 | 2022-06-14 02:22:14 | [diff] [blame] | 605 | visitedLibs.insert(std::string(sys::path::filename(path).lower())); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 606 | return path; |
Rui Ueyama | 54b71da | 2015-05-31 19:17:12 | [diff] [blame] | 607 | } |
| 608 | |
Martin Storsjo | 33d43ff | 2018-10-10 09:00:10 | [diff] [blame] | 609 | // MinGW specific. If an embedded directive specified to link to |
| 610 | // foo.lib, but it isn't found, try libfoo.a instead. |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 611 | StringRef LinkerDriver::findLibMinGW(StringRef filename) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 612 | if (filename.contains('/') || filename.contains('\\')) |
| 613 | return filename; |
Martin Storsjo | 33d43ff | 2018-10-10 09:00:10 | [diff] [blame] | 614 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 615 | SmallString<128> s = filename; |
| 616 | sys::path::replace_extension(s, ".a"); |
Alexandre Ganea | 83d59e0 | 2022-01-20 19:53:18 | [diff] [blame] | 617 | StringRef libName = saver().save("lib" + s.str()); |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 618 | return findFile(libName); |
Martin Storsjo | 33d43ff | 2018-10-10 09:00:10 | [diff] [blame] | 619 | } |
| 620 | |
Rui Ueyama | d21b00b | 2015-05-31 19:17:14 | [diff] [blame] | 621 | // Find library file from search path. |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 622 | StringRef LinkerDriver::findLib(StringRef filename) { |
Rui Ueyama | d21b00b | 2015-05-31 19:17:14 | [diff] [blame] | 623 | // Add ".lib" to Filename if that has no file extension. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 624 | bool hasExt = filename.contains('.'); |
| 625 | if (!hasExt) |
Alexandre Ganea | 83d59e0 | 2022-01-20 19:53:18 | [diff] [blame] | 626 | filename = saver().save(filename + ".lib"); |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 627 | StringRef ret = findFile(filename); |
Martin Storsjo | 33d43ff | 2018-10-10 09:00:10 | [diff] [blame] | 628 | // For MinGW, if the find above didn't turn up anything, try |
| 629 | // looking for a MinGW formatted library name. |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 630 | if (ctx.config.mingw && ret == filename) |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 631 | return findLibMinGW(filename); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 632 | return ret; |
Rui Ueyama | d21b00b | 2015-05-31 19:17:14 | [diff] [blame] | 633 | } |
| 634 | |
| 635 | // Resolves a library path. /nodefaultlib options are taken into |
| 636 | // consideration. This never returns the same path (in that case, |
Kazu Hirata | d6684f2 | 2022-12-11 01:04:56 | [diff] [blame] | 637 | // it returns std::nullopt). |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 638 | std::optional<StringRef> LinkerDriver::findLibIfNew(StringRef filename) { |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 639 | if (ctx.config.noDefaultLibAll) |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 640 | return std::nullopt; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 641 | if (!visitedLibs.insert(filename.lower()).second) |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 642 | return std::nullopt; |
Rui Ueyama | 4eed6cc | 2018-06-12 21:47:31 | [diff] [blame] | 643 | |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 644 | StringRef path = findLib(filename); |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 645 | if (ctx.config.noDefaultLibs.count(path.lower())) |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 646 | return std::nullopt; |
Rui Ueyama | 4eed6cc | 2018-06-12 21:47:31 | [diff] [blame] | 647 | |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 648 | if (std::optional<sys::fs::UniqueID> id = getUniqueID(path)) |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 649 | if (!visitedFiles.insert(*id).second) |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 650 | return std::nullopt; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 651 | return path; |
Rui Ueyama | 54b71da | 2015-05-31 19:17:12 | [diff] [blame] | 652 | } |
| 653 | |
Jacek Caban | 0a9810d | 2024-12-15 17:41:26 | [diff] [blame] | 654 | void LinkerDriver::setMachine(MachineTypes machine) { |
| 655 | assert(ctx.config.machine == IMAGE_FILE_MACHINE_UNKNOWN); |
| 656 | assert(machine != IMAGE_FILE_MACHINE_UNKNOWN); |
| 657 | |
| 658 | ctx.config.machine = machine; |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 659 | |
| 660 | if (machine != ARM64X) { |
| 661 | ctx.symtab.machine = machine; |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 662 | } else { |
Jacek Caban | 1c05c61 | 2025-04-11 13:53:25 | [diff] [blame] | 663 | ctx.symtab.machine = ARM64EC; |
| 664 | ctx.hybridSymtab.emplace(ctx, ARM64); |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 665 | } |
| 666 | |
Jacek Caban | 0a9810d | 2024-12-15 17:41:26 | [diff] [blame] | 667 | addWinSysRootLibSearchPaths(); |
| 668 | } |
| 669 | |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 670 | void LinkerDriver::detectWinSysRoot(const opt::InputArgList &Args) { |
| 671 | IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem(); |
| 672 | |
| 673 | // Check the command line first, that's the user explicitly telling us what to |
| 674 | // use. Check the environment next, in case we're being invoked from a VS |
| 675 | // command prompt. Failing that, just try to find the newest Visual Studio |
| 676 | // version we can and use its default VC toolchain. |
Fangrui Song | 900f3f9 | 2022-12-03 20:23:39 | [diff] [blame] | 677 | std::optional<StringRef> VCToolsDir, VCToolsVersion, WinSysRoot; |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 678 | if (auto *A = Args.getLastArg(OPT_vctoolsdir)) |
| 679 | VCToolsDir = A->getValue(); |
| 680 | if (auto *A = Args.getLastArg(OPT_vctoolsversion)) |
| 681 | VCToolsVersion = A->getValue(); |
| 682 | if (auto *A = Args.getLastArg(OPT_winsysroot)) |
| 683 | WinSysRoot = A->getValue(); |
| 684 | if (!findVCToolChainViaCommandLine(*VFS, VCToolsDir, VCToolsVersion, |
| 685 | WinSysRoot, vcToolChainPath, vsLayout) && |
| 686 | (Args.hasArg(OPT_lldignoreenv) || |
| 687 | !findVCToolChainViaEnvironment(*VFS, vcToolChainPath, vsLayout)) && |
Saleem Abdulrasool | af5f468 | 2023-03-07 18:10:31 | [diff] [blame] | 688 | !findVCToolChainViaSetupConfig(*VFS, {}, vcToolChainPath, vsLayout) && |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 689 | !findVCToolChainViaRegistry(vcToolChainPath, vsLayout)) |
| 690 | return; |
| 691 | |
| 692 | // If the VC environment hasn't been configured (perhaps because the user did |
| 693 | // not run vcvarsall), try to build a consistent link environment. If the |
| 694 | // environment variable is set however, assume the user knows what they're |
| 695 | // doing. If the user passes /vctoolsdir or /winsdkdir, trust that over env |
| 696 | // vars. |
| 697 | if (const auto *A = Args.getLastArg(OPT_diasdkdir, OPT_winsysroot)) { |
| 698 | diaPath = A->getValue(); |
| 699 | if (A->getOption().getID() == OPT_winsysroot) |
| 700 | path::append(diaPath, "DIA SDK"); |
| 701 | } |
| 702 | useWinSysRootLibPath = Args.hasArg(OPT_lldignoreenv) || |
| 703 | !Process::GetEnv("LIB") || |
| 704 | Args.getLastArg(OPT_vctoolsdir, OPT_winsysroot); |
| 705 | if (Args.hasArg(OPT_lldignoreenv) || !Process::GetEnv("LIB") || |
| 706 | Args.getLastArg(OPT_winsdkdir, OPT_winsysroot)) { |
Fangrui Song | 900f3f9 | 2022-12-03 20:23:39 | [diff] [blame] | 707 | std::optional<StringRef> WinSdkDir, WinSdkVersion; |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 708 | if (auto *A = Args.getLastArg(OPT_winsdkdir)) |
| 709 | WinSdkDir = A->getValue(); |
| 710 | if (auto *A = Args.getLastArg(OPT_winsdkversion)) |
| 711 | WinSdkVersion = A->getValue(); |
| 712 | |
| 713 | if (useUniversalCRT(vsLayout, vcToolChainPath, getArch(), *VFS)) { |
| 714 | std::string UniversalCRTSdkPath; |
| 715 | std::string UCRTVersion; |
| 716 | if (getUniversalCRTSdkDir(*VFS, WinSdkDir, WinSdkVersion, WinSysRoot, |
| 717 | UniversalCRTSdkPath, UCRTVersion)) { |
| 718 | universalCRTLibPath = UniversalCRTSdkPath; |
| 719 | path::append(universalCRTLibPath, "Lib", UCRTVersion, "ucrt"); |
| 720 | } |
| 721 | } |
| 722 | |
| 723 | std::string sdkPath; |
| 724 | std::string windowsSDKIncludeVersion; |
| 725 | std::string windowsSDKLibVersion; |
| 726 | if (getWindowsSDKDir(*VFS, WinSdkDir, WinSdkVersion, WinSysRoot, sdkPath, |
| 727 | sdkMajor, windowsSDKIncludeVersion, |
| 728 | windowsSDKLibVersion)) { |
| 729 | windowsSdkLibPath = sdkPath; |
| 730 | path::append(windowsSdkLibPath, "Lib"); |
| 731 | if (sdkMajor >= 8) |
| 732 | path::append(windowsSdkLibPath, windowsSDKLibVersion, "um"); |
| 733 | } |
| 734 | } |
| 735 | } |
| 736 | |
Tobias Hieta | af744f0 | 2023-07-14 07:46:54 | [diff] [blame] | 737 | void LinkerDriver::addClangLibSearchPaths(const std::string &argv0) { |
| 738 | std::string lldBinary = sys::fs::getMainExecutable(argv0.c_str(), nullptr); |
| 739 | SmallString<128> binDir(lldBinary); |
Matheus Izvekov | a5e280b | 2023-09-21 11:16:11 | [diff] [blame] | 740 | sys::path::remove_filename(binDir); // remove lld-link.exe |
Tobias Hieta | af744f0 | 2023-07-14 07:46:54 | [diff] [blame] | 741 | StringRef rootDir = sys::path::parent_path(binDir); // remove 'bin' |
| 742 | |
| 743 | SmallString<128> libDir(rootDir); |
| 744 | sys::path::append(libDir, "lib"); |
Tobias Hieta | af744f0 | 2023-07-14 07:46:54 | [diff] [blame] | 745 | |
| 746 | // Add the resource dir library path |
| 747 | SmallString<128> runtimeLibDir(rootDir); |
Matheus Izvekov | a5e280b | 2023-09-21 11:16:11 | [diff] [blame] | 748 | sys::path::append(runtimeLibDir, "lib", "clang", |
| 749 | std::to_string(LLVM_VERSION_MAJOR), "lib"); |
Tobias Hieta | af744f0 | 2023-07-14 07:46:54 | [diff] [blame] | 750 | // Resource dir + osname, which is hardcoded to windows since we are in the |
| 751 | // COFF driver. |
| 752 | SmallString<128> runtimeLibDirWithOS(runtimeLibDir); |
| 753 | sys::path::append(runtimeLibDirWithOS, "windows"); |
Martin Storsjö | f906fd5 | 2023-10-02 10:47:30 | [diff] [blame] | 754 | |
| 755 | searchPaths.push_back(saver().save(runtimeLibDirWithOS.str())); |
| 756 | searchPaths.push_back(saver().save(runtimeLibDir.str())); |
| 757 | searchPaths.push_back(saver().save(libDir.str())); |
Tobias Hieta | af744f0 | 2023-07-14 07:46:54 | [diff] [blame] | 758 | } |
| 759 | |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 760 | void LinkerDriver::addWinSysRootLibSearchPaths() { |
| 761 | if (!diaPath.empty()) { |
| 762 | // The DIA SDK always uses the legacy vc arch, even in new MSVC versions. |
| 763 | path::append(diaPath, "lib", archToLegacyVCArch(getArch())); |
| 764 | searchPaths.push_back(saver().save(diaPath.str())); |
| 765 | } |
| 766 | if (useWinSysRootLibPath) { |
| 767 | searchPaths.push_back(saver().save(getSubDirectoryPath( |
| 768 | SubDirectoryType::Lib, vsLayout, vcToolChainPath, getArch()))); |
| 769 | searchPaths.push_back(saver().save( |
| 770 | getSubDirectoryPath(SubDirectoryType::Lib, vsLayout, vcToolChainPath, |
| 771 | getArch(), "atlmfc"))); |
| 772 | } |
| 773 | if (!universalCRTLibPath.empty()) { |
| 774 | StringRef ArchName = archToWindowsSDKArch(getArch()); |
| 775 | if (!ArchName.empty()) { |
| 776 | path::append(universalCRTLibPath, ArchName); |
| 777 | searchPaths.push_back(saver().save(universalCRTLibPath.str())); |
| 778 | } |
| 779 | } |
| 780 | if (!windowsSdkLibPath.empty()) { |
| 781 | std::string path; |
| 782 | if (appendArchToWindowsSDKLibPath(sdkMajor, windowsSdkLibPath, getArch(), |
| 783 | path)) |
| 784 | searchPaths.push_back(saver().save(path)); |
| 785 | } |
A2uria | 90a08fb | 2025-03-12 06:47:01 | [diff] [blame] | 786 | |
| 787 | // Libraries specified by `/nodefaultlib:` may not be found in incomplete |
| 788 | // search paths before lld infers a machine type from input files. |
| 789 | std::set<std::string> noDefaultLibs; |
| 790 | for (const std::string &path : ctx.config.noDefaultLibs) |
| 791 | noDefaultLibs.insert(findLib(path).lower()); |
| 792 | ctx.config.noDefaultLibs = noDefaultLibs; |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 793 | } |
| 794 | |
Rui Ueyama | 54b71da | 2015-05-31 19:17:12 | [diff] [blame] | 795 | // Parses LIB environment which contains a list of search paths. |
Rui Ueyama | f00df0a | 2015-06-19 22:39:48 | [diff] [blame] | 796 | void LinkerDriver::addLibSearchPaths() { |
Krzysztof Parzyszek | 3c255f6 | 2022-12-06 17:53:37 | [diff] [blame] | 797 | std::optional<std::string> envOpt = Process::GetEnv("LIB"); |
Kazu Hirata | 5413bf1 | 2022-06-20 18:33:56 | [diff] [blame] | 798 | if (!envOpt) |
Rui Ueyama | f00df0a | 2015-06-19 22:39:48 | [diff] [blame] | 799 | return; |
Alexandre Ganea | 83d59e0 | 2022-01-20 19:53:18 | [diff] [blame] | 800 | StringRef env = saver().save(*envOpt); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 801 | while (!env.empty()) { |
| 802 | StringRef path; |
| 803 | std::tie(path, env) = env.split(';'); |
| 804 | searchPaths.push_back(path); |
Rui Ueyama | 54b71da | 2015-05-31 19:17:12 | [diff] [blame] | 805 | } |
Rui Ueyama | 54b71da | 2015-05-31 19:17:12 | [diff] [blame] | 806 | } |
| 807 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 808 | uint64_t LinkerDriver::getDefaultImageBase() { |
| 809 | if (ctx.config.is64()) |
| 810 | return ctx.config.dll ? 0x180000000 : 0x140000000; |
| 811 | return ctx.config.dll ? 0x10000000 : 0x400000; |
Rui Ueyama | 5c437cd | 2015-07-25 21:42:33 | [diff] [blame] | 812 | } |
| 813 | |
Nico Weber | e6d1f26 | 2021-02-22 19:29:55 | [diff] [blame] | 814 | static std::string rewritePath(StringRef s) { |
| 815 | if (fs::exists(s)) |
| 816 | return relativeToRoot(s); |
| 817 | return std::string(s); |
| 818 | } |
| 819 | |
| 820 | // Reconstructs command line arguments so that so that you can re-run |
| 821 | // the same command with the same inputs. This is for --reproduce. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 822 | static std::string createResponseFile(const opt::InputArgList &args, |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 823 | ArrayRef<StringRef> searchPaths) { |
| 824 | SmallString<0> data; |
| 825 | raw_svector_ostream os(data); |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 826 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 827 | for (auto *arg : args) { |
| 828 | switch (arg->getOption().getID()) { |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 829 | case OPT_linkrepro: |
Rui Ueyama | 0d53ac8 | 2019-10-04 07:27:38 | [diff] [blame] | 830 | case OPT_reproduce: |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 831 | case OPT_libpath: |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 832 | case OPT_winsysroot: |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 833 | break; |
Nico Weber | 34a44b2 | 2024-12-17 16:30:13 | [diff] [blame] | 834 | case OPT_INPUT: |
| 835 | os << quote(rewritePath(arg->getValue())) << "\n"; |
| 836 | break; |
| 837 | case OPT_wholearchive_file: |
| 838 | os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << "\n"; |
| 839 | break; |
Nico Weber | e6d1f26 | 2021-02-22 19:29:55 | [diff] [blame] | 840 | case OPT_call_graph_ordering_file: |
| 841 | case OPT_deffile: |
Nico Weber | 400a1de | 2021-08-24 14:19:21 | [diff] [blame] | 842 | case OPT_manifestinput: |
Nico Weber | e6d1f26 | 2021-02-22 19:29:55 | [diff] [blame] | 843 | case OPT_natvis: |
| 844 | os << arg->getSpelling() << quote(rewritePath(arg->getValue())) << '\n'; |
| 845 | break; |
| 846 | case OPT_order: { |
| 847 | StringRef orderFile = arg->getValue(); |
| 848 | orderFile.consume_front("@"); |
| 849 | os << arg->getSpelling() << '@' << quote(rewritePath(orderFile)) << '\n'; |
| 850 | break; |
| 851 | } |
| 852 | case OPT_pdbstream: { |
| 853 | const std::pair<StringRef, StringRef> nameFile = |
| 854 | StringRef(arg->getValue()).split("="); |
| 855 | os << arg->getSpelling() << nameFile.first << '=' |
| 856 | << quote(rewritePath(nameFile.second)) << '\n'; |
| 857 | break; |
| 858 | } |
Alexandre Ganea | 2769d58 | 2019-04-23 12:30:49 | [diff] [blame] | 859 | case OPT_implib: |
Nico Weber | 400a1de | 2021-08-24 14:19:21 | [diff] [blame] | 860 | case OPT_manifestfile: |
Alexandre Ganea | 2769d58 | 2019-04-23 12:30:49 | [diff] [blame] | 861 | case OPT_pdb: |
Reid Kleckner | 8045a8a | 2020-01-15 23:09:25 | [diff] [blame] | 862 | case OPT_pdbstripped: |
Alexandre Ganea | 2769d58 | 2019-04-23 12:30:49 | [diff] [blame] | 863 | case OPT_out: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 864 | os << arg->getSpelling() << sys::path::filename(arg->getValue()) << "\n"; |
Alexandre Ganea | 2769d58 | 2019-04-23 12:30:49 | [diff] [blame] | 865 | break; |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 866 | default: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 867 | os << toString(*arg) << "\n"; |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 868 | } |
| 869 | } |
| 870 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 871 | for (StringRef path : searchPaths) { |
| 872 | std::string relPath = relativeToRoot(path); |
| 873 | os << "/libpath:" << quote(relPath) << "\n"; |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 874 | } |
| 875 | |
Kazu Hirata | 21730eb | 2024-01-22 08:13:23 | [diff] [blame] | 876 | return std::string(data); |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 877 | } |
| 878 | |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 879 | static unsigned parseDebugTypes(COFFLinkerContext &ctx, |
| 880 | const opt::InputArgList &args) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 881 | unsigned debugTypes = static_cast<unsigned>(DebugType::None); |
Will Wilson | 3cb1834 | 2018-09-24 15:28:03 | [diff] [blame] | 882 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 883 | if (auto *a = args.getLastArg(OPT_debugtype)) { |
| 884 | SmallVector<StringRef, 3> types; |
| 885 | StringRef(a->getValue()) |
| 886 | .split(types, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false); |
Will Wilson | 3cb1834 | 2018-09-24 15:28:03 | [diff] [blame] | 887 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 888 | for (StringRef type : types) { |
| 889 | unsigned v = StringSwitch<unsigned>(type.lower()) |
Will Wilson | 3cb1834 | 2018-09-24 15:28:03 | [diff] [blame] | 890 | .Case("cv", static_cast<unsigned>(DebugType::CV)) |
| 891 | .Case("pdata", static_cast<unsigned>(DebugType::PData)) |
| 892 | .Case("fixup", static_cast<unsigned>(DebugType::Fixup)) |
| 893 | .Default(0); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 894 | if (v == 0) { |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 895 | Warn(ctx) << "/debugtype: unknown option '" << type << "'"; |
Will Wilson | 3cb1834 | 2018-09-24 15:28:03 | [diff] [blame] | 896 | continue; |
| 897 | } |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 898 | debugTypes |= v; |
Will Wilson | 3cb1834 | 2018-09-24 15:28:03 | [diff] [blame] | 899 | } |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 900 | return debugTypes; |
Will Wilson | 3cb1834 | 2018-09-24 15:28:03 | [diff] [blame] | 901 | } |
| 902 | |
| 903 | // Default debug types |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 904 | debugTypes = static_cast<unsigned>(DebugType::CV); |
| 905 | if (args.hasArg(OPT_driver)) |
| 906 | debugTypes |= static_cast<unsigned>(DebugType::PData); |
| 907 | if (args.hasArg(OPT_profile)) |
| 908 | debugTypes |= static_cast<unsigned>(DebugType::Fixup); |
Saleem Abdulrasool | a2cca7e | 2016-08-08 22:02:44 | [diff] [blame] | 909 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 910 | return debugTypes; |
Saleem Abdulrasool | a2cca7e | 2016-08-08 22:02:44 | [diff] [blame] | 911 | } |
| 912 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 913 | std::string LinkerDriver::getMapFile(const opt::InputArgList &args, |
| 914 | opt::OptSpecifier os, |
| 915 | opt::OptSpecifier osFile) { |
Sylvain Audi | b91905a | 2020-03-23 21:06:48 | [diff] [blame] | 916 | auto *arg = args.getLastArg(os, osFile); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 917 | if (!arg) |
Hans Wennborg | 1818e65 | 2016-12-09 20:54:44 | [diff] [blame] | 918 | return ""; |
Sylvain Audi | b91905a | 2020-03-23 21:06:48 | [diff] [blame] | 919 | if (arg->getOption().getID() == osFile.getID()) |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 920 | return arg->getValue(); |
Hans Wennborg | 1818e65 | 2016-12-09 20:54:44 | [diff] [blame] | 921 | |
Sylvain Audi | b91905a | 2020-03-23 21:06:48 | [diff] [blame] | 922 | assert(arg->getOption().getID() == os.getID()); |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 923 | StringRef outFile = ctx.config.outputFile; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 924 | return (outFile.substr(0, outFile.rfind('.')) + ".map").str(); |
Hans Wennborg | 1818e65 | 2016-12-09 20:54:44 | [diff] [blame] | 925 | } |
| 926 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 927 | std::string LinkerDriver::getImplibPath() { |
| 928 | if (!ctx.config.implib.empty()) |
| 929 | return std::string(ctx.config.implib); |
| 930 | SmallString<128> out = StringRef(ctx.config.outputFile); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 931 | sys::path::replace_extension(out, ".lib"); |
Kazu Hirata | 21730eb | 2024-01-22 08:13:23 | [diff] [blame] | 932 | return std::string(out); |
Reid Kleckner | 146eb7a | 2017-06-02 17:53:06 | [diff] [blame] | 933 | } |
| 934 | |
Nico Weber | 79a8476 | 2019-10-10 02:04:56 | [diff] [blame] | 935 | // The import name is calculated as follows: |
Saleem Abdulrasool | ace2fa7 | 2017-07-19 02:01:27 | [diff] [blame] | 936 | // |
| 937 | // | LIBRARY w/ ext | LIBRARY w/o ext | no LIBRARY |
| 938 | // -----+----------------+---------------------+------------------ |
| 939 | // LINK | {value} | {value}.{.dll/.exe} | {output name} |
| 940 | // LIB | {value} | {value}.dll | {output name}.dll |
| 941 | // |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 942 | std::string LinkerDriver::getImportName(bool asLib) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 943 | SmallString<128> out; |
Saleem Abdulrasool | ace2fa7 | 2017-07-19 02:01:27 | [diff] [blame] | 944 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 945 | if (ctx.config.importName.empty()) { |
| 946 | out.assign(sys::path::filename(ctx.config.outputFile)); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 947 | if (asLib) |
| 948 | sys::path::replace_extension(out, ".dll"); |
Saleem Abdulrasool | ace2fa7 | 2017-07-19 02:01:27 | [diff] [blame] | 949 | } else { |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 950 | out.assign(ctx.config.importName); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 951 | if (!sys::path::has_extension(out)) |
| 952 | sys::path::replace_extension(out, |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 953 | (ctx.config.dll || asLib) ? ".dll" : ".exe"); |
Saleem Abdulrasool | ace2fa7 | 2017-07-19 02:01:27 | [diff] [blame] | 954 | } |
| 955 | |
Kazu Hirata | 21730eb | 2024-01-22 08:13:23 | [diff] [blame] | 956 | return std::string(out); |
Saleem Abdulrasool | ace2fa7 | 2017-07-19 02:01:27 | [diff] [blame] | 957 | } |
| 958 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 959 | void LinkerDriver::createImportLibrary(bool asLib) { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 960 | llvm::TimeTraceScope timeScope("Create import library"); |
Jacek Caban | e902cf2 | 2025-01-29 08:57:11 | [diff] [blame] | 961 | std::vector<COFFShortExport> exports, nativeExports; |
| 962 | |
| 963 | auto getExports = [](SymbolTable &symtab, |
| 964 | std::vector<COFFShortExport> &exports) { |
| 965 | for (Export &e1 : symtab.exports) { |
| 966 | COFFShortExport e2; |
| 967 | e2.Name = std::string(e1.name); |
| 968 | e2.SymbolName = std::string(e1.symbolName); |
| 969 | e2.ExtName = std::string(e1.extName); |
| 970 | e2.ExportAs = std::string(e1.exportAs); |
| 971 | e2.ImportName = std::string(e1.importName); |
| 972 | e2.Ordinal = e1.ordinal; |
| 973 | e2.Noname = e1.noname; |
| 974 | e2.Data = e1.data; |
| 975 | e2.Private = e1.isPrivate; |
| 976 | e2.Constant = e1.constant; |
| 977 | exports.push_back(e2); |
| 978 | } |
| 979 | }; |
| 980 | |
Jacek Caban | 1c05c61 | 2025-04-11 13:53:25 | [diff] [blame] | 981 | getExports(ctx.symtab, exports); |
| 982 | if (ctx.hybridSymtab) |
| 983 | getExports(*ctx.hybridSymtab, nativeExports); |
Reid Kleckner | 146eb7a | 2017-06-02 17:53:06 | [diff] [blame] | 984 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 985 | std::string libName = getImportName(asLib); |
| 986 | std::string path = getImplibPath(); |
Bob Haarman | 4ce341f | 2018-01-23 00:36:42 | [diff] [blame] | 987 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 988 | if (!ctx.config.incremental) { |
Jacek Caban | 4612208 | 2024-02-13 14:17:28 | [diff] [blame] | 989 | checkError(writeImportLibrary(libName, path, exports, ctx.config.machine, |
Jacek Caban | e902cf2 | 2025-01-29 08:57:11 | [diff] [blame] | 990 | ctx.config.mingw, nativeExports)); |
Bob Haarman | 5ec4485 | 2018-01-31 23:44:00 | [diff] [blame] | 991 | return; |
| 992 | } |
| 993 | |
Bob Haarman | 4ce341f | 2018-01-23 00:36:42 | [diff] [blame] | 994 | // If the import library already exists, replace it only if the contents |
| 995 | // have changed. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 996 | ErrorOr<std::unique_ptr<MemoryBuffer>> oldBuf = MemoryBuffer::getFile( |
Abhina Sreeskantharajan | c83cd8f | 2021-03-25 13:47:25 | [diff] [blame] | 997 | path, /*IsText=*/false, /*RequiresNullTerminator=*/false); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 998 | if (!oldBuf) { |
Jacek Caban | 4612208 | 2024-02-13 14:17:28 | [diff] [blame] | 999 | checkError(writeImportLibrary(libName, path, exports, ctx.config.machine, |
Jacek Caban | e902cf2 | 2025-01-29 08:57:11 | [diff] [blame] | 1000 | ctx.config.mingw, nativeExports)); |
Bob Haarman | 4ce341f | 2018-01-23 00:36:42 | [diff] [blame] | 1001 | return; |
| 1002 | } |
| 1003 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1004 | SmallString<128> tmpName; |
| 1005 | if (std::error_code ec = |
| 1006 | sys::fs::createUniqueFile(path + ".tmp-%%%%%%%%.lib", tmpName)) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1007 | Fatal(ctx) << "cannot create temporary file for import library " << path |
| 1008 | << ": " << ec.message(); |
Bob Haarman | 4ce341f | 2018-01-23 00:36:42 | [diff] [blame] | 1009 | |
Jacek Caban | e902cf2 | 2025-01-29 08:57:11 | [diff] [blame] | 1010 | if (Error e = |
| 1011 | writeImportLibrary(libName, tmpName, exports, ctx.config.machine, |
| 1012 | ctx.config.mingw, nativeExports)) { |
Nico Weber | f309183 | 2021-10-04 15:45:55 | [diff] [blame] | 1013 | checkError(std::move(e)); |
Bob Haarman | 4ce341f | 2018-01-23 00:36:42 | [diff] [blame] | 1014 | return; |
| 1015 | } |
| 1016 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1017 | std::unique_ptr<MemoryBuffer> newBuf = check(MemoryBuffer::getFile( |
Abhina Sreeskantharajan | c83cd8f | 2021-03-25 13:47:25 | [diff] [blame] | 1018 | tmpName, /*IsText=*/false, /*RequiresNullTerminator=*/false)); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1019 | if ((*oldBuf)->getBuffer() != newBuf->getBuffer()) { |
| 1020 | oldBuf->reset(); |
Nico Weber | f309183 | 2021-10-04 15:45:55 | [diff] [blame] | 1021 | checkError(errorCodeToError(sys::fs::rename(tmpName, path))); |
Martin Storsjo | cf47b04 | 2018-01-30 07:26:01 | [diff] [blame] | 1022 | } else { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1023 | sys::fs::remove(tmpName); |
Bob Haarman | 4ce341f | 2018-01-23 00:36:42 | [diff] [blame] | 1024 | } |
Reid Kleckner | 146eb7a | 2017-06-02 17:53:06 | [diff] [blame] | 1025 | } |
| 1026 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1027 | void LinkerDriver::enqueueTask(std::function<void()> task) { |
| 1028 | taskQueue.push_back(std::move(task)); |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 1029 | } |
| 1030 | |
| 1031 | bool LinkerDriver::run() { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1032 | llvm::TimeTraceScope timeScope("Read input files"); |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 1033 | ScopedTimer t(ctx.inputFileTimer); |
Zachary Turner | 727f153 | 2018-01-17 19:16:26 | [diff] [blame] | 1034 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1035 | bool didWork = !taskQueue.empty(); |
| 1036 | while (!taskQueue.empty()) { |
| 1037 | taskQueue.front()(); |
| 1038 | taskQueue.pop_front(); |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 1039 | } |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1040 | return didWork; |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 1041 | } |
| 1042 | |
Rui Ueyama | 57175aa | 2018-01-27 00:34:46 | [diff] [blame] | 1043 | // Parse an /order file. If an option is given, the linker places |
| 1044 | // COMDAT sections in the same order as their names appear in the |
| 1045 | // given file. |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1046 | void LinkerDriver::parseOrderFile(StringRef arg) { |
Rui Ueyama | 57175aa | 2018-01-27 00:34:46 | [diff] [blame] | 1047 | // For some reason, the MSVC linker requires a filename to be |
| 1048 | // preceded by "@". |
Fangrui Song | 8d85c96 | 2023-06-05 21:36:19 | [diff] [blame] | 1049 | if (!arg.starts_with("@")) { |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1050 | Err(ctx) << "malformed /order option: '@' missing"; |
Rui Ueyama | 57175aa | 2018-01-27 00:34:46 | [diff] [blame] | 1051 | return; |
| 1052 | } |
| 1053 | |
Rui Ueyama | b6d3a93 | 2018-01-29 21:50:53 | [diff] [blame] | 1054 | // Get a list of all comdat sections for error checking. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1055 | DenseSet<StringRef> set; |
Jacek Caban | 1bd5f34 | 2025-01-16 11:55:12 | [diff] [blame] | 1056 | for (Chunk *c : ctx.driver.getChunks()) |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1057 | if (auto *sec = dyn_cast<SectionChunk>(c)) |
| 1058 | if (sec->sym) |
| 1059 | set.insert(sec->sym->getName()); |
Rui Ueyama | b6d3a93 | 2018-01-29 21:50:53 | [diff] [blame] | 1060 | |
Rui Ueyama | 57175aa | 2018-01-27 00:34:46 | [diff] [blame] | 1061 | // Open a file. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1062 | StringRef path = arg.substr(1); |
Abhina Sreeskantharajan | c83cd8f | 2021-03-25 13:47:25 | [diff] [blame] | 1063 | std::unique_ptr<MemoryBuffer> mb = |
| 1064 | CHECK(MemoryBuffer::getFile(path, /*IsText=*/false, |
| 1065 | /*RequiresNullTerminator=*/false, |
| 1066 | /*IsVolatile=*/true), |
| 1067 | "could not open " + path); |
Rui Ueyama | 57175aa | 2018-01-27 00:34:46 | [diff] [blame] | 1068 | |
| 1069 | // Parse a file. An order file contains one symbol per line. |
| 1070 | // All symbols that were not present in a given order file are |
| 1071 | // considered to have the lowest priority 0 and are placed at |
| 1072 | // end of an output section. |
Benjamin Kramer | adcd026 | 2020-01-28 19:23:46 | [diff] [blame] | 1073 | for (StringRef arg : args::getLines(mb->getMemBufferRef())) { |
| 1074 | std::string s(arg); |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1075 | if (ctx.config.machine == I386 && !isDecorated(s)) |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1076 | s = "_" + s; |
Rui Ueyama | b6d3a93 | 2018-01-29 21:50:53 | [diff] [blame] | 1077 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1078 | if (set.count(s) == 0) { |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1079 | if (ctx.config.warnMissingOrderSymbol) |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 1080 | Warn(ctx) << "/order:" << arg << ": missing symbol: " << s |
| 1081 | << " [LNK4037]"; |
Matheus Izvekov | a5e280b | 2023-09-21 11:16:11 | [diff] [blame] | 1082 | } else |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1083 | ctx.config.order[s] = INT_MIN + ctx.config.order.size(); |
Rui Ueyama | 57175aa | 2018-01-27 00:34:46 | [diff] [blame] | 1084 | } |
Nico Weber | e6d1f26 | 2021-02-22 19:29:55 | [diff] [blame] | 1085 | |
| 1086 | // Include in /reproduce: output if applicable. |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1087 | ctx.driver.takeBuffer(std::move(mb)); |
Rui Ueyama | 57175aa | 2018-01-27 00:34:46 | [diff] [blame] | 1088 | } |
| 1089 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1090 | void LinkerDriver::parseCallGraphFile(StringRef path) { |
Abhina Sreeskantharajan | c83cd8f | 2021-03-25 13:47:25 | [diff] [blame] | 1091 | std::unique_ptr<MemoryBuffer> mb = |
| 1092 | CHECK(MemoryBuffer::getFile(path, /*IsText=*/false, |
| 1093 | /*RequiresNullTerminator=*/false, |
| 1094 | /*IsVolatile=*/true), |
| 1095 | "could not open " + path); |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1096 | |
| 1097 | // Build a map from symbol name to section. |
| 1098 | DenseMap<StringRef, Symbol *> map; |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 1099 | for (ObjFile *file : ctx.objFileInstances) |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1100 | for (Symbol *sym : file->getSymbols()) |
| 1101 | if (sym) |
| 1102 | map[sym->getName()] = sym; |
| 1103 | |
| 1104 | auto findSection = [&](StringRef name) -> SectionChunk * { |
| 1105 | Symbol *sym = map.lookup(name); |
| 1106 | if (!sym) { |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1107 | if (ctx.config.warnMissingOrderSymbol) |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 1108 | Warn(ctx) << path << ": no such symbol: " << name; |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1109 | return nullptr; |
| 1110 | } |
| 1111 | |
| 1112 | if (DefinedCOFF *dr = dyn_cast_or_null<DefinedCOFF>(sym)) |
| 1113 | return dyn_cast_or_null<SectionChunk>(dr->getChunk()); |
| 1114 | return nullptr; |
| 1115 | }; |
| 1116 | |
| 1117 | for (StringRef line : args::getLines(*mb)) { |
| 1118 | SmallVector<StringRef, 3> fields; |
| 1119 | line.split(fields, ' '); |
| 1120 | uint64_t count; |
| 1121 | |
| 1122 | if (fields.size() != 3 || !to_integer(fields[2], count)) { |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1123 | Err(ctx) << path << ": parse error"; |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1124 | return; |
| 1125 | } |
| 1126 | |
| 1127 | if (SectionChunk *from = findSection(fields[0])) |
| 1128 | if (SectionChunk *to = findSection(fields[1])) |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1129 | ctx.config.callGraphProfile[{from, to}] += count; |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1130 | } |
Nico Weber | e6d1f26 | 2021-02-22 19:29:55 | [diff] [blame] | 1131 | |
| 1132 | // Include in /reproduce: output if applicable. |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1133 | ctx.driver.takeBuffer(std::move(mb)); |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1134 | } |
| 1135 | |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 1136 | static void readCallGraphsFromObjectFiles(COFFLinkerContext &ctx) { |
| 1137 | for (ObjFile *obj : ctx.objFileInstances) { |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1138 | if (obj->callgraphSec) { |
| 1139 | ArrayRef<uint8_t> contents; |
| 1140 | cantFail( |
| 1141 | obj->getCOFFObj()->getSectionContents(obj->callgraphSec, contents)); |
Kazu Hirata | 4a0ccfa | 2023-10-13 04:21:44 | [diff] [blame] | 1142 | BinaryStreamReader reader(contents, llvm::endianness::little); |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1143 | while (!reader.empty()) { |
| 1144 | uint32_t fromIndex, toIndex; |
| 1145 | uint64_t count; |
| 1146 | if (Error err = reader.readInteger(fromIndex)) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1147 | Fatal(ctx) << toString(obj) << ": Expected 32-bit integer"; |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1148 | if (Error err = reader.readInteger(toIndex)) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1149 | Fatal(ctx) << toString(obj) << ": Expected 32-bit integer"; |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1150 | if (Error err = reader.readInteger(count)) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1151 | Fatal(ctx) << toString(obj) << ": Expected 64-bit integer"; |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1152 | auto *fromSym = dyn_cast_or_null<Defined>(obj->getSymbol(fromIndex)); |
| 1153 | auto *toSym = dyn_cast_or_null<Defined>(obj->getSymbol(toIndex)); |
| 1154 | if (!fromSym || !toSym) |
| 1155 | continue; |
| 1156 | auto *from = dyn_cast_or_null<SectionChunk>(fromSym->getChunk()); |
| 1157 | auto *to = dyn_cast_or_null<SectionChunk>(toSym->getChunk()); |
| 1158 | if (from && to) |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1159 | ctx.config.callGraphProfile[{from, to}] += count; |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 1160 | } |
| 1161 | } |
| 1162 | } |
| 1163 | } |
| 1164 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1165 | static void markAddrsig(Symbol *s) { |
| 1166 | if (auto *d = dyn_cast_or_null<Defined>(s)) |
| 1167 | if (SectionChunk *c = dyn_cast_or_null<SectionChunk>(d->getChunk())) |
| 1168 | c->keepUnique = true; |
Peter Collingbourne | ab03802 | 2018-08-23 17:44:42 | [diff] [blame] | 1169 | } |
| 1170 | |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 1171 | static void findKeepUniqueSections(COFFLinkerContext &ctx) { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1172 | llvm::TimeTraceScope timeScope("Find keep unique sections"); |
| 1173 | |
Peter Collingbourne | ab03802 | 2018-08-23 17:44:42 | [diff] [blame] | 1174 | // Exported symbols could be address-significant in other executables or DSOs, |
| 1175 | // so we conservatively mark them as address-significant. |
Jacek Caban | 455b3d6 | 2025-01-21 09:41:15 | [diff] [blame] | 1176 | ctx.forEachSymtab([](SymbolTable &symtab) { |
| 1177 | for (Export &r : symtab.exports) |
| 1178 | markAddrsig(r.sym); |
| 1179 | }); |
Peter Collingbourne | ab03802 | 2018-08-23 17:44:42 | [diff] [blame] | 1180 | |
| 1181 | // Visit the address-significance table in each object file and mark each |
| 1182 | // referenced symbol as address-significant. |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 1183 | for (ObjFile *obj : ctx.objFileInstances) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1184 | ArrayRef<Symbol *> syms = obj->getSymbols(); |
| 1185 | if (obj->addrsigSec) { |
| 1186 | ArrayRef<uint8_t> contents; |
Fangrui Song | e1cb2c0 | 2019-05-14 04:22:51 | [diff] [blame] | 1187 | cantFail( |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1188 | obj->getCOFFObj()->getSectionContents(obj->addrsigSec, contents)); |
| 1189 | const uint8_t *cur = contents.begin(); |
| 1190 | while (cur != contents.end()) { |
| 1191 | unsigned size; |
Adrian Prantl | 2c07181 | 2023-11-27 18:42:57 | [diff] [blame] | 1192 | const char *err = nullptr; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1193 | uint64_t symIndex = decodeULEB128(cur, &size, contents.end(), &err); |
| 1194 | if (err) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1195 | Fatal(ctx) << toString(obj) |
| 1196 | << ": could not decode addrsig section: " << err; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1197 | if (symIndex >= syms.size()) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1198 | Fatal(ctx) << toString(obj) |
| 1199 | << ": invalid symbol index in addrsig section"; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1200 | markAddrsig(syms[symIndex]); |
| 1201 | cur += size; |
Peter Collingbourne | ab03802 | 2018-08-23 17:44:42 | [diff] [blame] | 1202 | } |
| 1203 | } else { |
| 1204 | // If an object file does not have an address-significance table, |
| 1205 | // conservatively mark all of its symbols as address-significant. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1206 | for (Symbol *s : syms) |
| 1207 | markAddrsig(s); |
Peter Collingbourne | ab03802 | 2018-08-23 17:44:42 | [diff] [blame] | 1208 | } |
| 1209 | } |
| 1210 | } |
| 1211 | |
Fangrui Song | 2e2038b | 2019-07-16 08:26:38 | [diff] [blame] | 1212 | // link.exe replaces each %foo% in altPath with the contents of environment |
Nico Weber | 9d75241 | 2018-10-08 23:06:05 | [diff] [blame] | 1213 | // variable foo, and adds the two magic env vars _PDB (expands to the basename |
| 1214 | // of pdb's output path) and _EXT (expands to the extension of the output |
| 1215 | // binary). |
| 1216 | // lld only supports %_PDB% and %_EXT% and warns on references to all other env |
| 1217 | // vars. |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1218 | void LinkerDriver::parsePDBAltPath() { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1219 | SmallString<128> buf; |
| 1220 | StringRef pdbBasename = |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1221 | sys::path::filename(ctx.config.pdbPath, sys::path::Style::windows); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1222 | StringRef binaryExtension = |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1223 | sys::path::extension(ctx.config.outputFile, sys::path::Style::windows); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1224 | if (!binaryExtension.empty()) |
| 1225 | binaryExtension = binaryExtension.substr(1); // %_EXT% does not include '.'. |
Nico Weber | 9d75241 | 2018-10-08 23:06:05 | [diff] [blame] | 1226 | |
| 1227 | // Invariant: |
Fangrui Song | 2e2038b | 2019-07-16 08:26:38 | [diff] [blame] | 1228 | // +--------- cursor ('a...' might be the empty string). |
| 1229 | // | +----- firstMark |
| 1230 | // | | +- secondMark |
Nico Weber | 9d75241 | 2018-10-08 23:06:05 | [diff] [blame] | 1231 | // v v v |
| 1232 | // a...%...%... |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1233 | size_t cursor = 0; |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1234 | while (cursor < ctx.config.pdbAltPath.size()) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1235 | size_t firstMark, secondMark; |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1236 | if ((firstMark = ctx.config.pdbAltPath.find('%', cursor)) == |
| 1237 | StringRef::npos || |
| 1238 | (secondMark = ctx.config.pdbAltPath.find('%', firstMark + 1)) == |
| 1239 | StringRef::npos) { |
Nico Weber | 9d75241 | 2018-10-08 23:06:05 | [diff] [blame] | 1240 | // Didn't find another full fragment, treat rest of string as literal. |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1241 | buf.append(ctx.config.pdbAltPath.substr(cursor)); |
Nico Weber | 9d75241 | 2018-10-08 23:06:05 | [diff] [blame] | 1242 | break; |
| 1243 | } |
| 1244 | |
| 1245 | // Found a full fragment. Append text in front of first %, and interpret |
| 1246 | // text between first and second % as variable name. |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1247 | buf.append(ctx.config.pdbAltPath.substr(cursor, firstMark - cursor)); |
| 1248 | StringRef var = |
| 1249 | ctx.config.pdbAltPath.substr(firstMark, secondMark - firstMark + 1); |
Martin Storsjö | 3c6f8ca | 2021-06-24 08:06:35 | [diff] [blame] | 1250 | if (var.equals_insensitive("%_pdb%")) |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1251 | buf.append(pdbBasename); |
Martin Storsjö | 3c6f8ca | 2021-06-24 08:06:35 | [diff] [blame] | 1252 | else if (var.equals_insensitive("%_ext%")) |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1253 | buf.append(binaryExtension); |
Nico Weber | 9d75241 | 2018-10-08 23:06:05 | [diff] [blame] | 1254 | else { |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 1255 | Warn(ctx) << "only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " |
| 1256 | << var << " as literal"; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1257 | buf.append(var); |
Nico Weber | 9d75241 | 2018-10-08 23:06:05 | [diff] [blame] | 1258 | } |
| 1259 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1260 | cursor = secondMark + 1; |
Nico Weber | 9d75241 | 2018-10-08 23:06:05 | [diff] [blame] | 1261 | } |
| 1262 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1263 | ctx.config.pdbAltPath = buf; |
Nico Weber | 9d75241 | 2018-10-08 23:06:05 | [diff] [blame] | 1264 | } |
| 1265 | |
Martin Storsjo | 3d3a9b3 | 2019-08-30 06:56:33 | [diff] [blame] | 1266 | /// Convert resource files and potentially merge input resource object |
| 1267 | /// trees into one resource tree. |
Nico Weber | af6bc65 | 2019-06-11 15:22:28 | [diff] [blame] | 1268 | /// Call after ObjFile::Instances is complete. |
Martin Storsjo | 3d3a9b3 | 2019-08-30 06:56:33 | [diff] [blame] | 1269 | void LinkerDriver::convertResources() { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1270 | llvm::TimeTraceScope timeScope("Convert resources"); |
Martin Storsjo | 3d3a9b3 | 2019-08-30 06:56:33 | [diff] [blame] | 1271 | std::vector<ObjFile *> resourceObjFiles; |
| 1272 | |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 1273 | for (ObjFile *f : ctx.objFileInstances) { |
Martin Storsjo | 3d3a9b3 | 2019-08-30 06:56:33 | [diff] [blame] | 1274 | if (f->isResourceObjFile()) |
| 1275 | resourceObjFiles.push_back(f); |
Nico Weber | af6bc65 | 2019-06-11 15:22:28 | [diff] [blame] | 1276 | } |
Martin Storsjo | 3d3a9b3 | 2019-08-30 06:56:33 | [diff] [blame] | 1277 | |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1278 | if (!ctx.config.mingw && |
Martin Storsjo | 3d3a9b3 | 2019-08-30 06:56:33 | [diff] [blame] | 1279 | (resourceObjFiles.size() > 1 || |
| 1280 | (resourceObjFiles.size() == 1 && !resources.empty()))) { |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1281 | Err(ctx) << (!resources.empty() |
| 1282 | ? "internal .obj file created from .res files" |
| 1283 | : toString(resourceObjFiles[1])) |
| 1284 | << ": more than one resource obj file not allowed, already got " |
| 1285 | << resourceObjFiles.front(); |
Martin Storsjo | 3d3a9b3 | 2019-08-30 06:56:33 | [diff] [blame] | 1286 | return; |
| 1287 | } |
| 1288 | |
| 1289 | if (resources.empty() && resourceObjFiles.size() <= 1) { |
| 1290 | // No resources to convert, and max one resource object file in |
| 1291 | // the input. Keep that preconverted resource section as is. |
| 1292 | for (ObjFile *f : resourceObjFiles) |
| 1293 | f->includeResourceChunks(); |
| 1294 | return; |
| 1295 | } |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 1296 | ObjFile *f = |
Jacek Caban | 9c8214f | 2024-12-17 18:26:13 | [diff] [blame] | 1297 | ObjFile::create(ctx, convertResToCOFF(resources, resourceObjFiles)); |
Jacek Caban | 8435225 | 2025-01-01 18:42:49 | [diff] [blame] | 1298 | addFile(f); |
Martin Storsjo | 3d3a9b3 | 2019-08-30 06:56:33 | [diff] [blame] | 1299 | f->includeResourceChunks(); |
Nico Weber | af6bc65 | 2019-06-11 15:22:28 | [diff] [blame] | 1300 | } |
| 1301 | |
Jacek Caban | a2d8743 | 2024-08-22 20:03:05 | [diff] [blame] | 1302 | void LinkerDriver::maybeCreateECExportThunk(StringRef name, Symbol *&sym) { |
| 1303 | Defined *def; |
| 1304 | if (!sym) |
| 1305 | return; |
| 1306 | if (auto undef = dyn_cast<Undefined>(sym)) |
Jacek Caban | ba898db | 2024-10-15 20:58:13 | [diff] [blame] | 1307 | def = undef->getDefinedWeakAlias(); |
Jacek Caban | a2d8743 | 2024-08-22 20:03:05 | [diff] [blame] | 1308 | else |
| 1309 | def = dyn_cast<Defined>(sym); |
| 1310 | if (!def) |
| 1311 | return; |
| 1312 | |
| 1313 | if (def->getChunk()->getArm64ECRangeType() != chpe_range_type::Arm64EC) |
| 1314 | return; |
| 1315 | StringRef expName; |
| 1316 | if (auto mangledName = getArm64ECMangledFunctionName(name)) |
| 1317 | expName = saver().save("EXP+" + *mangledName); |
| 1318 | else |
| 1319 | expName = saver().save("EXP+" + name); |
Jacek Caban | 61f80db | 2025-04-11 16:50:16 | [diff] [blame] | 1320 | sym = ctx.symtab.addGCRoot(expName); |
Jacek Caban | a2d8743 | 2024-08-22 20:03:05 | [diff] [blame] | 1321 | if (auto undef = dyn_cast<Undefined>(sym)) { |
| 1322 | if (!undef->getWeakAlias()) { |
| 1323 | auto thunk = make<ECExportThunkChunk>(def); |
| 1324 | replaceSymbol<DefinedSynthetic>(undef, undef->getName(), thunk); |
| 1325 | } |
| 1326 | } |
| 1327 | } |
| 1328 | |
| 1329 | void LinkerDriver::createECExportThunks() { |
| 1330 | // Check if EXP+ symbols have corresponding $hp_target symbols and use them |
| 1331 | // to create export thunks when available. |
Jacek Caban | 61f80db | 2025-04-11 16:50:16 | [diff] [blame] | 1332 | for (Symbol *s : ctx.symtab.expSymbols) { |
Jacek Caban | a2d8743 | 2024-08-22 20:03:05 | [diff] [blame] | 1333 | if (!s->isUsedInRegularObj) |
| 1334 | continue; |
| 1335 | assert(s->getName().starts_with("EXP+")); |
| 1336 | std::string targetName = |
| 1337 | (s->getName().substr(strlen("EXP+")) + "$hp_target").str(); |
Jacek Caban | 61f80db | 2025-04-11 16:50:16 | [diff] [blame] | 1338 | Symbol *sym = ctx.symtab.find(targetName); |
Jacek Caban | a2d8743 | 2024-08-22 20:03:05 | [diff] [blame] | 1339 | if (!sym) |
| 1340 | continue; |
| 1341 | Defined *targetSym; |
| 1342 | if (auto undef = dyn_cast<Undefined>(sym)) |
Jacek Caban | ba898db | 2024-10-15 20:58:13 | [diff] [blame] | 1343 | targetSym = undef->getDefinedWeakAlias(); |
Jacek Caban | a2d8743 | 2024-08-22 20:03:05 | [diff] [blame] | 1344 | else |
| 1345 | targetSym = dyn_cast<Defined>(sym); |
| 1346 | if (!targetSym) |
| 1347 | continue; |
| 1348 | |
| 1349 | auto *undef = dyn_cast<Undefined>(s); |
| 1350 | if (undef && !undef->getWeakAlias()) { |
| 1351 | auto thunk = make<ECExportThunkChunk>(targetSym); |
| 1352 | replaceSymbol<DefinedSynthetic>(undef, undef->getName(), thunk); |
| 1353 | } |
| 1354 | if (!targetSym->isGCRoot) { |
| 1355 | targetSym->isGCRoot = true; |
| 1356 | ctx.config.gcroot.push_back(targetSym); |
| 1357 | } |
| 1358 | } |
| 1359 | |
Jacek Caban | 61f80db | 2025-04-11 16:50:16 | [diff] [blame] | 1360 | if (ctx.symtab.entry) |
| 1361 | maybeCreateECExportThunk(ctx.symtab.entry->getName(), ctx.symtab.entry); |
| 1362 | for (Export &e : ctx.symtab.exports) { |
Jacek Caban | a2d8743 | 2024-08-22 20:03:05 | [diff] [blame] | 1363 | if (!e.data) |
| 1364 | maybeCreateECExportThunk(e.extName.empty() ? e.name : e.extName, e.sym); |
| 1365 | } |
| 1366 | } |
| 1367 | |
Jacek Caban | 99a2354 | 2024-09-11 12:46:40 | [diff] [blame] | 1368 | void LinkerDriver::pullArm64ECIcallHelper() { |
| 1369 | if (!ctx.config.arm64ECIcallHelper) |
Jacek Caban | 251ef3f | 2025-01-13 22:16:57 | [diff] [blame] | 1370 | ctx.config.arm64ECIcallHelper = |
Jacek Caban | 61f80db | 2025-04-11 16:50:16 | [diff] [blame] | 1371 | ctx.symtab.addGCRoot("__icall_helper_arm64ec"); |
Jacek Caban | 99a2354 | 2024-09-11 12:46:40 | [diff] [blame] | 1372 | } |
| 1373 | |
Rui Ueyama | 659f275 | 2019-02-19 22:06:44 | [diff] [blame] | 1374 | // In MinGW, if no symbols are chosen to be exported, then all symbols are |
| 1375 | // automatically exported by default. This behavior can be forced by the |
| 1376 | // -export-all-symbols option, so that it happens even when exports are |
| 1377 | // explicitly specified. The automatic behavior can be disabled using the |
| 1378 | // -exclude-all-symbols option, so that lld-link behaves like link.exe rather |
| 1379 | // than MinGW in the case that nothing is explicitly exported. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1380 | void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1381 | if (!args.hasArg(OPT_export_all_symbols)) { |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1382 | if (!ctx.config.dll) |
Martin Storsjö | 9dbc4b0 | 2021-07-18 19:52:32 | [diff] [blame] | 1383 | return; |
| 1384 | |
Jacek Caban | f729477 | 2025-02-06 21:25:53 | [diff] [blame] | 1385 | if (ctx.symtab.hadExplicitExports || |
| 1386 | (ctx.hybridSymtab && ctx.hybridSymtab->hadExplicitExports)) |
Rui Ueyama | 659f275 | 2019-02-19 22:06:44 | [diff] [blame] | 1387 | return; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1388 | if (args.hasArg(OPT_exclude_all_symbols)) |
Rui Ueyama | 659f275 | 2019-02-19 22:06:44 | [diff] [blame] | 1389 | return; |
| 1390 | } |
| 1391 | |
Jacek Caban | f729477 | 2025-02-06 21:25:53 | [diff] [blame] | 1392 | ctx.forEachSymtab([&](SymbolTable &symtab) { |
| 1393 | AutoExporter exporter(symtab, excludedSymbols); |
Rui Ueyama | 659f275 | 2019-02-19 22:06:44 | [diff] [blame] | 1394 | |
Jacek Caban | f729477 | 2025-02-06 21:25:53 | [diff] [blame] | 1395 | for (auto *arg : args.filtered(OPT_wholearchive_file)) |
| 1396 | if (std::optional<StringRef> path = findFile(arg->getValue())) |
| 1397 | exporter.addWholeArchive(*path); |
Rui Ueyama | 659f275 | 2019-02-19 22:06:44 | [diff] [blame] | 1398 | |
Jacek Caban | f729477 | 2025-02-06 21:25:53 | [diff] [blame] | 1399 | for (auto *arg : args.filtered(OPT_exclude_symbols)) { |
| 1400 | SmallVector<StringRef, 2> vec; |
| 1401 | StringRef(arg->getValue()).split(vec, ','); |
| 1402 | for (StringRef sym : vec) |
| 1403 | exporter.addExcludedSymbol(symtab.mangle(sym)); |
Martin Storsjö | 82de4e0 | 2021-04-30 12:15:13 | [diff] [blame] | 1404 | } |
| 1405 | |
Jacek Caban | f729477 | 2025-02-06 21:25:53 | [diff] [blame] | 1406 | symtab.forEachSymbol([&](Symbol *s) { |
| 1407 | auto *def = dyn_cast<Defined>(s); |
| 1408 | if (!exporter.shouldExport(def)) |
| 1409 | return; |
| 1410 | |
| 1411 | if (!def->isGCRoot) { |
| 1412 | def->isGCRoot = true; |
| 1413 | ctx.config.gcroot.push_back(def); |
| 1414 | } |
| 1415 | |
| 1416 | Export e; |
| 1417 | e.name = def->getName(); |
| 1418 | e.sym = def; |
| 1419 | if (Chunk *c = def->getChunk()) |
| 1420 | if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) |
| 1421 | e.data = true; |
| 1422 | s->isUsedInRegularObj = true; |
| 1423 | symtab.exports.push_back(e); |
| 1424 | }); |
Rui Ueyama | 659f275 | 2019-02-19 22:06:44 | [diff] [blame] | 1425 | }); |
| 1426 | } |
| 1427 | |
Rui Ueyama | 0d53ac8 | 2019-10-04 07:27:38 | [diff] [blame] | 1428 | // lld has a feature to create a tar file containing all input files as well as |
| 1429 | // all command line options, so that other people can run lld again with exactly |
| 1430 | // the same inputs. This feature is accessible via /linkrepro and /reproduce. |
| 1431 | // |
| 1432 | // /linkrepro and /reproduce are very similar, but /linkrepro takes a directory |
| 1433 | // name while /reproduce takes a full path. We have /linkrepro for compatibility |
| 1434 | // with Microsoft link.exe. |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 1435 | std::optional<std::string> getReproduceFile(const opt::InputArgList &args) { |
Rui Ueyama | 0d53ac8 | 2019-10-04 07:27:38 | [diff] [blame] | 1436 | if (auto *arg = args.getLastArg(OPT_reproduce)) |
| 1437 | return std::string(arg->getValue()); |
| 1438 | |
| 1439 | if (auto *arg = args.getLastArg(OPT_linkrepro)) { |
| 1440 | SmallString<64> path = StringRef(arg->getValue()); |
| 1441 | sys::path::append(path, "repro.tar"); |
Jonas Devlieghere | 3e24242 | 2020-01-30 05:30:21 | [diff] [blame] | 1442 | return std::string(path); |
Rui Ueyama | 0d53ac8 | 2019-10-04 07:27:38 | [diff] [blame] | 1443 | } |
| 1444 | |
Nico Weber | a0994cb | 2020-11-27 18:33:55 | [diff] [blame] | 1445 | // This is intentionally not guarded by OPT_lldignoreenv since writing |
| 1446 | // a repro tar file doesn't affect the main output. |
| 1447 | if (auto *path = getenv("LLD_REPRODUCE")) |
| 1448 | return std::string(path); |
| 1449 | |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 1450 | return std::nullopt; |
Rui Ueyama | 0d53ac8 | 2019-10-04 07:27:38 | [diff] [blame] | 1451 | } |
| 1452 | |
Alex Brachet | fd9962e | 2022-07-11 21:31:01 | [diff] [blame] | 1453 | static std::unique_ptr<llvm::vfs::FileSystem> |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1454 | getVFS(COFFLinkerContext &ctx, const opt::InputArgList &args) { |
Alex Brachet | fd9962e | 2022-07-11 21:31:01 | [diff] [blame] | 1455 | using namespace llvm::vfs; |
| 1456 | |
| 1457 | const opt::Arg *arg = args.getLastArg(OPT_vfsoverlay); |
| 1458 | if (!arg) |
| 1459 | return nullptr; |
| 1460 | |
| 1461 | auto bufOrErr = llvm::MemoryBuffer::getFile(arg->getValue()); |
| 1462 | if (!bufOrErr) { |
| 1463 | checkError(errorCodeToError(bufOrErr.getError())); |
| 1464 | return nullptr; |
| 1465 | } |
| 1466 | |
Matheus Izvekov | a5e280b | 2023-09-21 11:16:11 | [diff] [blame] | 1467 | if (auto ret = vfs::getVFSFromYAML(std::move(*bufOrErr), |
| 1468 | /*DiagHandler*/ nullptr, arg->getValue())) |
Alex Brachet | fd9962e | 2022-07-11 21:31:01 | [diff] [blame] | 1469 | return ret; |
| 1470 | |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1471 | Err(ctx) << "Invalid vfs overlay"; |
Alex Brachet | fd9962e | 2022-07-11 21:31:01 | [diff] [blame] | 1472 | return nullptr; |
| 1473 | } |
| 1474 | |
Miguel A. Arroyo | 5cd6e21 | 2024-11-12 20:30:48 | [diff] [blame] | 1475 | constexpr const char *lldsaveTempsValues[] = { |
| 1476 | "resolution", "preopt", "promote", "internalize", "import", |
| 1477 | "opt", "precodegen", "prelink", "combinedindex"}; |
| 1478 | |
Reshabh Sharma | fdd6ed8 | 2020-12-18 06:39:01 | [diff] [blame] | 1479 | void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 1480 | ScopedTimer rootTimer(ctx.rootTimer); |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1481 | Configuration *config = &ctx.config; |
Reid Kleckner | 3508c1d | 2020-05-20 14:50:19 | [diff] [blame] | 1482 | |
Bob Haarman | f3fb7fa | 2019-05-08 22:11:02 | [diff] [blame] | 1483 | // Needed for LTO. |
| 1484 | InitializeAllTargetInfos(); |
| 1485 | InitializeAllTargets(); |
| 1486 | InitializeAllTargetMCs(); |
| 1487 | InitializeAllAsmParsers(); |
| 1488 | InitializeAllAsmPrinters(); |
| 1489 | |
Rui Ueyama | 27e470a | 2015-08-09 20:45:17 | [diff] [blame] | 1490 | // If the first command line argument is "/lib", link.exe acts like lib.exe. |
| 1491 | // We call our own implementation of lib.exe that understands bitcode files. |
Martin Storsjö | 3c6f8ca | 2021-06-24 08:06:35 | [diff] [blame] | 1492 | if (argsArr.size() > 1 && |
| 1493 | (StringRef(argsArr[1]).equals_insensitive("/lib") || |
| 1494 | StringRef(argsArr[1]).equals_insensitive("-lib"))) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1495 | if (llvm::libDriverMain(argsArr.slice(1)) != 0) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1496 | Fatal(ctx) << "lib failed"; |
Rui Ueyama | 27e470a | 2015-08-09 20:45:17 | [diff] [blame] | 1497 | return; |
| 1498 | } |
| 1499 | |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 1500 | // Parse command line options. |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 1501 | ArgParser parser(ctx); |
Nico Weber | d48ea5d | 2019-09-13 13:13:52 | [diff] [blame] | 1502 | opt::InputArgList args = parser.parse(argsArr); |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 1503 | |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1504 | // Initialize time trace profiler. |
| 1505 | config->timeTraceEnabled = args.hasArg(OPT_time_trace_eq); |
| 1506 | config->timeTraceGranularity = |
| 1507 | args::getInteger(args, OPT_time_trace_granularity_eq, 500); |
| 1508 | |
| 1509 | if (config->timeTraceEnabled) |
| 1510 | timeTraceProfilerInitialize(config->timeTraceGranularity, argsArr[0]); |
| 1511 | |
| 1512 | llvm::TimeTraceScope timeScope("COFF link"); |
| 1513 | |
Rui Ueyama | 9a3e733 | 2017-03-30 20:10:40 | [diff] [blame] | 1514 | // Parse and evaluate -mllvm options. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1515 | std::vector<const char *> v; |
| 1516 | v.push_back("lld-link (LLVM option parsing)"); |
Nico Weber | 67d311a | 2022-11-14 19:23:56 | [diff] [blame] | 1517 | for (const auto *arg : args.filtered(OPT_mllvm)) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1518 | v.push_back(arg->getValue()); |
Nico Weber | 67d311a | 2022-11-14 19:23:56 | [diff] [blame] | 1519 | config->mllvmOpts.emplace_back(arg->getValue()); |
| 1520 | } |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1521 | { |
| 1522 | llvm::TimeTraceScope timeScope2("Parse cl::opt"); |
| 1523 | cl::ResetAllOptionOccurrences(); |
| 1524 | cl::ParseCommandLineOptions(v.size(), v.data()); |
| 1525 | } |
Rui Ueyama | 9a3e733 | 2017-03-30 20:10:40 | [diff] [blame] | 1526 | |
Bob Haarman | ac8f7fc | 2017-04-05 00:43:54 | [diff] [blame] | 1527 | // Handle /errorlimit early, because error() depends on it. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1528 | if (auto *arg = args.getLastArg(OPT_errorlimit)) { |
| 1529 | int n = 20; |
| 1530 | StringRef s = arg->getValue(); |
| 1531 | if (s.getAsInteger(10, n)) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1532 | Err(ctx) << arg->getSpelling() << " number expected, but got " << s; |
Fangrui Song | 1bfe55af | 2024-11-17 02:31:57 | [diff] [blame] | 1533 | ctx.e.errorLimit = n; |
Bob Haarman | ac8f7fc | 2017-04-05 00:43:54 | [diff] [blame] | 1534 | } |
| 1535 | |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1536 | config->vfs = getVFS(ctx, args); |
Alex Brachet | fd9962e | 2022-07-11 21:31:01 | [diff] [blame] | 1537 | |
Rui Ueyama | 5c72643 | 2015-05-29 16:11:52 | [diff] [blame] | 1538 | // Handle /help |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1539 | if (args.hasArg(OPT_help)) { |
| 1540 | printHelp(argsArr[0]); |
Rafael Espindola | b835ae8 | 2015-08-06 14:58:50 | [diff] [blame] | 1541 | return; |
Rui Ueyama | 5c72643 | 2015-05-29 16:11:52 | [diff] [blame] | 1542 | } |
| 1543 | |
Fangrui Song | eb4663d | 2020-03-17 19:40:19 | [diff] [blame] | 1544 | // /threads: takes a positive integer and provides the default value for |
| 1545 | // /opt:lldltojobs=. |
| 1546 | if (auto *arg = args.getLastArg(OPT_threads)) { |
| 1547 | StringRef v(arg->getValue()); |
| 1548 | unsigned threads = 0; |
| 1549 | if (!llvm::to_integer(v, threads, 0) || threads == 0) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1550 | Err(ctx) << arg->getSpelling() |
| 1551 | << ": expected a positive integer, but got '" << arg->getValue() |
| 1552 | << "'"; |
Fangrui Song | eb4663d | 2020-03-17 19:40:19 | [diff] [blame] | 1553 | parallel::strategy = hardware_concurrency(threads); |
| 1554 | config->thinLTOJobs = v.str(); |
| 1555 | } |
Alexandre Ganea | 97b2b06 | 2019-02-27 20:53:50 | [diff] [blame] | 1556 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1557 | if (args.hasArg(OPT_show_timing)) |
| 1558 | config->showTiming = true; |
Zachary Turner | 727f153 | 2018-01-17 19:16:26 | [diff] [blame] | 1559 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1560 | config->showSummary = args.hasArg(OPT_summary); |
Tobias Hieta | 33f9342 | 2023-07-12 07:22:06 | [diff] [blame] | 1561 | config->printSearchPaths = args.hasArg(OPT_print_search_paths); |
Alexandre Ganea | 3e60ee9 | 2019-03-14 18:45:08 | [diff] [blame] | 1562 | |
Rui Ueyama | a4cf97b | 2017-10-23 14:57:53 | [diff] [blame] | 1563 | // Handle --version, which is an lld extension. This option is a bit odd |
| 1564 | // because it doesn't start with "/", but we deliberately chose "--" to |
| 1565 | // avoid conflict with /version and for compatibility with clang-cl. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1566 | if (args.hasArg(OPT_dash_dash_version)) { |
Fangrui Song | bc66e9a | 2024-12-04 05:29:02 | [diff] [blame] | 1567 | Msg(ctx) << getLLDVersion(); |
Rui Ueyama | a4cf97b | 2017-10-23 14:57:53 | [diff] [blame] | 1568 | return; |
| 1569 | } |
| 1570 | |
Martin Storsjo | 31fe4cd | 2017-09-13 19:29:39 | [diff] [blame] | 1571 | // Handle /lldmingw early, since it can potentially affect how other |
| 1572 | // options are handled. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1573 | config->mingw = args.hasArg(OPT_lldmingw); |
Alvin Wong | de4364f | 2022-11-10 11:32:07 | [diff] [blame] | 1574 | if (config->mingw) |
| 1575 | ctx.e.errorLimitExceededMsg = "too many errors emitted, stopping now" |
| 1576 | " (use --error-limit=0 to see all errors)"; |
Martin Storsjo | 31fe4cd | 2017-09-13 19:29:39 | [diff] [blame] | 1577 | |
Rui Ueyama | 0d53ac8 | 2019-10-04 07:27:38 | [diff] [blame] | 1578 | // Handle /linkrepro and /reproduce. |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1579 | { |
| 1580 | llvm::TimeTraceScope timeScope2("Reproducer"); |
| 1581 | if (std::optional<std::string> path = getReproduceFile(args)) { |
| 1582 | Expected<std::unique_ptr<TarWriter>> errOrWriter = |
| 1583 | TarWriter::create(*path, sys::path::stem(*path)); |
Rui Ueyama | 6785824 | 2019-10-04 07:27:31 | [diff] [blame] | 1584 | |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1585 | if (errOrWriter) { |
| 1586 | tar = std::move(*errOrWriter); |
| 1587 | } else { |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1588 | Err(ctx) << "/linkrepro: failed to open " << *path << ": " |
| 1589 | << toString(errOrWriter.takeError()); |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1590 | } |
Rui Ueyama | 7f1f912 | 2017-01-06 02:33:53 | [diff] [blame] | 1591 | } |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 1592 | } |
| 1593 | |
Reid Kleckner | ce0f3ee | 2019-11-07 21:50:31 | [diff] [blame] | 1594 | if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1595 | if (args.hasArg(OPT_deffile)) |
| 1596 | config->noEntry = true; |
Saleem Abdulrasool | bc7ff70 | 2017-06-15 20:39:58 | [diff] [blame] | 1597 | else |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1598 | Fatal(ctx) << "no input files"; |
Saleem Abdulrasool | bc7ff70 | 2017-06-15 20:39:58 | [diff] [blame] | 1599 | } |
Rui Ueyama | 3d3e6fb | 2015-05-29 16:06:00 | [diff] [blame] | 1600 | |
Rui Ueyama | f00df0a | 2015-06-19 22:39:48 | [diff] [blame] | 1601 | // Construct search path list. |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1602 | { |
| 1603 | llvm::TimeTraceScope timeScope2("Search paths"); |
| 1604 | searchPaths.emplace_back(""); |
Martin Storsjö | 92126ca | 2024-01-15 20:52:57 | [diff] [blame] | 1605 | for (auto *arg : args.filtered(OPT_libpath)) |
| 1606 | searchPaths.push_back(arg->getValue()); |
Martin Storsjö | 241c290 | 2023-02-15 10:06:45 | [diff] [blame] | 1607 | if (!config->mingw) { |
| 1608 | // Prefer the Clang provided builtins over the ones bundled with MSVC. |
| 1609 | // In MinGW mode, the compiler driver passes the necessary libpath |
| 1610 | // options explicitly. |
| 1611 | addClangLibSearchPaths(argsArr[0]); |
Martin Storsjö | 241c290 | 2023-02-15 10:06:45 | [diff] [blame] | 1612 | // Don't automatically deduce the lib path from the environment or MSVC |
| 1613 | // installations when operating in mingw mode. (This also makes LLD ignore |
| 1614 | // winsysroot and vctoolsdir arguments.) |
| 1615 | detectWinSysRoot(args); |
| 1616 | if (!args.hasArg(OPT_lldignoreenv) && !args.hasArg(OPT_winsysroot)) |
| 1617 | addLibSearchPaths(); |
| 1618 | } else { |
| 1619 | if (args.hasArg(OPT_vctoolsdir, OPT_winsysroot)) |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 1620 | Warn(ctx) << "ignoring /vctoolsdir or /winsysroot flags in MinGW mode"; |
Martin Storsjö | 241c290 | 2023-02-15 10:06:45 | [diff] [blame] | 1621 | } |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1622 | } |
Rui Ueyama | f00df0a | 2015-06-19 22:39:48 | [diff] [blame] | 1623 | |
Bob Haarman | e90ac01 | 2017-12-28 07:02:13 | [diff] [blame] | 1624 | // Handle /ignore |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1625 | for (auto *arg : args.filtered(OPT_ignore)) { |
| 1626 | SmallVector<StringRef, 8> vec; |
| 1627 | StringRef(arg->getValue()).split(vec, ','); |
| 1628 | for (StringRef s : vec) { |
| 1629 | if (s == "4037") |
| 1630 | config->warnMissingOrderSymbol = false; |
| 1631 | else if (s == "4099") |
| 1632 | config->warnDebugInfoUnusable = false; |
| 1633 | else if (s == "4217") |
| 1634 | config->warnLocallyDefinedImported = false; |
Reid Kleckner | deaf121 | 2019-10-29 22:57:40 | [diff] [blame] | 1635 | else if (s == "longsections") |
| 1636 | config->warnLongSectionNames = false; |
Alexandre Ganea | 27ba559 | 2019-01-11 19:10:01 | [diff] [blame] | 1637 | // Other warning numbers are ignored. |
| 1638 | } |
Bob Haarman | e90ac01 | 2017-12-28 07:02:13 | [diff] [blame] | 1639 | } |
| 1640 | |
Rui Ueyama | ad66098 | 2015-06-07 00:20:32 | [diff] [blame] | 1641 | // Handle /out |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1642 | if (auto *arg = args.getLastArg(OPT_out)) |
| 1643 | config->outputFile = arg->getValue(); |
Rui Ueyama | ad66098 | 2015-06-07 00:20:32 | [diff] [blame] | 1644 | |
Rui Ueyama | 3d3e6fb | 2015-05-29 16:06:00 | [diff] [blame] | 1645 | // Handle /verbose |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1646 | if (args.hasArg(OPT_verbose)) |
| 1647 | config->verbose = true; |
Fangrui Song | 1bfe55af | 2024-11-17 02:31:57 | [diff] [blame] | 1648 | ctx.e.verbose = config->verbose; |
Rui Ueyama | 3d3e6fb | 2015-05-29 16:06:00 | [diff] [blame] | 1649 | |
Rui Ueyama | 95925fd | 2015-06-28 19:35:15 | [diff] [blame] | 1650 | // Handle /force or /force:unresolved |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1651 | if (args.hasArg(OPT_force, OPT_force_unresolved)) |
| 1652 | config->forceUnresolved = true; |
Rui Ueyama | 11ca38f | 2018-09-13 22:05:10 | [diff] [blame] | 1653 | |
| 1654 | // Handle /force or /force:multiple |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1655 | if (args.hasArg(OPT_force, OPT_force_multiple)) |
| 1656 | config->forceMultiple = true; |
Rui Ueyama | 95925fd | 2015-06-28 19:35:15 | [diff] [blame] | 1657 | |
Nico Weber | 81862f8 | 2019-05-02 21:21:55 | [diff] [blame] | 1658 | // Handle /force or /force:multipleres |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1659 | if (args.hasArg(OPT_force, OPT_force_multipleres)) |
| 1660 | config->forceMultipleRes = true; |
Nico Weber | 81862f8 | 2019-05-02 21:21:55 | [diff] [blame] | 1661 | |
Martin Storsjö | e6e615c | 2023-12-15 18:07:22 | [diff] [blame] | 1662 | // Don't warn about long section names, such as .debug_info, for mingw (or |
| 1663 | // when -debug:dwarf is requested, handled below). |
| 1664 | if (config->mingw) |
| 1665 | config->warnLongSectionNames = false; |
| 1666 | |
| 1667 | bool doGC = true; |
| 1668 | |
Rui Ueyama | 6600eb1 | 2015-07-04 23:37:32 | [diff] [blame] | 1669 | // Handle /debug |
Martin Storsjö | e6e615c | 2023-12-15 18:07:22 | [diff] [blame] | 1670 | bool shouldCreatePDB = false; |
Martin Storsjö | efe017f | 2023-12-15 18:09:24 | [diff] [blame] | 1671 | for (auto *arg : args.filtered(OPT_debug, OPT_debug_opt)) { |
| 1672 | std::string str; |
Martin Storsjö | e6e615c | 2023-12-15 18:07:22 | [diff] [blame] | 1673 | if (arg->getOption().getID() == OPT_debug) |
Martin Storsjö | efe017f | 2023-12-15 18:09:24 | [diff] [blame] | 1674 | str = "full"; |
Martin Storsjö | e6e615c | 2023-12-15 18:07:22 | [diff] [blame] | 1675 | else |
Martin Storsjö | efe017f | 2023-12-15 18:09:24 | [diff] [blame] | 1676 | str = StringRef(arg->getValue()).lower(); |
| 1677 | SmallVector<StringRef, 1> vec; |
| 1678 | StringRef(str).split(vec, ','); |
| 1679 | for (StringRef s : vec) { |
| 1680 | if (s == "fastlink") { |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 1681 | Warn(ctx) << "/debug:fastlink unsupported; using /debug:full"; |
Martin Storsjö | efe017f | 2023-12-15 18:09:24 | [diff] [blame] | 1682 | s = "full"; |
| 1683 | } |
| 1684 | if (s == "none") { |
| 1685 | config->debug = false; |
| 1686 | config->incremental = false; |
| 1687 | config->includeDwarfChunks = false; |
| 1688 | config->debugGHashes = false; |
| 1689 | config->writeSymtab = false; |
| 1690 | shouldCreatePDB = false; |
| 1691 | doGC = true; |
| 1692 | } else if (s == "full" || s == "ghash" || s == "noghash") { |
| 1693 | config->debug = true; |
| 1694 | config->incremental = true; |
| 1695 | config->includeDwarfChunks = true; |
| 1696 | if (s == "full" || s == "ghash") |
| 1697 | config->debugGHashes = true; |
| 1698 | shouldCreatePDB = true; |
| 1699 | doGC = false; |
| 1700 | } else if (s == "dwarf") { |
| 1701 | config->debug = true; |
| 1702 | config->incremental = true; |
| 1703 | config->includeDwarfChunks = true; |
| 1704 | config->writeSymtab = true; |
| 1705 | config->warnLongSectionNames = false; |
| 1706 | doGC = false; |
Martin Storsjö | e36535d | 2023-12-15 18:10:41 | [diff] [blame] | 1707 | } else if (s == "nodwarf") { |
| 1708 | config->includeDwarfChunks = false; |
Martin Storsjö | efe017f | 2023-12-15 18:09:24 | [diff] [blame] | 1709 | } else if (s == "symtab") { |
| 1710 | config->writeSymtab = true; |
| 1711 | doGC = false; |
Martin Storsjö | e36535d | 2023-12-15 18:10:41 | [diff] [blame] | 1712 | } else if (s == "nosymtab") { |
| 1713 | config->writeSymtab = false; |
Martin Storsjö | efe017f | 2023-12-15 18:09:24 | [diff] [blame] | 1714 | } else { |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1715 | Err(ctx) << "/debug: unknown option: " << s; |
Martin Storsjö | efe017f | 2023-12-15 18:09:24 | [diff] [blame] | 1716 | } |
Martin Storsjö | e6e615c | 2023-12-15 18:07:22 | [diff] [blame] | 1717 | } |
Saleem Abdulrasool | a2cca7e | 2016-08-08 22:02:44 | [diff] [blame] | 1718 | } |
Rui Ueyama | 6600eb1 | 2015-07-04 23:37:32 | [diff] [blame] | 1719 | |
Nico Weber | 020d92c | 2019-03-11 23:02:18 | [diff] [blame] | 1720 | // Handle /demangle |
Fangrui Song | c37accf | 2022-03-26 07:57:06 | [diff] [blame] | 1721 | config->demangle = args.hasFlag(OPT_demangle, OPT_demangle_no, true); |
Nico Weber | 020d92c | 2019-03-11 23:02:18 | [diff] [blame] | 1722 | |
Will Wilson | 3cb1834 | 2018-09-24 15:28:03 | [diff] [blame] | 1723 | // Handle /debugtype |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 1724 | config->debugTypes = parseDebugTypes(ctx, args); |
Will Wilson | 3cb1834 | 2018-09-24 15:28:03 | [diff] [blame] | 1725 | |
Rui Ueyama | f95ed69 | 2019-11-13 04:53:15 | [diff] [blame] | 1726 | // Handle /driver[:uponly|:wdm]. |
| 1727 | config->driverUponly = args.hasArg(OPT_driver_uponly) || |
| 1728 | args.hasArg(OPT_driver_uponly_wdm) || |
| 1729 | args.hasArg(OPT_driver_wdm_uponly); |
| 1730 | config->driverWdm = args.hasArg(OPT_driver_wdm) || |
| 1731 | args.hasArg(OPT_driver_uponly_wdm) || |
| 1732 | args.hasArg(OPT_driver_wdm_uponly); |
| 1733 | config->driver = |
| 1734 | config->driverUponly || config->driverWdm || args.hasArg(OPT_driver); |
| 1735 | |
Shoaib Meenai | c4fdbca | 2017-12-15 23:52:46 | [diff] [blame] | 1736 | // Handle /pdb |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1737 | if (shouldCreatePDB) { |
| 1738 | if (auto *arg = args.getLastArg(OPT_pdb)) |
| 1739 | config->pdbPath = arg->getValue(); |
| 1740 | if (auto *arg = args.getLastArg(OPT_pdbaltpath)) |
| 1741 | config->pdbAltPath = arg->getValue(); |
Nico Weber | f964ca8 | 2021-10-30 15:22:55 | [diff] [blame] | 1742 | if (auto *arg = args.getLastArg(OPT_pdbpagesize)) |
| 1743 | parsePDBPageSize(arg->getValue()); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1744 | if (args.hasArg(OPT_natvis)) |
| 1745 | config->natvisFiles = args.getAllArgValues(OPT_natvis); |
Eric Astor | a39b14f | 2020-04-07 20:16:22 | [diff] [blame] | 1746 | if (args.hasArg(OPT_pdbstream)) { |
| 1747 | for (const StringRef value : args.getAllArgValues(OPT_pdbstream)) { |
| 1748 | const std::pair<StringRef, StringRef> nameFile = value.split("="); |
| 1749 | const StringRef name = nameFile.first; |
| 1750 | const std::string file = nameFile.second.str(); |
| 1751 | config->namedStreams[name] = file; |
| 1752 | } |
| 1753 | } |
Takuto Ikuta | d855928 | 2018-07-19 04:56:22 | [diff] [blame] | 1754 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1755 | if (auto *arg = args.getLastArg(OPT_pdb_source_path)) |
| 1756 | config->pdbSourcePath = arg->getValue(); |
Zachary Turner | f228276 | 2018-03-23 19:57:25 | [diff] [blame] | 1757 | } |
Saleem Abdulrasool | 8fcff93 | 2016-08-29 21:20:46 | [diff] [blame] | 1758 | |
Reid Kleckner | 8045a8a | 2020-01-15 23:09:25 | [diff] [blame] | 1759 | // Handle /pdbstripped |
Martin Storsjö | e6b0ce7 | 2020-01-23 11:23:12 | [diff] [blame] | 1760 | if (args.hasArg(OPT_pdbstripped)) |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 1761 | Warn(ctx) << "ignoring /pdbstripped flag, it is not yet supported"; |
Reid Kleckner | 8045a8a | 2020-01-15 23:09:25 | [diff] [blame] | 1762 | |
Rui Ueyama | a8b6045 | 2015-06-28 19:56:30 | [diff] [blame] | 1763 | // Handle /noentry |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1764 | if (args.hasArg(OPT_noentry)) { |
| 1765 | if (args.hasArg(OPT_dll)) |
| 1766 | config->noEntry = true; |
Bob Haarman | ac8f7fc | 2017-04-05 00:43:54 | [diff] [blame] | 1767 | else |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1768 | Err(ctx) << "/noentry must be specified with /dll"; |
Rui Ueyama | a8b6045 | 2015-06-28 19:56:30 | [diff] [blame] | 1769 | } |
| 1770 | |
Rui Ueyama | 97dff9e | 2015-06-17 00:16:33 | [diff] [blame] | 1771 | // Handle /dll |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1772 | if (args.hasArg(OPT_dll)) { |
| 1773 | config->dll = true; |
| 1774 | config->manifestID = 2; |
Rui Ueyama | 24c5fd0 | 2015-06-18 00:12:42 | [diff] [blame] | 1775 | } |
Rui Ueyama | 97dff9e | 2015-06-17 00:16:33 | [diff] [blame] | 1776 | |
Shoaib Meenai | 59bf362 | 2017-10-24 21:17:16 | [diff] [blame] | 1777 | // Handle /dynamicbase and /fixed. We can't use hasFlag for /dynamicbase |
| 1778 | // because we need to explicitly check whether that option or its inverse was |
| 1779 | // present in the argument list in order to handle /fixed. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1780 | auto *dynamicBaseArg = args.getLastArg(OPT_dynamicbase, OPT_dynamicbase_no); |
| 1781 | if (dynamicBaseArg && |
| 1782 | dynamicBaseArg->getOption().getID() == OPT_dynamicbase_no) |
| 1783 | config->dynamicBase = false; |
Shoaib Meenai | 59bf362 | 2017-10-24 21:17:16 | [diff] [blame] | 1784 | |
Nico Weber | a764379 | 2018-03-30 17:17:04 | [diff] [blame] | 1785 | // MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the |
| 1786 | // default setting for any other project type.", but link.exe defaults to |
| 1787 | // /FIXED:NO for exe outputs as well. Match behavior, not docs. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1788 | bool fixed = args.hasFlag(OPT_fixed, OPT_fixed_no, false); |
| 1789 | if (fixed) { |
| 1790 | if (dynamicBaseArg && |
| 1791 | dynamicBaseArg->getOption().getID() == OPT_dynamicbase) { |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1792 | Err(ctx) << "/fixed must not be specified with /dynamicbase"; |
Bob Haarman | ac8f7fc | 2017-04-05 00:43:54 | [diff] [blame] | 1793 | } else { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1794 | config->relocatable = false; |
| 1795 | config->dynamicBase = false; |
Bob Haarman | ac8f7fc | 2017-04-05 00:43:54 | [diff] [blame] | 1796 | } |
Rui Ueyama | 6592ff8 | 2015-06-16 23:13:00 | [diff] [blame] | 1797 | } |
Rui Ueyama | 588e832 | 2015-06-15 01:23:58 | [diff] [blame] | 1798 | |
Shoaib Meenai | 59bf362 | 2017-10-24 21:17:16 | [diff] [blame] | 1799 | // Handle /appcontainer |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1800 | config->appContainer = |
| 1801 | args.hasFlag(OPT_appcontainer, OPT_appcontainer_no, false); |
Saleem Abdulrasool | 671029d | 2017-04-06 23:07:53 | [diff] [blame] | 1802 | |
Rui Ueyama | 3d3e6fb | 2015-05-29 16:06:00 | [diff] [blame] | 1803 | // Handle /machine |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1804 | { |
| 1805 | llvm::TimeTraceScope timeScope2("Machine arg"); |
| 1806 | if (auto *arg = args.getLastArg(OPT_machine)) { |
Jacek Caban | 0a9810d | 2024-12-15 17:41:26 | [diff] [blame] | 1807 | MachineTypes machine = getMachineType(arg->getValue()); |
| 1808 | if (machine == IMAGE_FILE_MACHINE_UNKNOWN) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1809 | Fatal(ctx) << "unknown /machine argument: " << arg->getValue(); |
Jacek Caban | 0a9810d | 2024-12-15 17:41:26 | [diff] [blame] | 1810 | setMachine(machine); |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1811 | } |
Nico Weber | b941fa8 | 2019-06-11 01:13:41 | [diff] [blame] | 1812 | } |
Jacek Caban | 4e9d5a3 | 2025-01-22 22:32:18 | [diff] [blame] | 1813 | |
Rui Ueyama | d21b00b | 2015-05-31 19:17:14 | [diff] [blame] | 1814 | // Handle /nodefaultlib:<filename> |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 1815 | { |
| 1816 | llvm::TimeTraceScope timeScope2("Nodefaultlib"); |
| 1817 | for (auto *arg : args.filtered(OPT_nodefaultlib)) |
| 1818 | config->noDefaultLibs.insert(findLib(arg->getValue()).lower()); |
| 1819 | } |
Rui Ueyama | d21b00b | 2015-05-31 19:17:14 | [diff] [blame] | 1820 | |
| 1821 | // Handle /nodefaultlib |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1822 | if (args.hasArg(OPT_nodefaultlib_all)) |
| 1823 | config->noDefaultLibAll = true; |
Rui Ueyama | d21b00b | 2015-05-31 19:17:14 | [diff] [blame] | 1824 | |
Rui Ueyama | 804a8b6 | 2015-05-29 16:18:15 | [diff] [blame] | 1825 | // Handle /base |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1826 | if (auto *arg = args.getLastArg(OPT_base)) |
| 1827 | parseNumbers(arg->getValue(), &config->imageBase); |
Rui Ueyama | b41b7e5 | 2015-05-29 16:21:11 | [diff] [blame] | 1828 | |
Rui Ueyama | 74de620 | 2019-05-24 12:42:36 | [diff] [blame] | 1829 | // Handle /filealign |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1830 | if (auto *arg = args.getLastArg(OPT_filealign)) { |
| 1831 | parseNumbers(arg->getValue(), &config->fileAlign); |
| 1832 | if (!isPowerOf2_64(config->fileAlign)) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1833 | Err(ctx) << "/filealign: not a power of two: " << config->fileAlign; |
Rui Ueyama | 74de620 | 2019-05-24 12:42:36 | [diff] [blame] | 1834 | } |
| 1835 | |
Rui Ueyama | b41b7e5 | 2015-05-29 16:21:11 | [diff] [blame] | 1836 | // Handle /stack |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1837 | if (auto *arg = args.getLastArg(OPT_stack)) |
| 1838 | parseNumbers(arg->getValue(), &config->stackReserve, &config->stackCommit); |
Rui Ueyama | 804a8b6 | 2015-05-29 16:18:15 | [diff] [blame] | 1839 | |
Reid Kleckner | af2f7da | 2018-02-06 01:58:26 | [diff] [blame] | 1840 | // Handle /guard:cf |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1841 | if (auto *arg = args.getLastArg(OPT_guard)) |
| 1842 | parseGuard(arg->getValue()); |
Reid Kleckner | af2f7da | 2018-02-06 01:58:26 | [diff] [blame] | 1843 | |
Rui Ueyama | c377e9a | 2015-05-29 16:23:40 | [diff] [blame] | 1844 | // Handle /heap |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1845 | if (auto *arg = args.getLastArg(OPT_heap)) |
| 1846 | parseNumbers(arg->getValue(), &config->heapReserve, &config->heapCommit); |
Rui Ueyama | c377e9a | 2015-05-29 16:23:40 | [diff] [blame] | 1847 | |
Rui Ueyama | b9dcdb5 | 2015-05-29 16:28:29 | [diff] [blame] | 1848 | // Handle /version |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1849 | if (auto *arg = args.getLastArg(OPT_version)) |
| 1850 | parseVersion(arg->getValue(), &config->majorImageVersion, |
| 1851 | &config->minorImageVersion); |
Rui Ueyama | b9dcdb5 | 2015-05-29 16:28:29 | [diff] [blame] | 1852 | |
Rui Ueyama | 15cc47e | 2015-05-29 16:34:31 | [diff] [blame] | 1853 | // Handle /subsystem |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1854 | if (auto *arg = args.getLastArg(OPT_subsystem)) |
Martin Storsjö | 45c4c54 | 2020-10-03 22:29:45 | [diff] [blame] | 1855 | parseSubsystem(arg->getValue(), &config->subsystem, |
| 1856 | &config->majorSubsystemVersion, |
| 1857 | &config->minorSubsystemVersion); |
| 1858 | |
| 1859 | // Handle /osversion |
| 1860 | if (auto *arg = args.getLastArg(OPT_osversion)) { |
| 1861 | parseVersion(arg->getValue(), &config->majorOSVersion, |
| 1862 | &config->minorOSVersion); |
| 1863 | } else { |
| 1864 | config->majorOSVersion = config->majorSubsystemVersion; |
| 1865 | config->minorOSVersion = config->minorSubsystemVersion; |
| 1866 | } |
Rui Ueyama | 15cc47e | 2015-05-29 16:34:31 | [diff] [blame] | 1867 | |
Zachary Turner | c8dd6cc | 2018-05-17 15:11:01 | [diff] [blame] | 1868 | // Handle /timestamp |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1869 | if (llvm::opt::Arg *arg = args.getLastArg(OPT_timestamp, OPT_repro)) { |
| 1870 | if (arg->getOption().getID() == OPT_repro) { |
| 1871 | config->timestamp = 0; |
| 1872 | config->repro = true; |
Zachary Turner | c8dd6cc | 2018-05-17 15:11:01 | [diff] [blame] | 1873 | } else { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1874 | config->repro = false; |
| 1875 | StringRef value(arg->getValue()); |
| 1876 | if (value.getAsInteger(0, config->timestamp)) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1877 | Fatal(ctx) << "invalid timestamp: " << value |
| 1878 | << ". Expected 32-bit integer"; |
Zachary Turner | c8dd6cc | 2018-05-17 15:11:01 | [diff] [blame] | 1879 | } |
| 1880 | } else { |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1881 | config->repro = false; |
Martin Storsjö | 0df8aed | 2024-02-10 21:57:12 | [diff] [blame] | 1882 | if (std::optional<std::string> epoch = |
| 1883 | Process::GetEnv("SOURCE_DATE_EPOCH")) { |
| 1884 | StringRef value(*epoch); |
| 1885 | if (value.getAsInteger(0, config->timestamp)) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 1886 | Fatal(ctx) << "invalid SOURCE_DATE_EPOCH timestamp: " << value |
| 1887 | << ". Expected 32-bit integer"; |
Martin Storsjö | 0df8aed | 2024-02-10 21:57:12 | [diff] [blame] | 1888 | } else { |
| 1889 | config->timestamp = time(nullptr); |
| 1890 | } |
Zachary Turner | c8dd6cc | 2018-05-17 15:11:01 | [diff] [blame] | 1891 | } |
| 1892 | |
Rui Ueyama | 2edb35a | 2015-06-18 19:09:30 | [diff] [blame] | 1893 | // Handle /alternatename |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1894 | for (auto *arg : args.filtered(OPT_alternatename)) |
Jacek Caban | 1c05c61 | 2025-04-11 13:53:25 | [diff] [blame] | 1895 | ctx.symtab.parseAlternateName(arg->getValue()); |
Rui Ueyama | 2edb35a | 2015-06-18 19:09:30 | [diff] [blame] | 1896 | |
Rui Ueyama | 08d5e18 | 2015-06-18 23:20:11 | [diff] [blame] | 1897 | // Handle /include |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1898 | for (auto *arg : args.filtered(OPT_incl)) |
Jacek Caban | 1c05c61 | 2025-04-11 13:53:25 | [diff] [blame] | 1899 | ctx.symtab.addGCRoot(arg->getValue()); |
Rui Ueyama | 08d5e18 | 2015-06-18 23:20:11 | [diff] [blame] | 1900 | |
Rui Ueyama | b95188c | 2015-06-18 20:27:09 | [diff] [blame] | 1901 | // Handle /implib |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1902 | if (auto *arg = args.getLastArg(OPT_implib)) |
| 1903 | config->implib = arg->getValue(); |
Rui Ueyama | b95188c | 2015-06-18 20:27:09 | [diff] [blame] | 1904 | |
Tobias Hieta | 837d16f | 2022-04-13 14:39:22 | [diff] [blame] | 1905 | config->noimplib = args.hasArg(OPT_noimplib); |
Tobias Hieta | eb4eef9 | 2022-04-12 14:06:46 | [diff] [blame] | 1906 | |
Martin Storsjö | e6e615c | 2023-12-15 18:07:22 | [diff] [blame] | 1907 | if (args.hasArg(OPT_profile)) |
| 1908 | doGC = true; |
Reid Kleckner | c2dcdd8 | 2017-11-13 18:38:25 | [diff] [blame] | 1909 | // Handle /opt. |
Kazu Hirata | fd8d0b0 | 2022-11-27 04:53:26 | [diff] [blame] | 1910 | std::optional<ICFLevel> icfLevel; |
Zequan Wu | 5bdc5e7 | 2021-02-27 00:38:24 | [diff] [blame] | 1911 | if (args.hasArg(OPT_profile)) |
| 1912 | icfLevel = ICFLevel::None; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1913 | unsigned tailMerge = 1; |
rojamd | b79e990 | 2020-11-05 19:41:35 | [diff] [blame] | 1914 | bool ltoDebugPM = false; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1915 | for (auto *arg : args.filtered(OPT_opt)) { |
| 1916 | std::string str = StringRef(arg->getValue()).lower(); |
| 1917 | SmallVector<StringRef, 1> vec; |
| 1918 | StringRef(str).split(vec, ','); |
| 1919 | for (StringRef s : vec) { |
| 1920 | if (s == "ref") { |
| 1921 | doGC = true; |
| 1922 | } else if (s == "noref") { |
| 1923 | doGC = false; |
Fangrui Song | 8d85c96 | 2023-06-05 21:36:19 | [diff] [blame] | 1924 | } else if (s == "icf" || s.starts_with("icf=")) { |
Zequan Wu | 5bdc5e7 | 2021-02-27 00:38:24 | [diff] [blame] | 1925 | icfLevel = ICFLevel::All; |
| 1926 | } else if (s == "safeicf") { |
| 1927 | icfLevel = ICFLevel::Safe; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1928 | } else if (s == "noicf") { |
Zequan Wu | 5bdc5e7 | 2021-02-27 00:38:24 | [diff] [blame] | 1929 | icfLevel = ICFLevel::None; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1930 | } else if (s == "lldtailmerge") { |
| 1931 | tailMerge = 2; |
| 1932 | } else if (s == "nolldtailmerge") { |
| 1933 | tailMerge = 0; |
rojamd | b79e990 | 2020-11-05 19:41:35 | [diff] [blame] | 1934 | } else if (s == "ltodebugpassmanager") { |
| 1935 | ltoDebugPM = true; |
| 1936 | } else if (s == "noltodebugpassmanager") { |
| 1937 | ltoDebugPM = false; |
Fangrui Song | 0534791 | 2023-01-30 23:28:10 | [diff] [blame] | 1938 | } else if (s.consume_front("lldlto=")) { |
| 1939 | if (s.getAsInteger(10, config->ltoo) || config->ltoo > 3) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1940 | Err(ctx) << "/opt:lldlto: invalid optimization level: " << s; |
Scott Linder | 45ee0a9 | 2023-02-15 17:12:47 | [diff] [blame] | 1941 | } else if (s.consume_front("lldltocgo=")) { |
| 1942 | config->ltoCgo.emplace(); |
| 1943 | if (s.getAsInteger(10, *config->ltoCgo) || *config->ltoCgo > 3) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1944 | Err(ctx) << "/opt:lldltocgo: invalid codegen optimization level: " |
| 1945 | << s; |
Fangrui Song | 0534791 | 2023-01-30 23:28:10 | [diff] [blame] | 1946 | } else if (s.consume_front("lldltojobs=")) { |
| 1947 | if (!get_threadpool_strategy(s)) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1948 | Err(ctx) << "/opt:lldltojobs: invalid job count: " << s; |
Fangrui Song | 0534791 | 2023-01-30 23:28:10 | [diff] [blame] | 1949 | config->thinLTOJobs = s.str(); |
| 1950 | } else if (s.consume_front("lldltopartitions=")) { |
| 1951 | if (s.getAsInteger(10, config->ltoPartitions) || |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1952 | config->ltoPartitions == 0) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1953 | Err(ctx) << "/opt:lldltopartitions: invalid partition count: " << s; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1954 | } else if (s != "lbr" && s != "nolbr") |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1955 | Err(ctx) << "/opt: unknown option: " << s; |
Rui Ueyama | e2cbfea | 2015-06-07 03:17:42 | [diff] [blame] | 1956 | } |
Rui Ueyama | e2cbfea | 2015-06-07 03:17:42 | [diff] [blame] | 1957 | } |
| 1958 | |
Zequan Wu | 5bdc5e7 | 2021-02-27 00:38:24 | [diff] [blame] | 1959 | if (!icfLevel) |
| 1960 | icfLevel = doGC ? ICFLevel::All : ICFLevel::None; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1961 | config->doGC = doGC; |
Kazu Hirata | ed8fcea | 2022-06-21 06:35:53 | [diff] [blame] | 1962 | config->doICF = *icfLevel; |
Zequan Wu | 5bdc5e7 | 2021-02-27 00:38:24 | [diff] [blame] | 1963 | config->tailMerge = |
| 1964 | (tailMerge == 1 && config->doICF != ICFLevel::None) || tailMerge == 2; |
rojamd | b79e990 | 2020-11-05 19:41:35 | [diff] [blame] | 1965 | config->ltoDebugPassManager = ltoDebugPM; |
Reid Kleckner | c2dcdd8 | 2017-11-13 18:38:25 | [diff] [blame] | 1966 | |
Bob Haarman | 69b196d | 2017-02-08 18:36:41 | [diff] [blame] | 1967 | // Handle /lldsavetemps |
Miguel A. Arroyo | 5cd6e21 | 2024-11-12 20:30:48 | [diff] [blame] | 1968 | if (args.hasArg(OPT_lldsavetemps)) { |
Kazu Hirata | 1ff7491 | 2025-03-29 17:29:45 | [diff] [blame] | 1969 | config->saveTempsArgs.insert_range(lldsaveTempsValues); |
Miguel A. Arroyo | 5cd6e21 | 2024-11-12 20:30:48 | [diff] [blame] | 1970 | } else { |
| 1971 | for (auto *arg : args.filtered(OPT_lldsavetemps_colon)) { |
| 1972 | StringRef s = arg->getValue(); |
| 1973 | if (llvm::is_contained(lldsaveTempsValues, s)) |
| 1974 | config->saveTempsArgs.insert(s); |
| 1975 | else |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1976 | Err(ctx) << "unknown /lldsavetemps value: " << s; |
Miguel A. Arroyo | 5cd6e21 | 2024-11-12 20:30:48 | [diff] [blame] | 1977 | } |
| 1978 | } |
Bob Haarman | 69b196d | 2017-02-08 18:36:41 | [diff] [blame] | 1979 | |
Matheus Izvekov | 3923e61 | 2023-10-02 20:54:43 | [diff] [blame] | 1980 | // Handle /lldemit |
| 1981 | if (auto *arg = args.getLastArg(OPT_lldemit)) { |
| 1982 | StringRef s = arg->getValue(); |
| 1983 | if (s == "obj") |
| 1984 | config->emit = EmitKind::Obj; |
| 1985 | else if (s == "llvm") |
| 1986 | config->emit = EmitKind::LLVM; |
Matheus Izvekov | d12b99a | 2023-10-03 23:24:54 | [diff] [blame] | 1987 | else if (s == "asm") |
| 1988 | config->emit = EmitKind::ASM; |
Matheus Izvekov | 3923e61 | 2023-10-02 20:54:43 | [diff] [blame] | 1989 | else |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 1990 | Err(ctx) << "/lldemit: unknown option: " << s; |
Matheus Izvekov | 3923e61 | 2023-10-02 20:54:43 | [diff] [blame] | 1991 | } |
| 1992 | |
Martin Storsjo | 5351891 | 2018-03-14 20:17:16 | [diff] [blame] | 1993 | // Handle /kill-at |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1994 | if (args.hasArg(OPT_kill_at)) |
| 1995 | config->killAt = true; |
Martin Storsjo | 5351891 | 2018-03-14 20:17:16 | [diff] [blame] | 1996 | |
Peter Collingbourne | 052e855e | 2017-09-08 00:50:50 | [diff] [blame] | 1997 | // Handle /lldltocache |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 1998 | if (auto *arg = args.getLastArg(OPT_lldltocache)) |
| 1999 | config->ltoCache = arg->getValue(); |
Peter Collingbourne | 052e855e | 2017-09-08 00:50:50 | [diff] [blame] | 2000 | |
| 2001 | // Handle /lldsavecachepolicy |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2002 | if (auto *arg = args.getLastArg(OPT_lldltocachepolicy)) |
| 2003 | config->ltoCachePolicy = CHECK( |
| 2004 | parseCachePruningPolicy(arg->getValue()), |
| 2005 | Twine("/lldltocachepolicy: invalid cache policy: ") + arg->getValue()); |
Peter Collingbourne | 052e855e | 2017-09-08 00:50:50 | [diff] [blame] | 2006 | |
Rui Ueyama | 8854d8a | 2015-06-04 19:21:24 | [diff] [blame] | 2007 | // Handle /failifmismatch |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2008 | for (auto *arg : args.filtered(OPT_failifmismatch)) |
| 2009 | checkFailIfMismatch(arg->getValue(), nullptr); |
Rui Ueyama | 8854d8a | 2015-06-04 19:21:24 | [diff] [blame] | 2010 | |
Rui Ueyama | 6600eb1 | 2015-07-04 23:37:32 | [diff] [blame] | 2011 | // Handle /merge |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2012 | for (auto *arg : args.filtered(OPT_merge)) |
| 2013 | parseMerge(arg->getValue()); |
Rui Ueyama | 6600eb1 | 2015-07-04 23:37:32 | [diff] [blame] | 2014 | |
Peter Collingbourne | 66f1c9a | 2018-04-17 23:28:52 | [diff] [blame] | 2015 | // Add default section merging rules after user rules. User rules take |
| 2016 | // precedence, but we will emit a warning if there is a conflict. |
| 2017 | parseMerge(".idata=.rdata"); |
| 2018 | parseMerge(".didat=.rdata"); |
| 2019 | parseMerge(".edata=.rdata"); |
Peter Collingbourne | 3d636ed | 2018-04-20 21:32:37 | [diff] [blame] | 2020 | parseMerge(".xdata=.rdata"); |
Jacek Caban | f78024c | 2023-12-13 10:43:38 | [diff] [blame] | 2021 | parseMerge(".00cfg=.rdata"); |
Peter Collingbourne | 326f419 | 2018-04-20 21:30:36 | [diff] [blame] | 2022 | parseMerge(".bss=.data"); |
Peter Collingbourne | 66f1c9a | 2018-04-17 23:28:52 | [diff] [blame] | 2023 | |
Jacek Caban | 76243ad | 2023-12-25 19:31:08 | [diff] [blame] | 2024 | if (isArm64EC(config->machine)) |
| 2025 | parseMerge(".wowthk=.text"); |
| 2026 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2027 | if (config->mingw) { |
Martin Storsjo | cfbbb70 | 2018-08-29 17:24:10 | [diff] [blame] | 2028 | parseMerge(".ctors=.rdata"); |
| 2029 | parseMerge(".dtors=.rdata"); |
| 2030 | parseMerge(".CRT=.rdata"); |
jeremyd2019 | f66f2fe | 2025-05-02 07:58:14 | [diff] [blame] | 2031 | parseMerge(".data_cygwin_nocopy=.data"); |
Martin Storsjo | cfbbb70 | 2018-08-29 17:24:10 | [diff] [blame] | 2032 | } |
| 2033 | |
Rui Ueyama | 440138c | 2016-06-20 03:39:39 | [diff] [blame] | 2034 | // Handle /section |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2035 | for (auto *arg : args.filtered(OPT_section)) |
| 2036 | parseSection(arg->getValue()); |
Rui Ueyama | 440138c | 2016-06-20 03:39:39 | [diff] [blame] | 2037 | |
Rui Ueyama | e6a33e1 | 2019-08-07 10:16:21 | [diff] [blame] | 2038 | // Handle /align |
| 2039 | if (auto *arg = args.getLastArg(OPT_align)) { |
| 2040 | parseNumbers(arg->getValue(), &config->align); |
| 2041 | if (!isPowerOf2_64(config->align)) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 2042 | Err(ctx) << "/align: not a power of two: " << StringRef(arg->getValue()); |
Rui Ueyama | 000ff30 | 2019-11-13 04:43:25 | [diff] [blame] | 2043 | if (!args.hasArg(OPT_driver)) |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 2044 | Warn(ctx) << "/align specified without /driver; image may not run"; |
Rui Ueyama | e6a33e1 | 2019-08-07 10:16:21 | [diff] [blame] | 2045 | } |
| 2046 | |
Martin Storsjo | d2752aa | 2017-08-14 19:07:27 | [diff] [blame] | 2047 | // Handle /aligncomm |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2048 | for (auto *arg : args.filtered(OPT_aligncomm)) |
Jacek Caban | 1c05c61 | 2025-04-11 13:53:25 | [diff] [blame] | 2049 | ctx.symtab.parseAligncomm(arg->getValue()); |
Martin Storsjo | d2752aa | 2017-08-14 19:07:27 | [diff] [blame] | 2050 | |
Nico Weber | 400a1de | 2021-08-24 14:19:21 | [diff] [blame] | 2051 | // Handle /manifestdependency. |
| 2052 | for (auto *arg : args.filtered(OPT_manifestdependency)) |
| 2053 | config->manifestDependencies.insert(arg->getValue()); |
Nico Weber | a7a2c44 | 2017-07-25 18:08:03 | [diff] [blame] | 2054 | |
| 2055 | // Handle /manifest and /manifest: |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2056 | if (auto *arg = args.getLastArg(OPT_manifest, OPT_manifest_colon)) { |
| 2057 | if (arg->getOption().getID() == OPT_manifest) |
| 2058 | config->manifest = Configuration::SideBySide; |
Nico Weber | a7a2c44 | 2017-07-25 18:08:03 | [diff] [blame] | 2059 | else |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2060 | parseManifest(arg->getValue()); |
Nico Weber | a7a2c44 | 2017-07-25 18:08:03 | [diff] [blame] | 2061 | } |
Rui Ueyama | 24c5fd0 | 2015-06-18 00:12:42 | [diff] [blame] | 2062 | |
| 2063 | // Handle /manifestuac |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2064 | if (auto *arg = args.getLastArg(OPT_manifestuac)) |
| 2065 | parseManifestUAC(arg->getValue()); |
Rui Ueyama | 24c5fd0 | 2015-06-18 00:12:42 | [diff] [blame] | 2066 | |
Rui Ueyama | 24c5fd0 | 2015-06-18 00:12:42 | [diff] [blame] | 2067 | // Handle /manifestfile |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2068 | if (auto *arg = args.getLastArg(OPT_manifestfile)) |
| 2069 | config->manifestFile = arg->getValue(); |
Rui Ueyama | 24c5fd0 | 2015-06-18 00:12:42 | [diff] [blame] | 2070 | |
Rui Ueyama | afb1901 | 2016-04-19 01:21:58 | [diff] [blame] | 2071 | // Handle /manifestinput |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2072 | for (auto *arg : args.filtered(OPT_manifestinput)) |
| 2073 | config->manifestInput.push_back(arg->getValue()); |
Rui Ueyama | afb1901 | 2016-04-19 01:21:58 | [diff] [blame] | 2074 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2075 | if (!config->manifestInput.empty() && |
| 2076 | config->manifest != Configuration::Embed) { |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 2077 | Fatal(ctx) << "/manifestinput: requires /manifest:embed"; |
Nico Weber | a7a2c44 | 2017-07-25 18:08:03 | [diff] [blame] | 2078 | } |
| 2079 | |
Haohai Wen | 2a631a8 | 2023-07-01 00:58:56 | [diff] [blame] | 2080 | // Handle /dwodir |
| 2081 | config->dwoDir = args.getLastArgValue(OPT_dwodir); |
| 2082 | |
Bob Haarman | 63efb28 | 2019-07-11 18:03:14 | [diff] [blame] | 2083 | config->thinLTOEmitImportsFiles = args.hasArg(OPT_thinlto_emit_imports_files); |
| 2084 | config->thinLTOIndexOnly = args.hasArg(OPT_thinlto_index_only) || |
| 2085 | args.hasArg(OPT_thinlto_index_only_arg); |
| 2086 | config->thinLTOIndexOnlyArg = |
| 2087 | args.getLastArgValue(OPT_thinlto_index_only_arg); |
Ivan Tadeu Ferreira Antunes Filho | 73fd9d3 | 2023-04-04 16:57:53 | [diff] [blame] | 2088 | std::tie(config->thinLTOPrefixReplaceOld, config->thinLTOPrefixReplaceNew, |
| 2089 | config->thinLTOPrefixReplaceNativeObject) = |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 2090 | getOldNewOptionsExtra(ctx, args, OPT_thinlto_prefix_replace); |
Bob Haarman | 5011b83 | 2019-07-11 18:48:58 | [diff] [blame] | 2091 | config->thinLTOObjectSuffixReplace = |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 2092 | getOldNewOptions(ctx, args, OPT_thinlto_object_suffix_replace); |
Bob Haarman | 5375b94 | 2019-08-21 18:24:59 | [diff] [blame] | 2093 | config->ltoObjPath = args.getLastArgValue(OPT_lto_obj_path); |
Yolanda Chen | 4f9c61e | 2021-03-25 02:55:18 | [diff] [blame] | 2094 | config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); |
| 2095 | config->ltoCSProfileFile = args.getLastArgValue(OPT_lto_cs_profile_file); |
chrulski-intel | a9fe23c | 2024-03-20 15:02:43 | [diff] [blame] | 2096 | config->ltoSampleProfileName = args.getLastArgValue(OPT_lto_sample_profile); |
Rui Ueyama | 6592ff8 | 2015-06-16 23:13:00 | [diff] [blame] | 2097 | // Handle miscellaneous boolean flags. |
Yolanda Chen | 8fa16cc | 2021-08-11 16:45:55 | [diff] [blame] | 2098 | config->ltoPGOWarnMismatch = args.hasFlag(OPT_lto_pgo_warn_mismatch, |
| 2099 | OPT_lto_pgo_warn_mismatch_no, true); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2100 | config->allowBind = args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); |
| 2101 | config->allowIsolation = |
| 2102 | args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true); |
| 2103 | config->incremental = |
| 2104 | args.hasFlag(OPT_incremental, OPT_incremental_no, |
Zequan Wu | 5bdc5e7 | 2021-02-27 00:38:24 | [diff] [blame] | 2105 | !config->doGC && config->doICF == ICFLevel::None && |
| 2106 | !args.hasArg(OPT_order) && !args.hasArg(OPT_profile)); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2107 | config->integrityCheck = |
| 2108 | args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false); |
Rui Ueyama | a2923b2 | 2020-03-13 10:41:18 | [diff] [blame] | 2109 | config->cetCompat = args.hasFlag(OPT_cetcompat, OPT_cetcompat_no, false); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2110 | config->nxCompat = args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); |
| 2111 | for (auto *arg : args.filtered(OPT_swaprun)) |
| 2112 | parseSwaprun(arg->getValue()); |
| 2113 | config->terminalServerAware = |
| 2114 | !config->dll && args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); |
Martin Storsjö | 7f0e6c3 | 2020-04-25 21:49:44 | [diff] [blame] | 2115 | config->autoImport = |
| 2116 | args.hasFlag(OPT_auto_import, OPT_auto_import_no, config->mingw); |
| 2117 | config->pseudoRelocs = args.hasFlag( |
| 2118 | OPT_runtime_pseudo_reloc, OPT_runtime_pseudo_reloc_no, config->mingw); |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 2119 | config->callGraphProfileSort = args.hasFlag( |
| 2120 | OPT_call_graph_profile_sort, OPT_call_graph_profile_sort_no, true); |
Martin Storsjö | ce211c5 | 2021-06-17 18:51:37 | [diff] [blame] | 2121 | config->stdcallFixup = |
| 2122 | args.hasFlag(OPT_stdcall_fixup, OPT_stdcall_fixup_no, config->mingw); |
| 2123 | config->warnStdcallFixup = !args.hasArg(OPT_stdcall_fixup); |
Martin Storsjö | a67ae8c | 2023-10-20 20:44:44 | [diff] [blame] | 2124 | config->allowDuplicateWeak = |
| 2125 | args.hasFlag(OPT_lld_allow_duplicate_weak, |
| 2126 | OPT_lld_allow_duplicate_weak_no, config->mingw); |
Rui Ueyama | 6592ff8 | 2015-06-16 23:13:00 | [diff] [blame] | 2127 | |
Alvin Wong | 8fa0cfe | 2023-04-23 15:58:24 | [diff] [blame] | 2128 | if (args.hasFlag(OPT_inferasanlibs, OPT_inferasanlibs_no, false)) |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 2129 | Warn(ctx) << "ignoring '/inferasanlibs', this flag is not supported"; |
Alvin Wong | 8fa0cfe | 2023-04-23 15:58:24 | [diff] [blame] | 2130 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2131 | if (config->incremental && args.hasArg(OPT_profile)) { |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 2132 | Warn(ctx) << "ignoring '/incremental' due to '/profile' specification"; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2133 | config->incremental = false; |
Nico Weber | 0945ad6 | 2018-03-30 17:14:50 | [diff] [blame] | 2134 | } |
| 2135 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2136 | if (config->incremental && args.hasArg(OPT_order)) { |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 2137 | Warn(ctx) << "ignoring '/incremental' due to '/order' specification"; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2138 | config->incremental = false; |
Nico Weber | 0945ad6 | 2018-03-30 17:14:50 | [diff] [blame] | 2139 | } |
| 2140 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2141 | if (config->incremental && config->doGC) { |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 2142 | Warn(ctx) << "ignoring '/incremental' because REF is enabled; use " |
| 2143 | "'/opt:noref' to " |
| 2144 | "disable"; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2145 | config->incremental = false; |
Bob Haarman | 5ec4485 | 2018-01-31 23:44:00 | [diff] [blame] | 2146 | } |
| 2147 | |
Zequan Wu | 5bdc5e7 | 2021-02-27 00:38:24 | [diff] [blame] | 2148 | if (config->incremental && config->doICF != ICFLevel::None) { |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 2149 | Warn(ctx) << "ignoring '/incremental' because ICF is enabled; use " |
| 2150 | "'/opt:noicf' to " |
| 2151 | "disable"; |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2152 | config->incremental = false; |
Bob Haarman | 5ec4485 | 2018-01-31 23:44:00 | [diff] [blame] | 2153 | } |
| 2154 | |
Fangrui Song | 982575fd | 2024-12-04 04:51:50 | [diff] [blame] | 2155 | if (errCount(ctx)) |
Bob Haarman | ac8f7fc | 2017-04-05 00:43:54 | [diff] [blame] | 2156 | return; |
| 2157 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2158 | std::set<sys::fs::UniqueID> wholeArchives; |
| 2159 | for (auto *arg : args.filtered(OPT_wholearchive_file)) |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 2160 | if (std::optional<StringRef> path = findFile(arg->getValue())) |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 2161 | if (std::optional<sys::fs::UniqueID> id = getUniqueID(*path)) |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2162 | wholeArchives.insert(*id); |
Rui Ueyama | 4eed6cc | 2018-06-12 21:47:31 | [diff] [blame] | 2163 | |
| 2164 | // A predicate returning true if a given path is an argument for |
| 2165 | // /wholearchive:, or /wholearchive is enabled globally. |
| 2166 | // This function is a bit tricky because "foo.obj /wholearchive:././foo.obj" |
| 2167 | // needs to be handled as "/wholearchive:foo.obj foo.obj". |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2168 | auto isWholeArchive = [&](StringRef path) -> bool { |
| 2169 | if (args.hasArg(OPT_wholearchive_flag)) |
Rui Ueyama | 4eed6cc | 2018-06-12 21:47:31 | [diff] [blame] | 2170 | return true; |
Fangrui Song | 9da7aee | 2022-11-28 00:39:40 | [diff] [blame] | 2171 | if (std::optional<sys::fs::UniqueID> id = getUniqueID(path)) |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2172 | return wholeArchives.count(*id); |
Rui Ueyama | 4eed6cc | 2018-06-12 21:47:31 | [diff] [blame] | 2173 | return false; |
| 2174 | }; |
| 2175 | |
Bob Haarman | 7dc5e7a0 | 2019-09-03 20:32:16 | [diff] [blame] | 2176 | // Create a list of input files. These can be given as OPT_INPUT options |
| 2177 | // and OPT_wholearchive_file options, and we also need to track OPT_start_lib |
| 2178 | // and OPT_end_lib. |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2179 | { |
| 2180 | llvm::TimeTraceScope timeScope2("Parse & queue inputs"); |
| 2181 | bool inLib = false; |
| 2182 | for (auto *arg : args) { |
| 2183 | switch (arg->getOption().getID()) { |
| 2184 | case OPT_end_lib: |
| 2185 | if (!inLib) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 2186 | Err(ctx) << "stray " << arg->getSpelling(); |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2187 | inLib = false; |
| 2188 | break; |
| 2189 | case OPT_start_lib: |
| 2190 | if (inLib) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 2191 | Err(ctx) << "nested " << arg->getSpelling(); |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2192 | inLib = true; |
| 2193 | break; |
| 2194 | case OPT_wholearchive_file: |
| 2195 | if (std::optional<StringRef> path = findFileIfNew(arg->getValue())) |
| 2196 | enqueuePath(*path, true, inLib); |
| 2197 | break; |
| 2198 | case OPT_INPUT: |
| 2199 | if (std::optional<StringRef> path = findFileIfNew(arg->getValue())) |
| 2200 | enqueuePath(*path, isWholeArchive(*path), inLib); |
| 2201 | break; |
| 2202 | default: |
| 2203 | // Ignore other options. |
| 2204 | break; |
| 2205 | } |
Bob Haarman | 7dc5e7a0 | 2019-09-03 20:32:16 | [diff] [blame] | 2206 | } |
| 2207 | } |
Rui Ueyama | 4eed6cc | 2018-06-12 21:47:31 | [diff] [blame] | 2208 | |
Peter Collingbourne | 8b65e51 | 2016-12-11 22:15:25 | [diff] [blame] | 2209 | // Read all input files given via the command line. |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 2210 | run(); |
Nico Weber | f1828e3 | 2018-09-13 18:13:21 | [diff] [blame] | 2211 | if (errorCount()) |
| 2212 | return; |
| 2213 | |
Peter Collingbourne | 8b65e51 | 2016-12-11 22:15:25 | [diff] [blame] | 2214 | // We should have inferred a machine type by now from the input files, but if |
| 2215 | // not we assume x64. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2216 | if (config->machine == IMAGE_FILE_MACHINE_UNKNOWN) { |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 2217 | Warn(ctx) << "/machine is not specified. x64 is assumed"; |
Jacek Caban | 0a9810d | 2024-12-15 17:41:26 | [diff] [blame] | 2218 | setMachine(AMD64); |
Rui Ueyama | ea533cd | 2015-07-09 19:54:13 | [diff] [blame] | 2219 | } |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2220 | config->wordsize = config->is64() ? 8 : 4; |
Rui Ueyama | ea533cd | 2015-07-09 19:54:13 | [diff] [blame] | 2221 | |
Tobias Hieta | 33f9342 | 2023-07-12 07:22:06 | [diff] [blame] | 2222 | if (config->printSearchPaths) { |
| 2223 | SmallString<256> buffer; |
| 2224 | raw_svector_ostream stream(buffer); |
| 2225 | stream << "Library search paths:\n"; |
| 2226 | |
Martin Storsjö | 7d7d9e4 | 2023-10-02 10:43:56 | [diff] [blame] | 2227 | for (StringRef path : searchPaths) { |
| 2228 | if (path == "") |
| 2229 | path = "(cwd)"; |
Tobias Hieta | 33f9342 | 2023-07-12 07:22:06 | [diff] [blame] | 2230 | stream << " " << path << "\n"; |
Martin Storsjö | 7d7d9e4 | 2023-10-02 10:43:56 | [diff] [blame] | 2231 | } |
Tobias Hieta | 33f9342 | 2023-07-12 07:22:06 | [diff] [blame] | 2232 | |
Fangrui Song | 982575fd | 2024-12-04 04:51:50 | [diff] [blame] | 2233 | Msg(ctx) << buffer; |
Tobias Hieta | 33f9342 | 2023-07-12 07:22:06 | [diff] [blame] | 2234 | } |
| 2235 | |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 2236 | // Process files specified as /defaultlib. These must be processed after |
| 2237 | // addWinSysRootLibSearchPaths(), which is why they are in a separate loop. |
| 2238 | for (auto *arg : args.filtered(OPT_defaultlib)) |
Arthur Eubanks | 5f8f310 | 2023-06-06 18:11:52 | [diff] [blame] | 2239 | if (std::optional<StringRef> path = findLibIfNew(arg->getValue())) |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 2240 | enqueuePath(*path, false, false); |
| 2241 | run(); |
| 2242 | if (errorCount()) |
| 2243 | return; |
| 2244 | |
Qfrost | 3f55853 | 2023-01-02 09:20:15 | [diff] [blame] | 2245 | // Handle /RELEASE |
| 2246 | if (args.hasArg(OPT_release)) |
| 2247 | config->writeCheckSum = true; |
Matheus Izvekov | a5e280b | 2023-09-21 11:16:11 | [diff] [blame] | 2248 | |
Reid Kleckner | fe44a53 | 2019-07-16 18:17:33 | [diff] [blame] | 2249 | // Handle /safeseh, x86 only, on by default, except for mingw. |
Martin Storsjö | 745eb02 | 2020-07-27 20:44:41 | [diff] [blame] | 2250 | if (config->machine == I386) { |
| 2251 | config->safeSEH = args.hasFlag(OPT_safeseh, OPT_safeseh_no, !config->mingw); |
| 2252 | config->noSEH = args.hasArg(OPT_noseh); |
| 2253 | } |
Reid Kleckner | fe44a53 | 2019-07-16 18:17:33 | [diff] [blame] | 2254 | |
kkent030315 | fb974e8 | 2025-01-20 21:38:59 | [diff] [blame] | 2255 | // Handle /stub |
| 2256 | if (auto *arg = args.getLastArg(OPT_stub)) |
| 2257 | parseDosStub(arg->getValue()); |
| 2258 | |
Alexandre Ganea | d307c4c | 2019-02-23 01:46:18 | [diff] [blame] | 2259 | // Handle /functionpadmin |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2260 | for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt)) |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 2261 | parseFunctionPadMin(arg); |
Alexandre Ganea | d307c4c | 2019-02-23 01:46:18 | [diff] [blame] | 2262 | |
Aleksei Nurmukhametov | 76947e0 | 2023-11-08 20:21:05 | [diff] [blame] | 2263 | // Handle /dependentloadflag |
| 2264 | for (auto *arg : |
| 2265 | args.filtered(OPT_dependentloadflag, OPT_dependentloadflag_opt)) |
| 2266 | parseDependentLoadFlags(arg); |
| 2267 | |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 2268 | if (tar) { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2269 | llvm::TimeTraceScope timeScope("Reproducer: response file"); |
Nico Weber | 34a44b2 | 2024-12-17 16:30:13 | [diff] [blame] | 2270 | tar->append( |
| 2271 | "response.txt", |
| 2272 | createResponseFile(args, ArrayRef<StringRef>(searchPaths).slice(1))); |
Peter Kasting | c5fb05f | 2022-02-16 14:20:03 | [diff] [blame] | 2273 | } |
Peter Collingbourne | feee210 | 2016-07-26 02:00:42 | [diff] [blame] | 2274 | |
Rui Ueyama | 4d54534 | 2015-07-28 03:12:00 | [diff] [blame] | 2275 | // Handle /largeaddressaware |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2276 | config->largeAddressAware = args.hasFlag( |
| 2277 | OPT_largeaddressaware, OPT_largeaddressaware_no, config->is64()); |
Rui Ueyama | 4d54534 | 2015-07-28 03:12:00 | [diff] [blame] | 2278 | |
Rui Ueyama | d68e211 | 2015-07-28 03:15:57 | [diff] [blame] | 2279 | // Handle /highentropyva |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2280 | config->highEntropyVA = |
| 2281 | config->is64() && |
| 2282 | args.hasFlag(OPT_highentropyva, OPT_highentropyva_no, true); |
Rui Ueyama | d68e211 | 2015-07-28 03:15:57 | [diff] [blame] | 2283 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2284 | if (!config->dynamicBase && |
Jacek Caban | 85d0fbe | 2023-10-11 16:09:00 | [diff] [blame] | 2285 | (config->machine == ARMNT || isAnyArm64(config->machine))) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 2286 | Err(ctx) << "/dynamicbase:no is not compatible with " |
| 2287 | << machineToStr(config->machine); |
Martin Storsjo | 6ea167c | 2017-12-12 19:39:13 | [diff] [blame] | 2288 | |
Rui Ueyama | bbdec4f | 2015-07-09 22:51:41 | [diff] [blame] | 2289 | // Handle /export |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2290 | { |
| 2291 | llvm::TimeTraceScope timeScope("Parse /export"); |
| 2292 | for (auto *arg : args.filtered(OPT_export)) { |
| 2293 | Export e = parseExport(arg->getValue()); |
| 2294 | if (config->machine == I386) { |
| 2295 | if (!isDecorated(e.name)) |
| 2296 | e.name = saver().save("_" + e.name); |
| 2297 | if (!e.extName.empty() && !isDecorated(e.extName)) |
| 2298 | e.extName = saver().save("_" + e.extName); |
| 2299 | } |
Jacek Caban | 1c05c61 | 2025-04-11 13:53:25 | [diff] [blame] | 2300 | ctx.symtab.exports.push_back(e); |
Rui Ueyama | f10a320 | 2015-08-31 08:43:21 | [diff] [blame] | 2301 | } |
Rui Ueyama | bbdec4f | 2015-07-09 22:51:41 | [diff] [blame] | 2302 | } |
| 2303 | |
| 2304 | // Handle /def |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2305 | if (auto *arg = args.getLastArg(OPT_deffile)) { |
Rui Ueyama | bbdec4f | 2015-07-09 22:51:41 | [diff] [blame] | 2306 | // parseModuleDefs mutates Config object. |
Jacek Caban | 1c05c61 | 2025-04-11 13:53:25 | [diff] [blame] | 2307 | ctx.symtab.parseModuleDefs(arg->getValue()); |
Jacek Caban | 4e9d5a3 | 2025-01-22 22:32:18 | [diff] [blame] | 2308 | if (ctx.hybridSymtab) { |
| 2309 | // MSVC ignores the /defArm64Native argument on non-ARM64X targets. |
| 2310 | // It is also ignored if the /def option is not specified. |
| 2311 | if (auto *arg = args.getLastArg(OPT_defarm64native)) |
Jacek Caban | 1c05c61 | 2025-04-11 13:53:25 | [diff] [blame] | 2312 | ctx.hybridSymtab->parseModuleDefs(arg->getValue()); |
Jacek Caban | 4e9d5a3 | 2025-01-22 22:32:18 | [diff] [blame] | 2313 | } |
Rui Ueyama | bbdec4f | 2015-07-09 22:51:41 | [diff] [blame] | 2314 | } |
| 2315 | |
Saleem Abdulrasool | bc7ff70 | 2017-06-15 20:39:58 | [diff] [blame] | 2316 | // Handle generation of import library from a def file. |
Reid Kleckner | ce0f3ee | 2019-11-07 21:50:31 | [diff] [blame] | 2317 | if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) { |
Jacek Caban | 455b3d6 | 2025-01-21 09:41:15 | [diff] [blame] | 2318 | ctx.forEachSymtab([](SymbolTable &symtab) { symtab.fixupExports(); }); |
Tobias Hieta | eb4eef9 | 2022-04-12 14:06:46 | [diff] [blame] | 2319 | if (!config->noimplib) |
| 2320 | createImportLibrary(/*asLib=*/true); |
Rui Ueyama | 6f4e255 | 2017-10-23 20:03:32 | [diff] [blame] | 2321 | return; |
Saleem Abdulrasool | bc7ff70 | 2017-06-15 20:39:58 | [diff] [blame] | 2322 | } |
| 2323 | |
Nico Weber | f4f5b7e | 2018-08-07 19:10:28 | [diff] [blame] | 2324 | // Windows specific -- if no /subsystem is given, we need to infer |
| 2325 | // that from entry point name. Must happen before /entry handling, |
| 2326 | // and after the early return when just writing an import library. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2327 | if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2328 | llvm::TimeTraceScope timeScope("Infer subsystem"); |
Jacek Caban | 1c05c61 | 2025-04-11 13:53:25 | [diff] [blame] | 2329 | config->subsystem = ctx.symtab.inferSubsystem(); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2330 | if (config->subsystem == IMAGE_SUBSYSTEM_UNKNOWN) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 2331 | Fatal(ctx) << "subsystem must be defined"; |
Nico Weber | f4f5b7e | 2018-08-07 19:10:28 | [diff] [blame] | 2332 | } |
| 2333 | |
| 2334 | // Handle /entry and /dll |
Jacek Caban | d004947 | 2025-01-16 11:53:48 | [diff] [blame] | 2335 | ctx.forEachSymtab([&](SymbolTable &symtab) { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2336 | llvm::TimeTraceScope timeScope("Entry point"); |
| 2337 | if (auto *arg = args.getLastArg(OPT_entry)) { |
Martin Storsjö | cb248f8 | 2024-06-24 17:02:39 | [diff] [blame] | 2338 | if (!arg->getValue()[0]) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 2339 | Fatal(ctx) << "missing entry point symbol name"; |
Jacek Caban | d004947 | 2025-01-16 11:53:48 | [diff] [blame] | 2340 | symtab.entry = symtab.addGCRoot(symtab.mangle(arg->getValue()), true); |
| 2341 | } else if (!symtab.entry && !config->noEntry) { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2342 | if (args.hasArg(OPT_dll)) { |
| 2343 | StringRef s = (config->machine == I386) ? "__DllMainCRTStartup@12" |
| 2344 | : "_DllMainCRTStartup"; |
Jacek Caban | d004947 | 2025-01-16 11:53:48 | [diff] [blame] | 2345 | symtab.entry = symtab.addGCRoot(s, true); |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2346 | } else if (config->driverWdm) { |
| 2347 | // /driver:wdm implies /entry:_NtProcessStartup |
Jacek Caban | d004947 | 2025-01-16 11:53:48 | [diff] [blame] | 2348 | symtab.entry = |
| 2349 | symtab.addGCRoot(symtab.mangle("_NtProcessStartup"), true); |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2350 | } else { |
| 2351 | // Windows specific -- If entry point name is not given, we need to |
| 2352 | // infer that from user-defined entry name. |
Jacek Caban | d004947 | 2025-01-16 11:53:48 | [diff] [blame] | 2353 | StringRef s = symtab.findDefaultEntry(); |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2354 | if (s.empty()) |
Fangrui Song | 8b844de | 2024-12-06 04:18:01 | [diff] [blame] | 2355 | Fatal(ctx) << "entry point must be defined"; |
Jacek Caban | d004947 | 2025-01-16 11:53:48 | [diff] [blame] | 2356 | symtab.entry = symtab.addGCRoot(s, true); |
Fangrui Song | 4639a9a | 2024-12-04 17:04:40 | [diff] [blame] | 2357 | Log(ctx) << "Entry name inferred: " << s; |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2358 | } |
Nico Weber | f4f5b7e | 2018-08-07 19:10:28 | [diff] [blame] | 2359 | } |
Jacek Caban | d004947 | 2025-01-16 11:53:48 | [diff] [blame] | 2360 | }); |
Nico Weber | f4f5b7e | 2018-08-07 19:10:28 | [diff] [blame] | 2361 | |
Rui Ueyama | 6d24908 | 2015-07-13 22:31:45 | [diff] [blame] | 2362 | // Handle /delayload |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2363 | { |
| 2364 | llvm::TimeTraceScope timeScope("Delay load"); |
| 2365 | for (auto *arg : args.filtered(OPT_delayload)) { |
| 2366 | config->delayLoads.insert(StringRef(arg->getValue()).lower()); |
Jacek Caban | 97aa56a | 2025-01-28 11:07:35 | [diff] [blame] | 2367 | ctx.forEachSymtab([&](SymbolTable &symtab) { |
| 2368 | if (symtab.machine == I386) { |
| 2369 | symtab.delayLoadHelper = symtab.addGCRoot("___delayLoadHelper2@8"); |
| 2370 | } else { |
| 2371 | symtab.delayLoadHelper = symtab.addGCRoot("__delayLoadHelper2", true); |
| 2372 | } |
| 2373 | }); |
Rui Ueyama | 6d24908 | 2015-07-13 22:31:45 | [diff] [blame] | 2374 | } |
| 2375 | } |
| 2376 | |
Reid Kleckner | 7668182e | 2017-03-21 00:12:51 | [diff] [blame] | 2377 | // Set default image name if neither /out or /def set it. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2378 | if (config->outputFile.empty()) { |
Reid Kleckner | ce0f3ee | 2019-11-07 21:50:31 | [diff] [blame] | 2379 | config->outputFile = getOutputPath( |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 2380 | (*args.filtered(OPT_INPUT, OPT_wholearchive_file).begin())->getValue(), |
| 2381 | config->dll, config->driver); |
Reid Kleckner | 7668182e | 2017-03-21 00:12:51 | [diff] [blame] | 2382 | } |
| 2383 | |
Rui Ueyama | 7fd99fc | 2019-03-11 16:30:55 | [diff] [blame] | 2384 | // Fail early if an output file is not writable. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2385 | if (auto e = tryCreateFile(config->outputFile)) { |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 2386 | Err(ctx) << "cannot open output file " << config->outputFile << ": " |
| 2387 | << e.message(); |
Rui Ueyama | 7fd99fc | 2019-03-11 16:30:55 | [diff] [blame] | 2388 | return; |
| 2389 | } |
| 2390 | |
Pengxuan Zheng | 961c45f | 2022-09-23 19:39:34 | [diff] [blame] | 2391 | config->lldmapFile = getMapFile(args, OPT_lldmap, OPT_lldmap_file); |
| 2392 | config->mapFile = getMapFile(args, OPT_map, OPT_map_file); |
| 2393 | |
| 2394 | if (config->mapFile != "" && args.hasArg(OPT_map_info)) { |
| 2395 | for (auto *arg : args.filtered(OPT_map_info)) { |
| 2396 | std::string s = StringRef(arg->getValue()).lower(); |
| 2397 | if (s == "exports") |
| 2398 | config->mapInfo = true; |
| 2399 | else |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 2400 | Err(ctx) << "unknown option: /mapinfo:" << s; |
Pengxuan Zheng | 961c45f | 2022-09-23 19:39:34 | [diff] [blame] | 2401 | } |
| 2402 | } |
| 2403 | |
| 2404 | if (config->lldmapFile != "" && config->lldmapFile == config->mapFile) { |
Fangrui Song | 1534f45 | 2024-12-04 06:19:30 | [diff] [blame] | 2405 | Warn(ctx) << "/lldmap and /map have the same output file '" |
| 2406 | << config->mapFile << "'.\n>>> ignoring /lldmap"; |
Pengxuan Zheng | 961c45f | 2022-09-23 19:39:34 | [diff] [blame] | 2407 | config->lldmapFile.clear(); |
| 2408 | } |
| 2409 | |
Zequan Wu | aaf3a8d | 2023-12-05 19:57:45 | [diff] [blame] | 2410 | // If should create PDB, use the hash of PDB content for build id. Otherwise, |
| 2411 | // generate using the hash of executable content. |
| 2412 | if (args.hasFlag(OPT_build_id, OPT_build_id_no, false)) |
| 2413 | config->buildIDHash = BuildIDHash::Binary; |
| 2414 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2415 | if (shouldCreatePDB) { |
Peter Collingbourne | 94aa62e | 2018-04-17 23:28:38 | [diff] [blame] | 2416 | // Put the PDB next to the image if no /pdb flag was passed. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2417 | if (config->pdbPath.empty()) { |
| 2418 | config->pdbPath = config->outputFile; |
| 2419 | sys::path::replace_extension(config->pdbPath, ".pdb"); |
Peter Collingbourne | 94aa62e | 2018-04-17 23:28:38 | [diff] [blame] | 2420 | } |
| 2421 | |
| 2422 | // The embedded PDB path should be the absolute path to the PDB if no |
| 2423 | // /pdbaltpath flag was passed. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2424 | if (config->pdbAltPath.empty()) { |
| 2425 | config->pdbAltPath = config->pdbPath; |
Zachary Turner | e2ce2a5 | 2018-07-12 03:22:39 | [diff] [blame] | 2426 | |
| 2427 | // It's important to make the path absolute and remove dots. This path |
| 2428 | // will eventually be written into the PE header, and certain Microsoft |
| 2429 | // tools won't work correctly if these assumptions are not held. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2430 | sys::fs::make_absolute(config->pdbAltPath); |
| 2431 | sys::path::remove_dots(config->pdbAltPath); |
Nico Weber | 9d75241 | 2018-10-08 23:06:05 | [diff] [blame] | 2432 | } else { |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 2433 | // Don't do this earlier, so that ctx.OutputFile is ready. |
| 2434 | parsePDBAltPath(); |
Peter Collingbourne | 94aa62e | 2018-04-17 23:28:38 | [diff] [blame] | 2435 | } |
Zequan Wu | aaf3a8d | 2023-12-05 19:57:45 | [diff] [blame] | 2436 | config->buildIDHash = BuildIDHash::PDB; |
Reid Kleckner | 13bdbfb | 2017-03-22 00:57:14 | [diff] [blame] | 2437 | } |
| 2438 | |
Rui Ueyama | 5c437cd | 2015-07-25 21:42:33 | [diff] [blame] | 2439 | // Set default image base if /base is not given. |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2440 | if (config->imageBase == uint64_t(-1)) |
| 2441 | config->imageBase = getDefaultImageBase(); |
Rui Ueyama | 5c437cd | 2015-07-25 21:42:33 | [diff] [blame] | 2442 | |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 2443 | ctx.forEachSymtab([&](SymbolTable &symtab) { |
Jacek Caban | f22af59 | 2025-01-15 14:21:06 | [diff] [blame] | 2444 | symtab.addSynthetic(symtab.mangle("__ImageBase"), nullptr); |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 2445 | if (symtab.machine == I386) { |
| 2446 | symtab.addAbsolute("___safe_se_handler_table", 0); |
| 2447 | symtab.addAbsolute("___safe_se_handler_count", 0); |
| 2448 | } |
Rui Ueyama | bbdec4f | 2015-07-09 22:51:41 | [diff] [blame] | 2449 | |
Jacek Caban | f22af59 | 2025-01-15 14:21:06 | [diff] [blame] | 2450 | symtab.addAbsolute(symtab.mangle("__guard_fids_count"), 0); |
| 2451 | symtab.addAbsolute(symtab.mangle("__guard_fids_table"), 0); |
| 2452 | symtab.addAbsolute(symtab.mangle("__guard_flags"), 0); |
| 2453 | symtab.addAbsolute(symtab.mangle("__guard_iat_count"), 0); |
| 2454 | symtab.addAbsolute(symtab.mangle("__guard_iat_table"), 0); |
| 2455 | symtab.addAbsolute(symtab.mangle("__guard_longjmp_count"), 0); |
| 2456 | symtab.addAbsolute(symtab.mangle("__guard_longjmp_table"), 0); |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 2457 | // Needed for MSVC 2017 15.5 CRT. |
Jacek Caban | f22af59 | 2025-01-15 14:21:06 | [diff] [blame] | 2458 | symtab.addAbsolute(symtab.mangle("__enclave_config"), 0); |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 2459 | // Needed for MSVC 2019 16.8 CRT. |
Jacek Caban | f22af59 | 2025-01-15 14:21:06 | [diff] [blame] | 2460 | symtab.addAbsolute(symtab.mangle("__guard_eh_cont_count"), 0); |
| 2461 | symtab.addAbsolute(symtab.mangle("__guard_eh_cont_table"), 0); |
Rui Ueyama | 107db55 | 2015-08-09 21:01:06 | [diff] [blame] | 2462 | |
Jacek Caban | db7123f | 2024-12-29 13:04:00 | [diff] [blame] | 2463 | if (symtab.isEC()) { |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 2464 | symtab.addAbsolute("__arm64x_extra_rfe_table", 0); |
| 2465 | symtab.addAbsolute("__arm64x_extra_rfe_table_size", 0); |
| 2466 | symtab.addAbsolute("__arm64x_redirection_metadata", 0); |
| 2467 | symtab.addAbsolute("__arm64x_redirection_metadata_count", 0); |
| 2468 | symtab.addAbsolute("__hybrid_auxiliary_delayload_iat_copy", 0); |
| 2469 | symtab.addAbsolute("__hybrid_auxiliary_delayload_iat", 0); |
| 2470 | symtab.addAbsolute("__hybrid_auxiliary_iat", 0); |
| 2471 | symtab.addAbsolute("__hybrid_auxiliary_iat_copy", 0); |
| 2472 | symtab.addAbsolute("__hybrid_code_map", 0); |
| 2473 | symtab.addAbsolute("__hybrid_code_map_count", 0); |
| 2474 | symtab.addAbsolute("__hybrid_image_info_bitfield", 0); |
| 2475 | symtab.addAbsolute("__x64_code_ranges_to_entry_points", 0); |
| 2476 | symtab.addAbsolute("__x64_code_ranges_to_entry_points_count", 0); |
| 2477 | symtab.addSynthetic("__guard_check_icall_a64n_fptr", nullptr); |
| 2478 | symtab.addSynthetic("__arm64x_native_entrypoint", nullptr); |
| 2479 | } |
Jacek Caban | fe2bd12 | 2023-11-15 11:35:45 | [diff] [blame] | 2480 | |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 2481 | if (config->pseudoRelocs) { |
Jacek Caban | f22af59 | 2025-01-15 14:21:06 | [diff] [blame] | 2482 | symtab.addAbsolute(symtab.mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0); |
| 2483 | symtab.addAbsolute(symtab.mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0); |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 2484 | } |
| 2485 | if (config->mingw) { |
Jacek Caban | f22af59 | 2025-01-15 14:21:06 | [diff] [blame] | 2486 | symtab.addAbsolute(symtab.mangle("__CTOR_LIST__"), 0); |
| 2487 | symtab.addAbsolute(symtab.mangle("__DTOR_LIST__"), 0); |
jeremyd2019 | f66f2fe | 2025-05-02 07:58:14 | [diff] [blame] | 2488 | symtab.addAbsolute("__data_start__", 0); |
| 2489 | symtab.addAbsolute("__data_end__", 0); |
| 2490 | symtab.addAbsolute("__bss_start__", 0); |
| 2491 | symtab.addAbsolute("__bss_end__", 0); |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 2492 | } |
| 2493 | if (config->debug || config->buildIDHash != BuildIDHash::None) |
| 2494 | if (symtab.findUnderscore("__buildid")) |
Jacek Caban | f22af59 | 2025-01-15 14:21:06 | [diff] [blame] | 2495 | symtab.addUndefined(symtab.mangle("__buildid")); |
Jacek Caban | 16ef239 | 2024-12-16 10:31:05 | [diff] [blame] | 2496 | }); |
Martin Storsjo | eac1b05 | 2018-08-27 08:43:31 | [diff] [blame] | 2497 | |
Peter Collingbourne | 6ee0b4e | 2016-12-15 04:02:23 | [diff] [blame] | 2498 | // This code may add new undefined symbols to the link, which may enqueue more |
| 2499 | // symbol resolution tasks, so we need to continue executing tasks until we |
| 2500 | // converge. |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2501 | { |
| 2502 | llvm::TimeTraceScope timeScope("Add unresolved symbols"); |
| 2503 | do { |
Jacek Caban | d004947 | 2025-01-16 11:53:48 | [diff] [blame] | 2504 | ctx.forEachSymtab([&](SymbolTable &symtab) { |
| 2505 | // Windows specific -- if entry point is not found, |
| 2506 | // search for its mangled names. |
| 2507 | if (symtab.entry) |
| 2508 | symtab.mangleMaybe(symtab.entry); |
Rui Ueyama | 85225b0 | 2015-07-02 03:15:15 | [diff] [blame] | 2509 | |
Jacek Caban | 455b3d6 | 2025-01-21 09:41:15 | [diff] [blame] | 2510 | // Windows specific -- Make sure we resolve all dllexported symbols. |
| 2511 | for (Export &e : symtab.exports) { |
| 2512 | if (!e.forwardTo.empty()) |
| 2513 | continue; |
| 2514 | e.sym = symtab.addGCRoot(e.name, !e.data); |
| 2515 | if (e.source != ExportSource::Directives) |
| 2516 | e.symbolName = symtab.mangleMaybe(e.sym); |
| 2517 | } |
Rui Ueyama | 2edb35a | 2015-06-18 19:09:30 | [diff] [blame] | 2518 | |
Jacek Caban | 8616c87 | 2025-02-21 11:52:28 | [diff] [blame] | 2519 | // Add weak aliases. Weak aliases is a mechanism to give remaining |
| 2520 | // undefined symbols final chance to be resolved successfully. |
| 2521 | for (auto pair : symtab.alternateNames) { |
| 2522 | StringRef from = pair.first; |
| 2523 | StringRef to = pair.second; |
| 2524 | Symbol *sym = symtab.find(from); |
| 2525 | if (!sym) |
| 2526 | continue; |
| 2527 | if (auto *u = dyn_cast<Undefined>(sym)) { |
| 2528 | if (u->weakAlias) { |
| 2529 | // On ARM64EC, anti-dependency aliases are treated as undefined |
| 2530 | // symbols unless a demangled symbol aliases a defined one, which |
| 2531 | // is part of the implementation. |
| 2532 | if (!symtab.isEC() || !u->isAntiDep) |
| 2533 | continue; |
| 2534 | if (!isa<Undefined>(u->weakAlias) && |
| 2535 | !isArm64ECMangledFunctionName(u->getName())) |
| 2536 | continue; |
| 2537 | } |
| 2538 | u->setWeakAlias(symtab.addUndefined(to)); |
Jacek Caban | 6bb6922 | 2024-10-25 09:53:47 | [diff] [blame] | 2539 | } |
Jacek Caban | 6bb6922 | 2024-10-25 09:53:47 | [diff] [blame] | 2540 | } |
Peter Collingbourne | 8b65e51 | 2016-12-11 22:15:25 | [diff] [blame] | 2541 | |
Jacek Caban | b068f2f | 2025-01-17 10:36:12 | [diff] [blame] | 2542 | // If any inputs are bitcode files, the LTO code generator may create |
| 2543 | // references to library functions that are not explicit in the bitcode |
| 2544 | // file's symbol table. If any of those library functions are defined in |
| 2545 | // a bitcode file in an archive member, we need to arrange to use LTO to |
| 2546 | // compile those archive members by adding them to the link beforehand. |
| 2547 | if (!symtab.bitcodeFileInstances.empty()) { |
| 2548 | llvm::Triple TT( |
| 2549 | symtab.bitcodeFileInstances.front()->obj->getTargetTriple()); |
| 2550 | for (auto *s : lto::LTO::getRuntimeLibcallSymbols(TT)) |
| 2551 | symtab.addLibcall(s); |
| 2552 | } |
| 2553 | |
Jacek Caban | 80084e9 | 2025-01-15 16:43:33 | [diff] [blame] | 2554 | // Windows specific -- if __load_config_used can be resolved, resolve |
| 2555 | // it. |
| 2556 | if (symtab.findUnderscore("_load_config_used")) |
| 2557 | symtab.addGCRoot(symtab.mangle("_load_config_used")); |
Peter Collingbourne | 8b65e51 | 2016-12-11 22:15:25 | [diff] [blame] | 2558 | |
Jacek Caban | 6536579 | 2025-02-10 21:01:53 | [diff] [blame] | 2559 | if (args.hasArg(OPT_include_optional)) { |
| 2560 | // Handle /includeoptional |
| 2561 | for (auto *arg : args.filtered(OPT_include_optional)) |
| 2562 | if (isa_and_nonnull<LazyArchive>(symtab.find(arg->getValue()))) |
| 2563 | symtab.addGCRoot(arg->getValue()); |
| 2564 | } |
| 2565 | }); |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2566 | } while (run()); |
| 2567 | } |
Martin Storsjo | c02f6bf | 2019-06-08 18:26:18 | [diff] [blame] | 2568 | |
Miguel A. Arroyo | b9bd8ca | 2024-09-24 20:57:01 | [diff] [blame] | 2569 | // Handle /includeglob |
| 2570 | for (StringRef pat : args::getStrings(args, OPT_incl_glob)) |
Jacek Caban | 2d0eb5df | 2025-03-03 21:39:42 | [diff] [blame] | 2571 | ctx.forEachSymtab( |
| 2572 | [&](SymbolTable &symtab) { symtab.addUndefinedGlob(pat); }); |
Miguel A. Arroyo | b9bd8ca | 2024-09-24 20:57:01 | [diff] [blame] | 2573 | |
Martin Storsjö | 3785a41 | 2020-10-06 10:54:49 | [diff] [blame] | 2574 | // Create wrapped symbols for -wrap option. |
Jacek Caban | 94d9563 | 2025-02-10 21:52:11 | [diff] [blame] | 2575 | ctx.forEachSymtab([&](SymbolTable &symtab) { |
| 2576 | addWrappedSymbols(symtab, args); |
| 2577 | // Load more object files that might be needed for wrapped symbols. |
| 2578 | if (!symtab.wrapped.empty()) |
| 2579 | while (run()) |
| 2580 | ; |
| 2581 | }); |
Martin Storsjö | 3785a41 | 2020-10-06 10:54:49 | [diff] [blame] | 2582 | |
Martin Storsjö | ce211c5 | 2021-06-17 18:51:37 | [diff] [blame] | 2583 | if (config->autoImport || config->stdcallFixup) { |
Martin Storsjö | 7f0e6c3 | 2020-04-25 21:49:44 | [diff] [blame] | 2584 | // MinGW specific. |
Martin Storsjo | eac1b05 | 2018-08-27 08:43:31 | [diff] [blame] | 2585 | // Load any further object files that might be needed for doing automatic |
Martin Storsjö | ce211c5 | 2021-06-17 18:51:37 | [diff] [blame] | 2586 | // imports, and do stdcall fixups. |
Martin Storsjo | eac1b05 | 2018-08-27 08:43:31 | [diff] [blame] | 2587 | // |
| 2588 | // For cases with no automatically imported symbols, this iterates once |
| 2589 | // over the symbol table and doesn't do anything. |
| 2590 | // |
| 2591 | // For the normal case with a few automatically imported symbols, this |
| 2592 | // should only need to be run once, since each new object file imported |
| 2593 | // is an import library and wouldn't add any new undefined references, |
| 2594 | // but there's nothing stopping the __imp_ symbols from coming from a |
| 2595 | // normal object file as well (although that won't be used for the |
| 2596 | // actual autoimport later on). If this pass adds new undefined references, |
| 2597 | // we won't iterate further to resolve them. |
Martin Storsjö | ce211c5 | 2021-06-17 18:51:37 | [diff] [blame] | 2598 | // |
| 2599 | // If stdcall fixups only are needed for loading import entries from |
| 2600 | // a DLL without import library, this also just needs running once. |
| 2601 | // If it ends up pulling in more object files from static libraries, |
| 2602 | // (and maybe doing more stdcall fixups along the way), this would need |
| 2603 | // to loop these two calls. |
Jacek Caban | c6598f6 | 2025-03-02 12:10:50 | [diff] [blame] | 2604 | ctx.forEachSymtab([](SymbolTable &symtab) { symtab.loadMinGWSymbols(); }); |
Martin Storsjo | eac1b05 | 2018-08-27 08:43:31 | [diff] [blame] | 2605 | run(); |
| 2606 | } |
| 2607 | |
Bob Haarman | 51dcb29 | 2019-07-26 17:56:45 | [diff] [blame] | 2608 | // At this point, we should not have any symbols that cannot be resolved. |
| 2609 | // If we are going to do codegen for link-time optimization, check for |
| 2610 | // unresolvable symbols first, so we don't spend time generating code that |
| 2611 | // will fail to link anyway. |
Jacek Caban | b068f2f | 2025-01-17 10:36:12 | [diff] [blame] | 2612 | if (!config->forceUnresolved) |
| 2613 | ctx.forEachSymtab([](SymbolTable &symtab) { |
| 2614 | if (!symtab.bitcodeFileInstances.empty()) |
| 2615 | symtab.reportUnresolvable(); |
| 2616 | }); |
Bob Haarman | 51dcb29 | 2019-07-26 17:56:45 | [diff] [blame] | 2617 | if (errorCount()) |
| 2618 | return; |
| 2619 | |
Jacek Caban | 455b3d6 | 2025-01-21 09:41:15 | [diff] [blame] | 2620 | ctx.forEachSymtab([](SymbolTable &symtab) { |
| 2621 | symtab.hadExplicitExports = !symtab.exports.empty(); |
| 2622 | }); |
Martin Storsjö | 33b71ec | 2021-04-29 11:06:24 | [diff] [blame] | 2623 | if (config->mingw) { |
| 2624 | // In MinGW, all symbols are automatically exported if no symbols |
| 2625 | // are chosen to be exported. |
| 2626 | maybeExportMinGWSymbols(args); |
| 2627 | } |
| 2628 | |
Bob Haarman | 51dcb29 | 2019-07-26 17:56:45 | [diff] [blame] | 2629 | // Do LTO by compiling bitcode input files to a set of native COFF files then |
| 2630 | // link those files (unless -thinlto-index-only was given, in which case we |
| 2631 | // resolve symbols and write indices, but don't generate native code or link). |
Jacek Caban | 8435225 | 2025-01-01 18:42:49 | [diff] [blame] | 2632 | ltoCompilationDone = true; |
Jacek Caban | b068f2f | 2025-01-17 10:36:12 | [diff] [blame] | 2633 | ctx.forEachSymtab([](SymbolTable &symtab) { symtab.compileBitcodeFiles(); }); |
Bob Haarman | 51dcb29 | 2019-07-26 17:56:45 | [diff] [blame] | 2634 | |
Martin Storsjö | 303370e8 | 2023-11-07 09:49:05 | [diff] [blame] | 2635 | if (Defined *d = |
| 2636 | dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore("_tls_used"))) |
| 2637 | config->gcroot.push_back(d); |
| 2638 | |
Bob Haarman | 51dcb29 | 2019-07-26 17:56:45 | [diff] [blame] | 2639 | // If -thinlto-index-only is given, we should create only "index |
| 2640 | // files" and not object files. Index file creation is already done |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 2641 | // in addCombinedLTOObject, so we are done if that's the case. |
Matheus Izvekov | 3923e61 | 2023-10-02 20:54:43 | [diff] [blame] | 2642 | // Likewise, don't emit object files for other /lldemit options. |
| 2643 | if (config->emit != EmitKind::Obj || config->thinLTOIndexOnly) |
Bob Haarman | 51dcb29 | 2019-07-26 17:56:45 | [diff] [blame] | 2644 | return; |
| 2645 | |
| 2646 | // If we generated native object files from bitcode files, this resolves |
| 2647 | // references to the symbols we use from them. |
| 2648 | run(); |
| 2649 | |
Martin Storsjö | 3785a41 | 2020-10-06 10:54:49 | [diff] [blame] | 2650 | // Apply symbol renames for -wrap. |
Jacek Caban | 94d9563 | 2025-02-10 21:52:11 | [diff] [blame] | 2651 | ctx.forEachSymtab([](SymbolTable &symtab) { |
| 2652 | if (!symtab.wrapped.empty()) |
| 2653 | wrapSymbols(symtab); |
| 2654 | }); |
Martin Storsjö | 3785a41 | 2020-10-06 10:54:49 | [diff] [blame] | 2655 | |
Jacek Caban | a2d8743 | 2024-08-22 20:03:05 | [diff] [blame] | 2656 | if (isArm64EC(config->machine)) |
| 2657 | createECExportThunks(); |
| 2658 | |
Bob Haarman | 51dcb29 | 2019-07-26 17:56:45 | [diff] [blame] | 2659 | // Resolve remaining undefined symbols and warn about imported locals. |
Alexandre Ganea | c75eac7c | 2025-04-07 15:34:24 | [diff] [blame] | 2660 | ctx.forEachSymtab( |
| 2661 | [&](SymbolTable &symtab) { symtab.resolveRemainingUndefines(); }); |
Mike Hommey | 6a1bdd9 | 2024-10-03 19:53:26 | [diff] [blame] | 2662 | |
Bob Haarman | b8a59c8 | 2017-10-25 22:28:38 | [diff] [blame] | 2663 | if (errorCount()) |
Rui Ueyama | cc6738a | 2017-10-06 23:43:54 | [diff] [blame] | 2664 | return; |
Peter Collingbourne | 2612a32 | 2015-07-04 05:28:41 | [diff] [blame] | 2665 | |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2666 | if (config->mingw) { |
Martin Storsjo | cdf126e | 2019-04-15 10:57:44 | [diff] [blame] | 2667 | // Make sure the crtend.o object is the last object file. This object |
| 2668 | // file can contain terminating section chunks that need to be placed |
| 2669 | // last. GNU ld processes files and static libraries explicitly in the |
| 2670 | // order provided on the command line, while lld will pull in needed |
| 2671 | // files from static libraries only after the last object file on the |
| 2672 | // command line. |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 2673 | for (auto i = ctx.objFileInstances.begin(), e = ctx.objFileInstances.end(); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2674 | i != e; i++) { |
| 2675 | ObjFile *file = *i; |
| 2676 | if (isCrtend(file->getName())) { |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 2677 | ctx.objFileInstances.erase(i); |
| 2678 | ctx.objFileInstances.push_back(file); |
Martin Storsjo | cdf126e | 2019-04-15 10:57:44 | [diff] [blame] | 2679 | break; |
| 2680 | } |
| 2681 | } |
| 2682 | } |
| 2683 | |
Rui Ueyama | 151d862 | 2015-06-17 20:40:43 | [diff] [blame] | 2684 | // Windows specific -- when we are creating a .dll file, we also |
Martin Storsjo | 6540e55 | 2019-08-20 10:14:54 | [diff] [blame] | 2685 | // need to create a .lib file. In MinGW mode, we only do that when the |
| 2686 | // -implib option is given explicitly, for compatibility with GNU ld. |
Jacek Caban | e902cf2 | 2025-01-29 08:57:11 | [diff] [blame] | 2687 | if (config->dll || !ctx.symtab.exports.empty() || |
| 2688 | (ctx.hybridSymtab && !ctx.hybridSymtab->exports.empty())) { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2689 | llvm::TimeTraceScope timeScope("Create .lib exports"); |
Jacek Caban | 455b3d6 | 2025-01-21 09:41:15 | [diff] [blame] | 2690 | ctx.forEachSymtab([](SymbolTable &symtab) { symtab.fixupExports(); }); |
Tobias Hieta | eb4eef9 | 2022-04-12 14:06:46 | [diff] [blame] | 2691 | if (!config->noimplib && (!config->mingw || !config->implib.empty())) |
Martin Storsjo | 6540e55 | 2019-08-20 10:14:54 | [diff] [blame] | 2692 | createImportLibrary(/*asLib=*/false); |
Jacek Caban | 455b3d6 | 2025-01-21 09:41:15 | [diff] [blame] | 2693 | ctx.forEachSymtab( |
| 2694 | [](SymbolTable &symtab) { symtab.assignExportOrdinals(); }); |
Rui Ueyama | 8765fba | 2015-07-15 22:21:08 | [diff] [blame] | 2695 | } |
Rui Ueyama | 97dff9e | 2015-06-17 00:16:33 | [diff] [blame] | 2696 | |
Martin Storsjo | 7f71acd | 2017-10-12 05:37:13 | [diff] [blame] | 2697 | // Handle /output-def (MinGW specific). |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2698 | if (auto *arg = args.getLastArg(OPT_output_def)) |
Jacek Caban | 1c05c61 | 2025-04-11 13:53:25 | [diff] [blame] | 2699 | writeDefFile(ctx, arg->getValue(), ctx.symtab.exports); |
Rui Ueyama | d73479b | 2018-01-29 19:55:55 | [diff] [blame] | 2700 | |
Martin Storsjo | d2752aa | 2017-08-14 19:07:27 | [diff] [blame] | 2701 | // Set extra alignment for .comm symbols |
Jacek Caban | f2473bc | 2025-03-03 21:48:20 | [diff] [blame] | 2702 | ctx.forEachSymtab([&](SymbolTable &symtab) { |
| 2703 | for (auto pair : symtab.alignComm) { |
| 2704 | StringRef name = pair.first; |
| 2705 | uint32_t alignment = pair.second; |
Rui Ueyama | cfc2f80 | 2017-09-13 21:54:55 | [diff] [blame] | 2706 | |
Jacek Caban | f2473bc | 2025-03-03 21:48:20 | [diff] [blame] | 2707 | Symbol *sym = symtab.find(name); |
| 2708 | if (!sym) { |
| 2709 | Warn(ctx) << "/aligncomm symbol " << name << " not found"; |
| 2710 | continue; |
| 2711 | } |
| 2712 | |
| 2713 | // If the symbol isn't common, it must have been replaced with a regular |
| 2714 | // symbol, which will carry its own alignment. |
| 2715 | auto *dc = dyn_cast<DefinedCommon>(sym); |
| 2716 | if (!dc) |
| 2717 | continue; |
| 2718 | |
| 2719 | CommonChunk *c = dc->getChunk(); |
| 2720 | c->setAlignment(std::max(c->getAlignment(), alignment)); |
Martin Storsjo | d2752aa | 2017-08-14 19:07:27 | [diff] [blame] | 2721 | } |
Jacek Caban | f2473bc | 2025-03-03 21:48:20 | [diff] [blame] | 2722 | }); |
Martin Storsjo | d2752aa | 2017-08-14 19:07:27 | [diff] [blame] | 2723 | |
Nico Weber | 400a1de | 2021-08-24 14:19:21 | [diff] [blame] | 2724 | // Windows specific -- Create an embedded or side-by-side manifest. |
| 2725 | // /manifestdependency: enables /manifest unless an explicit /manifest:no is |
| 2726 | // also passed. |
| 2727 | if (config->manifest == Configuration::Embed) |
| 2728 | addBuffer(createManifestRes(), false, false); |
| 2729 | else if (config->manifest == Configuration::SideBySide || |
| 2730 | (config->manifest == Configuration::Default && |
| 2731 | !config->manifestDependencies.empty())) |
Rafael Espindola | b835ae8 | 2015-08-06 14:58:50 | [diff] [blame] | 2732 | createSideBySideManifest(); |
Rui Ueyama | 24c5fd0 | 2015-06-18 00:12:42 | [diff] [blame] | 2733 | |
Rui Ueyama | b6d3a93 | 2018-01-29 21:50:53 | [diff] [blame] | 2734 | // Handle /order. We want to do this at this moment because we |
| 2735 | // need a complete list of comdat sections to warn on nonexistent |
| 2736 | // functions. |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 2737 | if (auto *arg = args.getLastArg(OPT_order)) { |
| 2738 | if (args.hasArg(OPT_call_graph_ordering_file)) |
Fangrui Song | 8d225f1 | 2024-12-06 03:44:26 | [diff] [blame] | 2739 | Err(ctx) << "/order and /call-graph-order-file may not be used together"; |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 2740 | parseOrderFile(arg->getValue()); |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 2741 | config->callGraphProfileSort = false; |
| 2742 | } |
| 2743 | |
| 2744 | // Handle /call-graph-ordering-file and /call-graph-profile-sort (default on). |
| 2745 | if (config->callGraphProfileSort) { |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2746 | llvm::TimeTraceScope timeScope("Call graph"); |
Haohai Wen | 2d9d291 | 2025-01-05 02:38:14 | [diff] [blame] | 2747 | if (auto *arg = args.getLastArg(OPT_call_graph_ordering_file)) |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 2748 | parseCallGraphFile(arg->getValue()); |
Haohai Wen | 2d9d291 | 2025-01-05 02:38:14 | [diff] [blame] | 2749 | else |
| 2750 | readCallGraphsFromObjectFiles(ctx); |
Zequan Wu | 763671f | 2020-07-21 20:46:11 | [diff] [blame] | 2751 | } |
| 2752 | |
| 2753 | // Handle /print-symbol-order. |
| 2754 | if (auto *arg = args.getLastArg(OPT_print_symbol_order)) |
| 2755 | config->printSymbolOrder = arg->getValue(); |
Rui Ueyama | b6d3a93 | 2018-01-29 21:50:53 | [diff] [blame] | 2756 | |
Jacek Caban | 61f80db | 2025-04-11 16:50:16 | [diff] [blame] | 2757 | if (ctx.symtab.isEC()) |
| 2758 | ctx.symtab.initializeECThunks(); |
Jacek Caban | ff29f38 | 2024-12-29 10:43:45 | [diff] [blame] | 2759 | ctx.forEachSymtab([](SymbolTable &symtab) { symtab.initializeLoadConfig(); }); |
Jacek Caban | fed8e38 | 2024-06-18 09:14:01 | [diff] [blame] | 2760 | |
Rui Ueyama | a5f0f75 | 2015-09-19 21:36:28 | [diff] [blame] | 2761 | // Identify unreferenced COMDAT sections. |
Martin Storsjö | 7e07683 | 2021-05-09 20:27:35 | [diff] [blame] | 2762 | if (config->doGC) { |
| 2763 | if (config->mingw) { |
| 2764 | // markLive doesn't traverse .eh_frame, but the personality function is |
| 2765 | // only reached that way. The proper solution would be to parse and |
| 2766 | // traverse the .eh_frame section, like the ELF linker does. |
| 2767 | // For now, just manually try to retain the known possible personality |
| 2768 | // functions. This doesn't bring in more object files, but only marks |
| 2769 | // functions that already have been included to be retained. |
Jacek Caban | d403f33 | 2025-03-02 12:37:51 | [diff] [blame] | 2770 | ctx.forEachSymtab([&](SymbolTable &symtab) { |
| 2771 | for (const char *n : {"__gxx_personality_v0", "__gcc_personality_v0", |
| 2772 | "rust_eh_personality"}) { |
| 2773 | Defined *d = dyn_cast_or_null<Defined>(symtab.findUnderscore(n)); |
| 2774 | if (d && !d->isGCRoot) { |
| 2775 | d->isGCRoot = true; |
| 2776 | config->gcroot.push_back(d); |
| 2777 | } |
Martin Storsjö | 7e07683 | 2021-05-09 20:27:35 | [diff] [blame] | 2778 | } |
Jacek Caban | d403f33 | 2025-03-02 12:37:51 | [diff] [blame] | 2779 | }); |
Martin Storsjö | 7e07683 | 2021-05-09 20:27:35 | [diff] [blame] | 2780 | } |
| 2781 | |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 2782 | markLive(ctx); |
Martin Storsjö | 7e07683 | 2021-05-09 20:27:35 | [diff] [blame] | 2783 | } |
Rui Ueyama | a5f0f75 | 2015-09-19 21:36:28 | [diff] [blame] | 2784 | |
Nico Weber | af6bc65 | 2019-06-11 15:22:28 | [diff] [blame] | 2785 | // Needs to happen after the last call to addFile(). |
Martin Storsjo | 3d3a9b3 | 2019-08-30 06:56:33 | [diff] [blame] | 2786 | convertResources(); |
Nico Weber | af6bc65 | 2019-06-11 15:22:28 | [diff] [blame] | 2787 | |
Rui Ueyama | a5f0f75 | 2015-09-19 21:36:28 | [diff] [blame] | 2788 | // Identify identical COMDAT sections to merge them. |
Zequan Wu | 5bdc5e7 | 2021-02-27 00:38:24 | [diff] [blame] | 2789 | if (config->doICF != ICFLevel::None) { |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 2790 | findKeepUniqueSections(ctx); |
Amy Huang | 5a58b19 | 2023-01-10 04:37:28 | [diff] [blame] | 2791 | doICF(ctx); |
Peter Collingbourne | ab03802 | 2018-08-23 17:44:42 | [diff] [blame] | 2792 | } |
Rui Ueyama | a5f0f75 | 2015-09-19 21:36:28 | [diff] [blame] | 2793 | |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 2794 | // Write the result. |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 2795 | writeResult(ctx); |
Zachary Turner | 727f153 | 2018-01-17 19:16:26 | [diff] [blame] | 2796 | |
| 2797 | // Stop early so we can print the results. |
Reid Kleckner | 3508c1d | 2020-05-20 14:50:19 | [diff] [blame] | 2798 | rootTimer.stop(); |
Rui Ueyama | 136d27a | 2019-07-11 05:40:30 | [diff] [blame] | 2799 | if (config->showTiming) |
Amy Huang | 6f7483b | 2021-09-16 23:48:26 | [diff] [blame] | 2800 | ctx.rootTimer.print(); |
Alexandre Ganea | 356139b | 2023-10-06 02:33:58 | [diff] [blame] | 2801 | |
| 2802 | if (config->timeTraceEnabled) { |
| 2803 | // Manually stop the topmost "COFF link" scope, since we're shutting down. |
| 2804 | timeTraceProfilerEnd(); |
| 2805 | |
| 2806 | checkError(timeTraceProfilerWrite( |
| 2807 | args.getLastArgValue(OPT_time_trace_eq).str(), config->outputFile)); |
| 2808 | timeTraceProfilerCleanup(); |
| 2809 | } |
Rui Ueyama | 411c6360 | 2015-05-28 19:09:30 | [diff] [blame] | 2810 | } |
| 2811 | |
Nico Weber | 7c26641 | 2022-08-08 15:32:26 | [diff] [blame] | 2812 | } // namespace lld::coff |