xref: /freebsd/contrib/llvm-project/lld/COFF/MinGW.cpp (revision e32fecd0c2c3ee37c47ee100f169e7eb0282a873)
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/Object/COFF.h"
17 #include "llvm/Support/Parallel.h"
18 #include "llvm/Support/Path.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 
26 AutoExporter::AutoExporter(
27     const llvm::DenseSet<StringRef> &manualExcludeSymbols)
28     : manualExcludeSymbols(manualExcludeSymbols) {
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       "libc++",
50       "libc++abi",
51       "libunwind",
52       "libmsvcrt",
53       "libucrtbase",
54   };
55 
56   excludeObjects = {
57       "crt0.o",    "crt1.o",  "crt1u.o", "crt2.o",  "crt2u.o",    "dllcrt1.o",
58       "dllcrt2.o", "gcrt0.o", "gcrt1.o", "gcrt2.o", "crtbegin.o", "crtend.o",
59   };
60 
61   excludeSymbolPrefixes = {
62       // Import symbols
63       "__imp_",
64       "__IMPORT_DESCRIPTOR_",
65       // Extra import symbols from GNU import libraries
66       "__nm_",
67       // C++ symbols
68       "__rtti_",
69       "__builtin_",
70       // Artificial symbols such as .refptr
71       ".",
72       // profile generate symbols
73       "__profc_",
74       "__profd_",
75       "__profvp_",
76   };
77 
78   excludeSymbolSuffixes = {
79       "_iname",
80       "_NULL_THUNK_DATA",
81   };
82 
83   if (config->machine == I386) {
84     excludeSymbols = {
85         "__NULL_IMPORT_DESCRIPTOR",
86         "__pei386_runtime_relocator",
87         "_do_pseudo_reloc",
88         "_impure_ptr",
89         "__impure_ptr",
90         "__fmode",
91         "_environ",
92         "___dso_handle",
93         // These are the MinGW names that differ from the standard
94         // ones (lacking an extra underscore).
95         "_DllMain@12",
96         "_DllEntryPoint@12",
97         "_DllMainCRTStartup@12",
98     };
99     excludeSymbolPrefixes.insert("__head_");
100   } else {
101     excludeSymbols = {
102         "__NULL_IMPORT_DESCRIPTOR",
103         "_pei386_runtime_relocator",
104         "do_pseudo_reloc",
105         "impure_ptr",
106         "_impure_ptr",
107         "_fmode",
108         "environ",
109         "__dso_handle",
110         // These are the MinGW names that differ from the standard
111         // ones (lacking an extra underscore).
112         "DllMain",
113         "DllEntryPoint",
114         "DllMainCRTStartup",
115     };
116     excludeSymbolPrefixes.insert("_head_");
117   }
118 }
119 
120 void AutoExporter::addWholeArchive(StringRef path) {
121   StringRef libName = sys::path::filename(path);
122   // Drop the file extension, to match the processing below.
123   libName = libName.substr(0, libName.rfind('.'));
124   excludeLibs.erase(libName);
125 }
126 
127 void AutoExporter::addExcludedSymbol(StringRef symbol) {
128   excludeSymbols.insert(symbol);
129 }
130 
131 bool AutoExporter::shouldExport(const COFFLinkerContext &ctx,
132                                 Defined *sym) const {
133   if (!sym || !sym->getChunk())
134     return false;
135 
136   // Only allow the symbol kinds that make sense to export; in particular,
137   // disallow import symbols.
138   if (!isa<DefinedRegular>(sym) && !isa<DefinedCommon>(sym))
139     return false;
140   if (excludeSymbols.count(sym->getName()) || manualExcludeSymbols.count(sym->getName()))
141     return false;
142 
143   for (StringRef prefix : excludeSymbolPrefixes.keys())
144     if (sym->getName().startswith(prefix))
145       return false;
146   for (StringRef suffix : excludeSymbolSuffixes.keys())
147     if (sym->getName().endswith(suffix))
148       return false;
149 
150   // If a corresponding __imp_ symbol exists and is defined, don't export it.
151   if (ctx.symtab.find(("__imp_" + sym->getName()).str()))
152     return false;
153 
154   // Check that file is non-null before dereferencing it, symbols not
155   // originating in regular object files probably shouldn't be exported.
156   if (!sym->getFile())
157     return false;
158 
159   StringRef libName = sys::path::filename(sym->getFile()->parentName);
160 
161   // Drop the file extension.
162   libName = libName.substr(0, libName.rfind('.'));
163   if (!libName.empty())
164     return !excludeLibs.count(libName);
165 
166   StringRef fileName = sys::path::filename(sym->getFile()->getName());
167   return !excludeObjects.count(fileName);
168 }
169 
170 void lld::coff::writeDefFile(StringRef name) {
171   std::error_code ec;
172   raw_fd_ostream os(name, ec, sys::fs::OF_None);
173   if (ec)
174     fatal("cannot open " + name + ": " + ec.message());
175 
176   os << "EXPORTS\n";
177   for (Export &e : config->exports) {
178     os << "    " << e.exportName << " "
179        << "@" << e.ordinal;
180     if (auto *def = dyn_cast_or_null<Defined>(e.sym)) {
181       if (def && def->getChunk() &&
182           !(def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
183         os << " DATA";
184     }
185     os << "\n";
186   }
187 }
188 
189 static StringRef mangle(Twine sym) {
190   assert(config->machine != IMAGE_FILE_MACHINE_UNKNOWN);
191   if (config->machine == I386)
192     return saver().save("_" + sym);
193   return saver().save(sym);
194 }
195 
196 // Handles -wrap option.
197 //
198 // This function instantiates wrapper symbols. At this point, they seem
199 // like they are not being used at all, so we explicitly set some flags so
200 // that LTO won't eliminate them.
201 std::vector<WrappedSymbol>
202 lld::coff::addWrappedSymbols(COFFLinkerContext &ctx, opt::InputArgList &args) {
203   std::vector<WrappedSymbol> v;
204   DenseSet<StringRef> seen;
205 
206   for (auto *arg : args.filtered(OPT_wrap)) {
207     StringRef name = arg->getValue();
208     if (!seen.insert(name).second)
209       continue;
210 
211     Symbol *sym = ctx.symtab.findUnderscore(name);
212     if (!sym)
213       continue;
214 
215     Symbol *real = ctx.symtab.addUndefined(mangle("__real_" + name));
216     Symbol *wrap = ctx.symtab.addUndefined(mangle("__wrap_" + name));
217     v.push_back({sym, real, wrap});
218 
219     // These symbols may seem undefined initially, but don't bail out
220     // at symtab.reportUnresolvable() due to them, but let wrapSymbols
221     // below sort things out before checking finally with
222     // symtab.resolveRemainingUndefines().
223     sym->deferUndefined = true;
224     real->deferUndefined = true;
225     // We want to tell LTO not to inline symbols to be overwritten
226     // because LTO doesn't know the final symbol contents after renaming.
227     real->canInline = false;
228     sym->canInline = false;
229 
230     // Tell LTO not to eliminate these symbols.
231     sym->isUsedInRegularObj = true;
232     if (!isa<Undefined>(wrap))
233       wrap->isUsedInRegularObj = true;
234   }
235   return v;
236 }
237 
238 // Do renaming for -wrap by updating pointers to symbols.
239 //
240 // When this function is executed, only InputFiles and symbol table
241 // contain pointers to symbol objects. We visit them to replace pointers,
242 // so that wrapped symbols are swapped as instructed by the command line.
243 void lld::coff::wrapSymbols(COFFLinkerContext &ctx,
244                             ArrayRef<WrappedSymbol> wrapped) {
245   DenseMap<Symbol *, Symbol *> map;
246   for (const WrappedSymbol &w : wrapped) {
247     map[w.sym] = w.wrap;
248     map[w.real] = w.sym;
249     if (Defined *d = dyn_cast<Defined>(w.wrap)) {
250       Symbol *imp = ctx.symtab.find(("__imp_" + w.sym->getName()).str());
251       // Create a new defined local import for the wrap symbol. If
252       // no imp prefixed symbol existed, there's no need for it.
253       // (We can't easily distinguish whether any object file actually
254       // referenced it or not, though.)
255       if (imp) {
256         DefinedLocalImport *wrapimp = make<DefinedLocalImport>(
257             saver().save("__imp_" + w.wrap->getName()), d);
258         ctx.symtab.localImportChunks.push_back(wrapimp->getChunk());
259         map[imp] = wrapimp;
260       }
261     }
262   }
263 
264   // Update pointers in input files.
265   parallelForEach(ctx.objFileInstances, [&](ObjFile *file) {
266     MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
267     for (size_t i = 0, e = syms.size(); i != e; ++i)
268       if (Symbol *s = map.lookup(syms[i]))
269         syms[i] = s;
270   });
271 }
272