Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -547,6 +547,18 @@ } } +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 +1209,53 @@ return; } + if (Config->DLL && ((Config->MinGW && Config->Exports.empty()) || + Args.hasArg(OPT_export_all_symbols))) { + std::vector ExcludeSymbols = { + "_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 I386, prepend the underscore - all the symbols in the exclude list + // are cdecl/stdcall that should have an underscore. + for (auto &Str : ExcludeSymbols) + Str = "_" + Str; + } else { + // For non-I386, drop the stdcall decoration. + for (auto &Str : ExcludeSymbols) + Str = Str.substr(0, Str.find('@')); + } + std::set ExcludeSymbolSet(ExcludeSymbols.begin(), + ExcludeSymbols.end()); + + Symtab->forEachSymbol([=](Symbol *S) { + auto *Def = dyn_cast(S->body()); + if (Def && Def->isLive() && Def->getChunk()) { + if (ExcludeSymbolSet.find(Def->getName()) != ExcludeSymbolSet.end()) + 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 +1264,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