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