xref: /freebsd/contrib/llvm-project/lld/COFF/MinGW.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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