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
21 using namespace llvm;
22 using namespace llvm::COFF;
23 using namespace lld;
24 using namespace lld::coff;
25
AutoExporter(SymbolTable & symtab,const llvm::DenseSet<StringRef> & manualExcludeSymbols)26 AutoExporter::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("__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("_head_");
127 }
128 if (symtab.isEC()) {
129 excludeSymbols.insert("__chpe_metadata");
130 excludeSymbolPrefixes.insert("__os_arm64x_");
131 }
132 }
133
addWholeArchive(StringRef path)134 void 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(0, libName.rfind('.'));
138 excludeLibs.erase(libName);
139 }
140
addExcludedSymbol(StringRef symbol)141 void AutoExporter::addExcludedSymbol(StringRef symbol) {
142 excludeSymbols.insert(symbol);
143 }
144
shouldExport(Defined * sym) const145 bool 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>(sym) && !isa<DefinedCommon>(sym))
152 return false;
153 if (excludeSymbols.count(sym->getName()) || manualExcludeSymbols.count(sym->getName()))
154 return false;
155
156 for (StringRef prefix : excludeSymbolPrefixes.keys())
157 if (sym->getName().starts_with(prefix))
158 return false;
159 for (StringRef suffix : excludeSymbolSuffixes.keys())
160 if (sym->getName().ends_with(suffix))
161 return false;
162
163 // If a corresponding __imp_ symbol exists and is defined, don't export it.
164 if (symtab.find(("__imp_" + sym->getName()).str()))
165 return false;
166
167 // Check that file is non-null before dereferencing it, symbols not
168 // originating in regular object files probably shouldn't be exported.
169 if (!sym->getFile())
170 return false;
171
172 StringRef libName = sys::path::filename(sym->getFile()->parentName);
173
174 // Drop the file extension.
175 libName = libName.substr(0, libName.rfind('.'));
176 if (!libName.empty())
177 return !excludeLibs.count(libName);
178
179 StringRef fileName = sys::path::filename(sym->getFile()->getName());
180 return !excludeObjects.count(fileName);
181 }
182
writeDefFile(COFFLinkerContext & ctx,StringRef name,const std::vector<Export> & exports)183 void lld::coff::writeDefFile(COFFLinkerContext &ctx, StringRef name,
184 const std::vector<Export> &exports) {
185 llvm::TimeTraceScope timeScope("Write .def file");
186 std::error_code ec;
187 raw_fd_ostream os(name, ec, sys::fs::OF_None);
188 if (ec)
189 Fatal(ctx) << "cannot open " << name << ": " << ec.message();
190
191 os << "EXPORTS\n";
192 for (const Export &e : exports) {
193 os << " " << e.exportName << " "
194 << "@" << e.ordinal;
195 if (auto *def = dyn_cast_or_null<Defined>(e.sym)) {
196 if (def && def->getChunk() &&
197 !(def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
198 os << " DATA";
199 }
200 os << "\n";
201 }
202 }
203
mangle(Twine sym,MachineTypes machine)204 static StringRef mangle(Twine sym, MachineTypes machine) {
205 assert(machine != IMAGE_FILE_MACHINE_UNKNOWN);
206 if (machine == I386)
207 return saver().save("_" + sym);
208 return saver().save(sym);
209 }
210
211 // Handles -wrap option.
212 //
213 // This function instantiates wrapper symbols. At this point, they seem
214 // like they are not being used at all, so we explicitly set some flags so
215 // that LTO won't eliminate them.
addWrappedSymbols(SymbolTable & symtab,opt::InputArgList & args)216 void lld::coff::addWrappedSymbols(SymbolTable &symtab,
217 opt::InputArgList &args) {
218 std::vector<WrappedSymbol> v;
219 DenseSet<StringRef> seen;
220
221 for (auto *arg : args.filtered(OPT_wrap)) {
222 StringRef name = arg->getValue();
223 if (!seen.insert(name).second)
224 continue;
225
226 Symbol *sym = symtab.findUnderscore(name);
227 if (!sym)
228 continue;
229
230 Symbol *real =
231 symtab.addUndefined(mangle("__real_" + name, symtab.machine));
232 Symbol *wrap =
233 symtab.addUndefined(mangle("__wrap_" + name, symtab.machine));
234 v.push_back({sym, real, wrap});
235
236 // These symbols may seem undefined initially, but don't bail out
237 // at symtab.reportUnresolvable() due to them, but let wrapSymbols
238 // below sort things out before checking finally with
239 // symtab.resolveRemainingUndefines().
240 sym->deferUndefined = true;
241 real->deferUndefined = true;
242 // We want to tell LTO not to inline symbols to be overwritten
243 // because LTO doesn't know the final symbol contents after renaming.
244 real->canInline = false;
245 sym->canInline = false;
246
247 // Tell LTO not to eliminate these symbols.
248 sym->isUsedInRegularObj = true;
249 if (!isa<Undefined>(wrap))
250 wrap->isUsedInRegularObj = true;
251 }
252 symtab.wrapped = std::move(v);
253 }
254
255 // Do renaming for -wrap by updating pointers to symbols.
256 //
257 // When this function is executed, only InputFiles and symbol table
258 // contain pointers to symbol objects. We visit them to replace pointers,
259 // so that wrapped symbols are swapped as instructed by the command line.
wrapSymbols(SymbolTable & symtab)260 void lld::coff::wrapSymbols(SymbolTable &symtab) {
261 DenseMap<Symbol *, Symbol *> map;
262 for (const WrappedSymbol &w : symtab.wrapped) {
263 map[w.sym] = w.wrap;
264 map[w.real] = w.sym;
265 if (Defined *d = dyn_cast<Defined>(w.wrap)) {
266 Symbol *imp = symtab.find(("__imp_" + w.sym->getName()).str());
267 // Create a new defined local import for the wrap symbol. If
268 // no imp prefixed symbol existed, there's no need for it.
269 // (We can't easily distinguish whether any object file actually
270 // referenced it or not, though.)
271 if (imp) {
272 DefinedLocalImport *wrapimp = make<DefinedLocalImport>(
273 symtab.ctx, saver().save("__imp_" + w.wrap->getName()), d);
274 symtab.localImportChunks.push_back(wrapimp->getChunk());
275 map[imp] = wrapimp;
276 }
277 }
278 }
279
280 // Update pointers in input files.
281 parallelForEach(symtab.ctx.objFileInstances, [&](ObjFile *file) {
282 MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
283 for (auto &sym : syms)
284 if (Symbol *s = map.lookup(sym))
285 sym = s;
286 });
287 }
288