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