Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -547,6 +547,64 @@ } } +// Get a sorted list of symbols not to automatically export +// when exporting all global symbols for MinGW. +static StringSet<> getExportExcludeSymbols() { + if (Config->Machine == I386) + return { + "__NULL_IMPORT_DESCRIPTOR", + "__pei386_runtime_relocator", + "_do_pseudo_reloc", + "_impure_ptr", + "__impure_ptr", + "__fmode", + "_environ", + "___dso_handle", + // These are the MinGW names that differ from the standard + // ones (lacking an extra underscore). + "_DllMain@12", + "_DllEntryPoint@12", + "_DllMainCRTStartup@12", + }; + + return { + "_NULL_IMPORT_DESCRIPTOR", + "_pei386_runtime_relocator", + "do_pseudo_reloc", + "impure_ptr", + "_impure_ptr", + "_fmode", + "environ", + "__dso_handle", + // These are the MinGW names that differ from the standard + // ones (lacking an extra underscore). + "DllMain", + "DllEntryPoint", + "DllMainCRTStartup", + }; +} + +// This is MinGW specific. +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; + if (E.Sym) { + auto *Def = dyn_cast(E.Sym); + if (Def && Def->getChunk() && + !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) + OS << " DATA"; + } + OS << "\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 +1255,25 @@ 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))) { + StringSet<> ExcludeSymbols = getExportExcludeSymbols(); + + Symtab->forEachSymbol([=](Symbol *S) { + auto *Def = dyn_cast(S->body()); + if (!Def || !Def->isLive() || !Def->getChunk()) + return; + if (ExcludeSymbols.count(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 +1282,10 @@ assignExportOrdinals(); } + // Handle /output-def (MinGW specific). + 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