]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
Vendor import of lld trunk r233088:
[FreeBSD/FreeBSD.git] / lib / ReaderWriter / PECOFF / LinkerGeneratedSymbolFile.h
1 //===- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h ----------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "Atoms.h"
11 #include "lld/Core/Simple.h"
12 #include "lld/ReaderWriter/PECOFFLinkingContext.h"
13 #include "llvm/Support/Allocator.h"
14 #include <algorithm>
15 #include <mutex>
16
17 using llvm::COFF::WindowsSubsystem;
18
19 namespace lld {
20 namespace pecoff {
21
22 bool findDecoratedSymbol(PECOFFLinkingContext *ctx,
23                          std::string sym, std::string &res);
24
25 namespace impl {
26
27 /// The defined atom for dllexported symbols with __imp_ prefix.
28 class ImpPointerAtom : public COFFLinkerInternalAtom {
29 public:
30   ImpPointerAtom(const File &file, StringRef symbolName, uint64_t ordinal)
31       : COFFLinkerInternalAtom(file, /*oridnal*/ 0, std::vector<uint8_t>(4),
32                                symbolName),
33         _ordinal(ordinal) {}
34
35   uint64_t ordinal() const override { return _ordinal; }
36   Scope scope() const override { return scopeGlobal; }
37   ContentType contentType() const override { return typeData; }
38   Alignment alignment() const override { return Alignment(4); }
39   ContentPermissions permissions() const override { return permR__; }
40
41 private:
42   uint64_t _ordinal;
43 };
44
45 class ImpSymbolFile : public SimpleFile {
46 public:
47   ImpSymbolFile(StringRef defsym, StringRef undefsym, uint64_t ordinal,
48                 bool is64)
49       : SimpleFile(defsym), _undefined(*this, undefsym),
50         _defined(*this, defsym, ordinal) {
51     SimpleReference *ref;
52     if (is64) {
53       ref = new SimpleReference(Reference::KindNamespace::COFF,
54                                 Reference::KindArch::x86_64,
55                                 llvm::COFF::IMAGE_REL_AMD64_ADDR32,
56                                 0, &_undefined, 0);
57     } else {
58       ref = new SimpleReference(Reference::KindNamespace::COFF,
59                                 Reference::KindArch::x86,
60                                 llvm::COFF::IMAGE_REL_I386_DIR32,
61                                 0, &_undefined, 0);
62     }
63     _defined.addReference(std::unique_ptr<SimpleReference>(ref));
64     addAtom(_defined);
65     addAtom(_undefined);
66   };
67
68 private:
69   SimpleUndefinedAtom _undefined;
70   ImpPointerAtom _defined;
71 };
72
73 // A file to make Resolver to resolve a symbol TO instead of a symbol FROM,
74 // using fallback mechanism for an undefined symbol. One can virtually rename an
75 // undefined symbol using this file.
76 class SymbolRenameFile : public SimpleFile {
77 public:
78   SymbolRenameFile(StringRef from, StringRef to)
79       : SimpleFile("<symbol-rename>"), _fromSym(from), _toSym(to),
80         _from(*this, _fromSym, &_to), _to(*this, _toSym) {
81     addAtom(_from);
82   };
83
84 private:
85   std::string _fromSym;
86   std::string _toSym;
87   COFFUndefinedAtom _from;
88   COFFUndefinedAtom _to;
89 };
90
91 } // namespace impl
92
93 // A virtual file containing absolute symbol __ImageBase. __ImageBase (or
94 // ___ImageBase on x86) is a linker-generated symbol whose address is the same
95 // as the image base address.
96 class LinkerGeneratedSymbolFile : public SimpleFile {
97 public:
98   LinkerGeneratedSymbolFile(const PECOFFLinkingContext &ctx)
99       : SimpleFile("<linker-internal-file>"),
100         _imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"),
101                        Atom::scopeGlobal, ctx.getBaseAddress()) {
102     addAtom(_imageBaseAtom);
103   };
104
105 private:
106   SimpleAbsoluteAtom _imageBaseAtom;
107 };
108
109 // A LocallyImporteSymbolFile is an archive file containing __imp_
110 // symbols for local use.
111 //
112 // For each defined symbol, linker creates an implicit defined symbol
113 // by appending "__imp_" prefix to the original name. The content of
114 // the implicit symbol is a pointer to the original symbol
115 // content. This feature allows one to compile and link the following
116 // code without error, although _imp__hello is not defined in the
117 // code. (the leading "_" in this example is automatically appended,
118 // assuming it's x86.)
119 //
120 //   void hello() { printf("Hello\n"); }
121 //   extern void (*_imp__hello)();
122 //   int main() {
123 //      _imp__hello();
124 //      return 0;
125 //   }
126 //
127 // This odd feature is for the compatibility with MSVC link.exe.
128 class LocallyImportedSymbolFile : public SimpleArchiveLibraryFile {
129 public:
130   LocallyImportedSymbolFile(const PECOFFLinkingContext &ctx)
131       : SimpleArchiveLibraryFile("__imp_"), _is64(ctx.is64Bit()),
132         _ordinal(0) {}
133
134   File *find(StringRef sym, bool dataSymbolOnly) override {
135     std::string prefix = "__imp_";
136     if (!sym.startswith(prefix))
137       return nullptr;
138     StringRef undef = sym.substr(prefix.size());
139     return new (_alloc) impl::ImpSymbolFile(sym, undef, _ordinal++, _is64);
140   }
141
142 private:
143   bool _is64;
144   uint64_t _ordinal;
145   llvm::BumpPtrAllocator _alloc;
146 };
147
148 // A ExportedSymbolRenameFile is a virtual archive file for dllexported symbols.
149 //
150 // One usually has to specify the exact symbol name to resolve it. That's true
151 // in most cases for PE/COFF, except the one described below.
152 //
153 // DLLExported symbols can be specified using a module definition file. In a
154 // file, one can write an EXPORT directive followed by symbol names. Such
155 // symbols may not be fully decorated.
156 //
157 // If a symbol FOO is specified to be dllexported by a module definition file,
158 // linker has to search not only for /FOO/ but also for /FOO@[0-9]+/ for stdcall
159 // and for /\?FOO@@.+/ for C++. This ambiguous matching semantics does not fit
160 // well with Resolver.
161 //
162 // We could probably modify Resolver to resolve ambiguous symbols, but I think
163 // we don't want to do that because it'd be rarely used, and only this Windows
164 // specific feature would use it. It's probably not a good idea to make the core
165 // linker to be able to deal with it.
166 //
167 // So, instead of tweaking Resolver, we chose to do some hack here. An
168 // ExportedSymbolRenameFile maintains a set containing all possibly defined
169 // symbol names. That set would be a union of (1) all the defined symbols that
170 // are already parsed and read and (2) all the defined symbols in archive files
171 // that are not yet be parsed.
172 //
173 // If Resolver asks this file to return an atom for a dllexported symbol, find()
174 // looks up the set, doing ambiguous matching. If there's a symbol with @
175 // prefix, it returns an atom to rename the dllexported symbol, hoping that
176 // Resolver will find the new symbol with atsign from an archive file at the
177 // next visit.
178 class ExportedSymbolRenameFile : public SimpleArchiveLibraryFile {
179 public:
180   ExportedSymbolRenameFile(const PECOFFLinkingContext &ctx)
181       : SimpleArchiveLibraryFile("<export>"),
182         _ctx(const_cast<PECOFFLinkingContext *>(&ctx)) {
183     for (PECOFFLinkingContext::ExportDesc &desc : _ctx->getDllExports())
184       _exportedSyms.insert(desc.name);
185   }
186
187   File *find(StringRef sym, bool dataSymbolOnly) override {
188     typedef PECOFFLinkingContext::ExportDesc ExportDesc;
189     if (_exportedSyms.count(sym) == 0)
190       return nullptr;
191     std::string replace;
192     if (!findDecoratedSymbol(_ctx, sym.str(), replace))
193       return nullptr;
194
195     for (ExportDesc &exp : _ctx->getDllExports())
196       if (exp.name == sym)
197         exp.mangledName = replace;
198     if (_ctx->deadStrip())
199       _ctx->addDeadStripRoot(_ctx->allocate(replace));
200     return new (_alloc) impl::SymbolRenameFile(sym, replace);
201   }
202
203 private:
204   std::set<std::string> _exportedSyms;
205   llvm::BumpPtrAllocator _alloc;
206   PECOFFLinkingContext *_ctx;
207 };
208
209 // Windows has not only one but many entry point functions. The
210 // appropriate one is automatically selected based on the subsystem
211 // setting and the user-supplied entry point function.
212 //
213 // http://msdn.microsoft.com/en-us/library/f9t8842e.aspx
214 class EntryPointFile : public SimpleFile {
215 public:
216   EntryPointFile(const PECOFFLinkingContext &ctx)
217       : SimpleFile("<entry>"), _ctx(const_cast<PECOFFLinkingContext *>(&ctx)),
218         _firstTime(true) {}
219
220   const atom_collection<UndefinedAtom> &undefined() const override {
221     return const_cast<EntryPointFile *>(this)->getUndefinedAtoms();
222   }
223
224 private:
225   const atom_collection<UndefinedAtom> &getUndefinedAtoms() {
226     std::lock_guard<std::mutex> lock(_mutex);
227     if (!_firstTime)
228       return _undefinedAtoms;
229     _firstTime = false;
230
231     if (_ctx->hasEntry()) {
232       StringRef entrySym = _ctx->allocate(getEntry());
233       _undefinedAtoms._atoms.push_back(
234           new (_alloc) SimpleUndefinedAtom(*this, entrySym));
235       _ctx->setHasEntry(true);
236       _ctx->setEntrySymbolName(entrySym);
237       if (_ctx->deadStrip())
238         _ctx->addDeadStripRoot(entrySym);
239     }
240     return _undefinedAtoms;
241   }
242
243   // Returns the entry point function name.
244   std::string getEntry() const {
245     StringRef opt = _ctx->getEntrySymbolName();
246     if (!opt.empty()) {
247       std::string mangled;
248       if (findDecoratedSymbol(_ctx, opt, mangled))
249         return mangled;
250       return _ctx->decorateSymbol(opt);
251     }
252     return _ctx->decorateSymbol(getDefaultEntry());
253   }
254
255   std::string getDefaultEntry() const {
256     const std::string wWinMainCRTStartup = "wWinMainCRTStartup";
257     const std::string WinMainCRTStartup = "WinMainCRTStartup";
258     const std::string wmainCRTStartup = "wmainCRTStartup";
259     const std::string mainCRTStartup = "mainCRTStartup";
260
261     if (_ctx->isDll()) {
262       if (_ctx->getMachineType() == llvm::COFF::IMAGE_FILE_MACHINE_I386)
263         return "_DllMainCRTStartup@12";
264       return "_DllMainCRTStartup";
265     }
266
267     // Returns true if a given name exists in an input object file.
268     auto defined = [&](StringRef name) -> bool {
269       StringRef sym = _ctx->decorateSymbol(name);
270       if (_ctx->definedSymbols().count(sym))
271         return true;
272       std::string ignore;
273       return findDecoratedSymbol(_ctx, sym, ignore);
274     };
275
276     switch (_ctx->getSubsystem()) {
277     case WindowsSubsystem::IMAGE_SUBSYSTEM_UNKNOWN: {
278       if (defined("wWinMain"))
279         return wWinMainCRTStartup;
280       if (defined("WinMain"))
281         return WinMainCRTStartup;
282       if (defined("wmain"))
283         return wmainCRTStartup;
284       if (!defined("main"))
285         llvm::errs() << "Cannot infer subsystem; assuming /subsystem:console\n";
286       return mainCRTStartup;
287     }
288     case WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI:
289       if (defined("WinMain"))
290         return WinMainCRTStartup;
291       return wWinMainCRTStartup;
292     case WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_CUI:
293       if (defined("wmain"))
294         return wmainCRTStartup;
295       return mainCRTStartup;
296     default:
297       return mainCRTStartup;
298     }
299   }
300
301   PECOFFLinkingContext *_ctx;
302   atom_collection_vector<UndefinedAtom> _undefinedAtoms;
303   std::mutex _mutex;
304   llvm::BumpPtrAllocator _alloc;
305   bool _firstTime;
306 };
307
308 } // end namespace pecoff
309 } // end namespace lld