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