Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -547,6 +547,51 @@ } } +// Get a sorted list of symbols not to automatically export +// when exporting all global symbols for MinGW. +static std::vector getExportExcludeSymbols() { + // These symbols are in the I386 form with a prepended underscore + // and with stdcall decorations where applicable. + std::vector V = { + "__NULL_IMPORT_DESCRIPTOR", + // Runtime pseudo-reloc. + "__pei386_runtime_relocator", + "_do_pseudo_reloc", + // Global vars that should not be exported. + "_impure_ptr", + "__impure_ptr", + "__fmode", + "_environ", + "___dso_handle", + // Entry point symbols, and entry hooks; these are the MinGW + // names that differ from the standard ones (lacking an extra + // underscore). + "_DllMain@12", + "_DllEntryPoint@0", + "_DllMainCRTStartup@12", + }; + + if (Config->Machine != I386) { + // For non-I386, drop the leading underscore and stdcall decoration. + for (auto &Str : V) + Str = Str.drop_front().substr(0, Str.find('@')); + } + std::sort(V.begin(), V.end()); + return V; +} + +static void writeDefFile(StringRef Name) { + std::error_code EC; + raw_fd_ostream OS(Name, EC, sys::fs::F_None); + if (EC) + fatal("cannot open " + Name + ": " + EC.message()); + + OS << "EXPORTS\n"; + for (Export &E : Config->Exports) + OS << " " << E.ExportName << " " + << "@" << E.Ordinal << "\n"; +} + // A helper function for filterBitcodeFiles. static bool needsRebuilding(MemoryBufferRef MB) { // The MSVC linker doesn't support thin archives, so if it's a thin @@ -1197,6 +1242,26 @@ return; } + // In MinGW, all symbols are automatically exported if no symbols + // are chosen to be exported. + if (Config->DLL && ((Config->MinGW && Config->Exports.empty()) || + Args.hasArg(OPT_export_all_symbols))) { + std::vector ExcludeSymbols = getExportExcludeSymbols(); + + Symtab->forEachSymbol([=](Symbol *S) { + auto *Def = dyn_cast(S->body()); + if (!Def || !Def->isLive() || !Def->getChunk()) + return; + if (std::binary_search(ExcludeSymbols.begin(), ExcludeSymbols.end(), + Def->getName())) + return; + Export E; + E.Name = Def->getName(); + E.Sym = Def; + Config->Exports.push_back(E); + }); + } + // Windows specific -- when we are creating a .dll file, we also // need to create a .lib file. if (!Config->Exports.empty() || Config->DLL) { @@ -1205,6 +1270,10 @@ assignExportOrdinals(); } + // Handle /output-def + if (auto *Arg = Args.getLastArg(OPT_output_def)) + writeDefFile(Arg->getValue()); + // Set extra alignment for .comm symbols for (auto Pair : Config->AlignComm) { StringRef Name = Pair.first; Index: COFF/Options.td =================================================================== --- COFF/Options.td +++ COFF/Options.td @@ -102,10 +102,12 @@ def help_q : Flag<["/?", "-?"], "">, Alias; // LLD extensions +def export_all_symbols : F<"export-all-symbols">; def nopdb : F<"nopdb">, HelpText<"Disable PDB generation for DWARF users">; def nosymtab : F<"nosymtab">; def lldmingw : F<"lldmingw">; def msvclto : F<"msvclto">; +def output_def : Joined<["/", "-"], "output-def:">; def rsp_quoting : Joined<["--"], "rsp-quoting=">, HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">; Index: test/COFF/export-all.s =================================================================== --- /dev/null +++ test/COFF/export-all.s @@ -0,0 +1,38 @@ +# REQEUIRES: x86 + +# RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj + +# RUN: lld-link -lldmingw -dll -out:%t.dll -entry:DllMainCRTStartup@12 %t.obj -implib:%t.lib +# RUN: llvm-readobj -coff-exports %t.dll | FileCheck %s + +# CHECK-NOT: Name: DllMainCRTStartup +# CHECK: Name: foobar + +.global _foobar +.global _DllMainCRTStartup@12 +.text +_DllMainCRTStartup@12: + ret +_foobar: + ret + +# Test specifying -export-all-symbols, on an object file that contains axi +# dllexport directive for some of the symbols. + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# +# RUN: lld-link -out:%t.dll -dll %t.obj -lldmingw -export-all-symbols -output-def:%t.def +# RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix=CHECK2 %s +# RUN: cat %t.def | FileCheck -check-prefix=CHECK2-DEF %s + +# Note, this will actually export _DllMainCRTStartup as well, since +# it uses the standard spelling in this object file, not the MinGW one. + +# CHECK2: Name: exportfn1 +# CHECK2: Name: exportfn2 +# CHECK2: Name: exportfn3 + +# CHECK2-DEF: EXPORTS +# CHECK2-DEF: exportfn1 @3 +# CHECK2-DEF: exportfn2 @4 +# CHECK2-DEF: exportfn3 @5