1//===- MinGW.cpp ----------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "MinGW.h"
10#include "COFFLinkerContext.h"
11#include "Driver.h"
12#include "InputFiles.h"
13#include "SymbolTable.h"
14#include "llvm/ADT/DenseMap.h"
15#include "llvm/ADT/DenseSet.h"
16#include "llvm/Support/Parallel.h"
17#include "llvm/Support/Path.h"
18#include "llvm/Support/TimeProfiler.h"
19#include "llvm/Support/raw_ostream.h"
20
21using namespace llvm;
22using namespace llvm::COFF;
23using namespace lld;
24using namespace lld::coff;
25
26AutoExporter::AutoExporter(
27 SymbolTable &symtab, const llvm::DenseSet<StringRef> &manualExcludeSymbols)
28 : manualExcludeSymbols(manualExcludeSymbols), symtab(symtab) {
29 excludeLibs = {
30 "libgcc",
31 "libgcc_s",
32 "libstdc++",
33 "libmingw32",
34 "libmingwex",
35 "libg2c",
36 "libsupc++",
37 "libobjc",
38 "libgcj",
39 "libclang_rt.builtins",
40 "libclang_rt.builtins-aarch64",
41 "libclang_rt.builtins-arm",
42 "libclang_rt.builtins-i386",
43 "libclang_rt.builtins-x86_64",
44 "libclang_rt.profile",
45 "libclang_rt.profile-aarch64",
46 "libclang_rt.profile-arm",
47 "libclang_rt.profile-i386",
48 "libclang_rt.profile-x86_64",
49 "libcygwin",
50 "libmsys-2.0",
51 "libc++",
52 "libc++abi",
53 "libflang_rt.runtime",
54 "libunwind",
55 "libmsvcrt",
56 "libmsvcrt-os",
57 "libucrtbase",
58 "libucrt",
59 "libucrtapp",
60 "libpthread",
61 "libwinpthread",
62 };
63
64 excludeObjects = {
65 "crt0.o", "crt1.o", "crt1u.o", "crt2.o", "crt2u.o", "dllcrt1.o",
66 "dllcrt2.o", "gcrt0.o", "gcrt1.o", "gcrt2.o", "crtbegin.o", "crtend.o",
67 };
68
69 excludeSymbolPrefixes = {
70 // Import symbols
71 "__imp_",
72 "__IMPORT_DESCRIPTOR_",
73 // Extra import symbols from GNU import libraries
74 "__nm_",
75 // C++ symbols
76 "__rtti_",
77 "__builtin_",
78 // Artificial symbols such as .refptr
79 ".",
80 // profile generate symbols
81 "__profc_",
82 "__profd_",
83 "__profvp_",
84 };
85
86 excludeSymbolSuffixes = {
87 "_iname",
88 "_NULL_THUNK_DATA",
89 };
90
91 if (symtab.machine == I386) {
92 excludeSymbols = {
93 "__NULL_IMPORT_DESCRIPTOR",
94 "__pei386_runtime_relocator",
95 "_do_pseudo_reloc",
96 "_impure_ptr",
97 "__impure_ptr",
98 "__fmode",
99 "_environ",
100 "___dso_handle",
101 "__load_config_used",
102 // These are the MinGW names that differ from the standard
103 // ones (lacking an extra underscore).
104 "_DllMain@12",
105 "_DllEntryPoint@12",
106 "_DllMainCRTStartup@12",
107 };
108 excludeSymbolPrefixes.insert(key: "__head_");
109 } else {
110 excludeSymbols = {
111 "__NULL_IMPORT_DESCRIPTOR",
112 "_pei386_runtime_relocator",
113 "do_pseudo_reloc",
114 "impure_ptr",
115 "_impure_ptr",
116 "_fmode",
117 "environ",
118 "__dso_handle",
119 "_load_config_used",
120 // These are the MinGW names that differ from the standard
121 // ones (lacking an extra underscore).
122 "DllMain",
123 "DllEntryPoint",
124 "DllMainCRTStartup",
125 };
126 excludeSymbolPrefixes.insert(key: "_head_");
127 }
128 if (symtab.isEC()) {
129 excludeSymbols.insert(key: "__chpe_metadata");
130 excludeSymbolPrefixes.insert(key: "__os_arm64x_");
131 }
132}
133
134void AutoExporter::addWholeArchive(StringRef path) {
135 StringRef libName = sys::path::filename(path);
136 // Drop the file extension, to match the processing below.
137 libName = libName.substr(Start: 0, N: libName.rfind(C: '.'));
138 excludeLibs.erase(Key: libName);
139}
140
141void AutoExporter::addExcludedSymbol(StringRef symbol) {
142 excludeSymbols.insert(key: symbol);
143}
144
145bool AutoExporter::shouldExport(Defined *sym) const {
146 if (!sym || !sym->getChunk())
147 return false;
148
149 // Only allow the symbol kinds that make sense to export; in particular,
150 // disallow import symbols.
151 if (!isa<DefinedRegular>(Val: sym) && !isa<DefinedCommon>(Val: sym))
152 return false;
153 if (excludeSymbols.contains(key: sym->getName()) ||
154 manualExcludeSymbols.contains(V: sym->getName()))
155 return false;
156
157 for (StringRef prefix : excludeSymbolPrefixes.keys())
158 if (sym->getName().starts_with(Prefix: prefix))
159 return false;
160 for (StringRef suffix : excludeSymbolSuffixes.keys())
161 if (sym->getName().ends_with(Suffix: suffix))
162 return false;
163
164 // If a corresponding __imp_ symbol exists and is defined, don't export it.
165 if (symtab.find(name: ("__imp_" + sym->getName()).str()))
166 return false;
167
168 // Check that file is non-null before dereferencing it, symbols not
169 // originating in regular object files probably shouldn't be exported.
170 if (!sym->getFile())
171 return false;
172
173 StringRef libName = sys::path::filename(path: sym->getFile()->parentName);
174
175 // Drop the file extension.
176 libName = libName.substr(Start: 0, N: libName.rfind(C: '.'));
177 if (!libName.empty())
178 return !excludeLibs.contains(key: libName);
179
180 StringRef fileName = sys::path::filename(path: sym->getFile()->getName());
181 return !excludeObjects.contains(key: fileName);
182}
183
184void lld::coff::writeDefFile(COFFLinkerContext &ctx, StringRef name,
185 const std::vector<Export> &exports) {
186 llvm::TimeTraceScope timeScope("Write .def file");
187 std::error_code ec;
188 raw_fd_ostream os(name, ec, sys::fs::OF_None);
189 if (ec)
190 Fatal(ctx) << "cannot open " << name << ": " << ec.message();
191
192 os << "EXPORTS\n";
193 for (const Export &e : exports) {
194 os << " " << e.exportName << " "
195 << "@" << e.ordinal;
196 if (auto *def = dyn_cast_or_null<Defined>(Val: e.sym)) {
197 if (def && def->getChunk() &&
198 !(def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
199 os << " DATA";
200 }
201 os << "\n";
202 }
203}
204
205static StringRef mangle(Twine sym, MachineTypes machine) {
206 assert(machine != IMAGE_FILE_MACHINE_UNKNOWN);
207 if (machine == I386)
208 return saver().save(S: "_" + sym);
209 return saver().save(S: sym);
210}
211
212// Handles -wrap option.
213//
214// This function instantiates wrapper symbols. At this point, they seem
215// like they are not being used at all, so we explicitly set some flags so
216// that LTO won't eliminate them.
217void lld::coff::addWrappedSymbols(SymbolTable &symtab,
218 opt::InputArgList &args) {
219 std::vector<WrappedSymbol> v;
220 DenseSet<StringRef> seen;
221
222 for (auto *arg : args.filtered(Ids: OPT_wrap)) {
223 StringRef name = arg->getValue();
224 if (!seen.insert(V: name).second)
225 continue;
226
227 Symbol *sym = symtab.findUnderscore(name);
228 if (!sym)
229 continue;
230
231 Symbol *real =
232 symtab.addUndefined(name: mangle(sym: "__real_" + name, machine: symtab.machine));
233 Symbol *wrap =
234 symtab.addUndefined(name: mangle(sym: "__wrap_" + name, machine: symtab.machine));
235 v.push_back(x: {.sym: sym, .real: real, .wrap: wrap});
236
237 // These symbols may seem undefined initially, but don't bail out
238 // at symtab.reportUnresolvable() due to them, but let wrapSymbols
239 // below sort things out before checking finally with
240 // symtab.resolveRemainingUndefines().
241 sym->deferUndefined = true;
242 real->deferUndefined = true;
243 // We want to tell LTO not to inline symbols to be overwritten
244 // because LTO doesn't know the final symbol contents after renaming.
245 real->canInline = false;
246 sym->canInline = false;
247
248 // Tell LTO not to eliminate these symbols.
249 sym->isUsedInRegularObj = true;
250 if (!isa<Undefined>(Val: wrap))
251 wrap->isUsedInRegularObj = true;
252 }
253 symtab.wrapped = std::move(v);
254}
255
256// Do renaming for -wrap by updating pointers to symbols.
257//
258// When this function is executed, only InputFiles and symbol table
259// contain pointers to symbol objects. We visit them to replace pointers,
260// so that wrapped symbols are swapped as instructed by the command line.
261void lld::coff::wrapSymbols(SymbolTable &symtab) {
262 DenseMap<Symbol *, Symbol *> map;
263 for (const WrappedSymbol &w : symtab.wrapped) {
264 map[w.sym] = w.wrap;
265 map[w.real] = w.sym;
266 if (Defined *d = dyn_cast<Defined>(Val: w.wrap)) {
267 Symbol *imp = symtab.find(name: ("__imp_" + w.sym->getName()).str());
268 // Create a new defined local import for the wrap symbol. If
269 // no imp prefixed symbol existed, there's no need for it.
270 // (We can't easily distinguish whether any object file actually
271 // referenced it or not, though.)
272 if (imp) {
273 if (Symbol *wrapimp =
274 symtab.find(name: ("__imp_" + w.wrap->getName()).str())) {
275 map[imp] = wrapimp;
276 } else {
277 DefinedLocalImport *localwrapimp = make<DefinedLocalImport>(
278 args&: symtab.ctx, args: saver().save(S: "__imp_" + w.wrap->getName()), args&: d);
279 symtab.localImportChunks.push_back(x: localwrapimp->getChunk());
280 map[imp] = localwrapimp;
281 }
282 }
283 }
284 }
285
286 // Update pointers in input files.
287 parallelForEach(R&: symtab.ctx.objFileInstances, Fn: [&](ObjFile *file) {
288 MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
289 for (auto &sym : syms)
290 if (Symbol *s = map.lookup(Val: sym))
291 sym = s;
292 });
293}
294