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