Index: COFF/Driver.h =================================================================== --- COFF/Driver.h +++ COFF/Driver.h @@ -110,11 +110,11 @@ void invokeMSVC(llvm::opt::InputArgList &Args); MemoryBufferRef takeBuffer(std::unique_ptr MB); - void addBuffer(std::unique_ptr MB); + void addBuffer(std::unique_ptr MB, bool WholeArchive); void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName, StringRef ParentName); - void enqueuePath(StringRef Path); + void enqueuePath(StringRef Path, bool WholeArchive); void enqueueTask(std::function Task); bool run(); Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -110,7 +110,8 @@ return MBRef; } -void LinkerDriver::addBuffer(std::unique_ptr MB) { +void LinkerDriver::addBuffer(std::unique_ptr MB, + bool WholeArchive) { MemoryBufferRef MBRef = takeBuffer(std::move(MB)); // File type is detected by contents, not by file extension. @@ -121,8 +122,18 @@ } FilePaths.push_back(MBRef.getBufferIdentifier()); - if (Magic == file_magic::archive) + if (Magic == file_magic::archive) { + if (WholeArchive) { + std::unique_ptr File = + check(Archive::create(MBRef), + MBRef.getBufferIdentifier() + ": failed to parse archive"); + + for (MemoryBufferRef Member : getArchiveMembers(File.get())) + addArchiveBuffer(Member, "*", MBRef.getBufferIdentifier()); + return; + } return Symtab->addFile(make(MBRef)); + } if (Magic == file_magic::bitcode) return Symtab->addFile(make(MBRef)); @@ -133,7 +144,7 @@ Symtab->addFile(make(MBRef)); } -void LinkerDriver::enqueuePath(StringRef Path) { +void LinkerDriver::enqueuePath(StringRef Path, bool WholeArchive) { auto Future = std::make_shared>(createFutureForFile(Path)); std::string PathStr = Path; @@ -142,7 +153,7 @@ if (MBOrErr.second) error("could not open " + PathStr + ": " + MBOrErr.second.message()); else - Driver->addBuffer(std::move(MBOrErr.first)); + Driver->addBuffer(std::move(MBOrErr.first), WholeArchive); }); } @@ -215,7 +226,7 @@ break; case OPT_defaultlib: if (Optional Path = findLib(Arg->getValue())) - enqueuePath(*Path); + enqueuePath(*Path, false); break; case OPT_export: { Export E = parseExport(Arg->getValue()); @@ -955,16 +966,29 @@ // Create a list of input files. Files can be given as arguments // for /defaultlib option. std::vector MBs; - for (auto *Arg : Args.filtered(OPT_INPUT)) - if (Optional Path = findFile(Arg->getValue())) - enqueuePath(*Path); + bool WholeArchive = false; + for (auto *Arg : + Args.filtered(OPT_INPUT, OPT_whole_archive, OPT_no_whole_archive)) { + switch (Arg->getOption().getID()) { + case OPT_INPUT: + if (Optional Path = findFile(Arg->getValue())) + enqueuePath(*Path, WholeArchive); + break; + case OPT_whole_archive: + WholeArchive = true; + break; + case OPT_no_whole_archive: + WholeArchive = false; + break; + } + } for (auto *Arg : Args.filtered(OPT_defaultlib)) if (Optional Path = findLib(Arg->getValue())) - enqueuePath(*Path); + enqueuePath(*Path, false); // Windows specific -- Create a resource file containing a manifest file. if (Config->Manifest == Configuration::Embed) - addBuffer(createManifestRes()); + addBuffer(createManifestRes(), false); // Read all input files given via the command line. run(); @@ -980,7 +1004,7 @@ // WindowsResource to convert resource files to a regular COFF file, // then link the resulting file normally. if (!Resources.empty()) - addBuffer(convertResToCOFF(Resources)); + addBuffer(convertResToCOFF(Resources), false); if (Tar) Tar->append("response.txt", Index: COFF/Options.td =================================================================== --- COFF/Options.td +++ COFF/Options.td @@ -96,6 +96,9 @@ defm safeseh : B<"safeseh", "Produce an image with Safe Exception Handler">; defm tsaware : B<"tsaware", "Create non-Terminal Server aware executable">; +def whole_archive : F<"whole-archive">; +def no_whole_archive : F<"no-whole-archive">; + def help : F<"help">; def help_q : Flag<["/?", "-?"], "">, Alias; Index: MinGW/Driver.cpp =================================================================== --- MinGW/Driver.cpp +++ MinGW/Driver.cpp @@ -169,11 +169,22 @@ for (auto *A : Args.filtered(OPT_L)) SearchPaths.push_back(A->getValue()); - for (auto *A : Args.filtered(OPT_INPUT, OPT_l)) { - if (A->getOption().getUnaliasedOption().getID() == OPT_INPUT) + for (auto *A : Args.filtered(OPT_INPUT, OPT_l, OPT_whole_archive, + OPT_no_whole_archive)) { + switch (A->getOption().getID()) { + case OPT_INPUT: Add(A->getValue()); - else + break; + case OPT_l: Add(searchLibrary(A->getValue(), SearchPaths, Args.hasArg(OPT_Bstatic))); + break; + case OPT_whole_archive: + Add("-whole-archive"); + break; + case OPT_no_whole_archive: + Add("-no-whole-archive"); + break; + } } if (Args.hasArg(OPT_verbose)) Index: MinGW/Options.td =================================================================== --- MinGW/Options.td +++ MinGW/Options.td @@ -9,6 +9,8 @@ def entry: S<"entry">, MetaVarName<"">, HelpText<"Name of entry point symbol">; def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; +def no_whole_archive: F<"no-whole-archive">, + HelpText<"No longer include all object files for following archives">; def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"">, HelpText<"Path to file to write output">; def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"">, @@ -17,6 +19,8 @@ def subs: Separate<["--"], "subsystem">, HelpText<"Specify subsystem">; def stack: Separate<["--"], "stack">; def outlib: Separate<["--"], "out-implib">, HelpText<"Import library name">; +def whole_archive: F<"whole-archive">, + HelpText<"Include all object files for following archives">; def verbose: F<"verbose">, HelpText<"Verbose mode">; // LLD specific options Index: test/MinGW/Inputs/export.yaml =================================================================== --- /dev/null +++ test/MinGW/Inputs/export.yaml @@ -0,0 +1,57 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: B800000000506800000000680000000050E80000000050E800000000 + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2f6578706f72743a6578706f7274666e3300 # /export:exportfn3 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 28 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: _DllMainCRTStartup + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn1 + Value: 8 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn2 + Value: 16 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportfn3 + Value: 16 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '?mangled@@YAHXZ' + Value: 16 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... Index: test/MinGW/whole-archive.test =================================================================== --- /dev/null +++ test/MinGW/whole-archive.test @@ -0,0 +1,15 @@ +# REQEUIRES: x86 + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.archive.obj +# RUN: llvm-ar rcs %t.archive.lib %t.archive.obj +# RUN: llvm-mc -triple=x86_64-windows-msvc %s -filetype=obj -o %t.main.obj +# RUN: ld.lld -m i386pep --shared --entry main %t.main.obj --whole-archive %t.archive.lib --no-whole-archive -o %t.dll --out-implib %t.lib +# RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB + +# CHECK-IMPLIB: Symbol: __imp_exportfn3 +# CHECK-IMPLIB: Symbol: exportfn3 + +.global main +.text +main: + ret