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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of lld/COFF/MinGW.cpp