1 //===- lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h ----------------===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 #include "lld/Core/Simple.h"
12 #include "lld/ReaderWriter/PECOFFLinkingContext.h"
13 #include "llvm/Support/Allocator.h"
17 using llvm::COFF::WindowsSubsystem;
22 bool findDecoratedSymbol(PECOFFLinkingContext *ctx,
23 std::string sym, std::string &res);
27 /// The defined atom for dllexported symbols with __imp_ prefix.
28 class ImpPointerAtom : public COFFLinkerInternalAtom {
30 ImpPointerAtom(const File &file, StringRef symbolName, uint64_t ordinal)
31 : COFFLinkerInternalAtom(file, /*oridnal*/ 0, std::vector<uint8_t>(4),
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__; }
45 class ImpSymbolFile : public SimpleFile {
47 ImpSymbolFile(StringRef defsym, StringRef undefsym, uint64_t ordinal,
49 : SimpleFile(defsym), _undefined(*this, undefsym),
50 _defined(*this, defsym, ordinal) {
53 ref = new SimpleReference(Reference::KindNamespace::COFF,
54 Reference::KindArch::x86_64,
55 llvm::COFF::IMAGE_REL_AMD64_ADDR32,
58 ref = new SimpleReference(Reference::KindNamespace::COFF,
59 Reference::KindArch::x86,
60 llvm::COFF::IMAGE_REL_I386_DIR32,
63 _defined.addReference(std::unique_ptr<SimpleReference>(ref));
69 SimpleUndefinedAtom _undefined;
70 ImpPointerAtom _defined;
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 {
78 SymbolRenameFile(StringRef from, StringRef to)
79 : SimpleFile("<symbol-rename>"), _fromSym(from), _toSym(to),
80 _from(*this, _fromSym, &_to), _to(*this, _toSym) {
87 COFFUndefinedAtom _from;
88 COFFUndefinedAtom _to;
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 {
98 LinkerGeneratedSymbolFile(const PECOFFLinkingContext &ctx)
99 : SimpleFile("<linker-internal-file>"),
100 _imageBaseAtom(*this, ctx.decorateSymbol("__ImageBase"),
101 Atom::scopeGlobal, ctx.getBaseAddress()) {
102 addAtom(_imageBaseAtom);
106 SimpleAbsoluteAtom _imageBaseAtom;
109 // A LocallyImporteSymbolFile is an archive file containing __imp_
110 // symbols for local use.
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.)
120 // void hello() { printf("Hello\n"); }
121 // extern void (*_imp__hello)();
127 // This odd feature is for the compatibility with MSVC link.exe.
128 class LocallyImportedSymbolFile : public SimpleArchiveLibraryFile {
130 LocallyImportedSymbolFile(const PECOFFLinkingContext &ctx)
131 : SimpleArchiveLibraryFile("__imp_"), _is64(ctx.is64Bit()),
134 File *find(StringRef sym, bool dataSymbolOnly) override {
135 std::string prefix = "__imp_";
136 if (!sym.startswith(prefix))
138 StringRef undef = sym.substr(prefix.size());
139 return new (_alloc) impl::ImpSymbolFile(sym, undef, _ordinal++, _is64);
145 llvm::BumpPtrAllocator _alloc;
148 // A ExportedSymbolRenameFile is a virtual archive file for dllexported symbols.
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.
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.
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.
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.
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.
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
178 class ExportedSymbolRenameFile : public SimpleArchiveLibraryFile {
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);
187 File *find(StringRef sym, bool dataSymbolOnly) override {
188 typedef PECOFFLinkingContext::ExportDesc ExportDesc;
189 if (_exportedSyms.count(sym) == 0)
192 if (!findDecoratedSymbol(_ctx, sym.str(), replace))
195 for (ExportDesc &exp : _ctx->getDllExports())
197 exp.mangledName = replace;
198 if (_ctx->deadStrip())
199 _ctx->addDeadStripRoot(_ctx->allocate(replace));
200 return new (_alloc) impl::SymbolRenameFile(sym, replace);
204 std::set<std::string> _exportedSyms;
205 llvm::BumpPtrAllocator _alloc;
206 PECOFFLinkingContext *_ctx;
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.
213 // http://msdn.microsoft.com/en-us/library/f9t8842e.aspx
214 class EntryPointFile : public SimpleFile {
216 EntryPointFile(const PECOFFLinkingContext &ctx)
217 : SimpleFile("<entry>"), _ctx(const_cast<PECOFFLinkingContext *>(&ctx)),
220 const atom_collection<UndefinedAtom> &undefined() const override {
221 return const_cast<EntryPointFile *>(this)->getUndefinedAtoms();
225 const atom_collection<UndefinedAtom> &getUndefinedAtoms() {
226 std::lock_guard<std::mutex> lock(_mutex);
228 return _undefinedAtoms;
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);
240 return _undefinedAtoms;
243 // Returns the entry point function name.
244 std::string getEntry() const {
245 StringRef opt = _ctx->getEntrySymbolName();
248 if (findDecoratedSymbol(_ctx, opt, mangled))
250 return _ctx->decorateSymbol(opt);
252 return _ctx->decorateSymbol(getDefaultEntry());
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";
262 if (_ctx->getMachineType() == llvm::COFF::IMAGE_FILE_MACHINE_I386)
263 return "_DllMainCRTStartup@12";
264 return "_DllMainCRTStartup";
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))
273 return findDecoratedSymbol(_ctx, sym, ignore);
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;
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;
297 return mainCRTStartup;
301 PECOFFLinkingContext *_ctx;
302 atom_collection_vector<UndefinedAtom> _undefinedAtoms;
304 llvm::BumpPtrAllocator _alloc;
308 } // end namespace pecoff
309 } // end namespace lld