diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -235,6 +235,8 @@ bool swaprunNet = false; bool thinLTOEmitImportsFiles; bool thinLTOIndexOnly; + bool autoImport = false; + bool pseudoRelocs = false; }; extern Configuration *config; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1580,6 +1580,10 @@ config->debugDwarf = debug == DebugKind::Dwarf; config->debugGHashes = debug == DebugKind::GHash; config->debugSymtab = debug == DebugKind::Symtab; + config->autoImport = + args.hasFlag(OPT_auto_import, OPT_auto_import_no, config->mingw); + config->pseudoRelocs = args.hasFlag( + OPT_runtime_pseudo_reloc, OPT_runtime_pseudo_reloc_no, config->mingw); // Don't warn about long section names, such as .debug_info, for mingw or when // -debug:dwarf is requested. @@ -1841,9 +1845,11 @@ // Needed for MSVC 2017 15.5 CRT. symtab->addAbsolute(mangle("__enclave_config"), 0); - if (config->mingw) { + if (config->pseudoRelocs) { symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0); symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0); + } + if (config->mingw) { symtab->addAbsolute(mangle("__CTOR_LIST__"), 0); symtab->addAbsolute(mangle("__DTOR_LIST__"), 0); } @@ -1901,7 +1907,8 @@ while (run()); } - if (config->mingw) { + if (config->autoImport) { + // MinGW specific. // Load any further object files that might be needed for doing automatic // imports. // diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -16,6 +16,13 @@ def _no : F, HelpText; } +// Same as B<> above, but without help texts, for private undocumented +// options. +multiclass B_priv { + def "" : F; + def _no : F; +} + def align : P<"align", "Section alignment">; def aligncomm : P<"aligncomm", "Set common symbol alignment">; def alternatename : P<"alternatename", "Define weak alias">; @@ -184,6 +191,8 @@ def help_q : Flag<["/??", "-??", "/?", "-?"], "">, Alias; // LLD extensions +defm auto_import : B_priv<"auto-import">; +defm runtime_pseudo_reloc : B_priv<"runtime-pseudo-reloc">; def end_lib : F<"end-lib">, HelpText<"Ends group of objects treated as if they were in a library">; def exclude_all_symbols : F<"exclude-all-symbols">; diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -438,7 +438,7 @@ if (name.contains("_PchSym_")) continue; - if (config->mingw && handleMinGWAutomaticImport(sym, name)) + if (config->autoImport && handleMinGWAutomaticImport(sym, name)) continue; // Remaining undefined symbols are not fatal if /force is specified. diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -969,11 +969,11 @@ if (config->guardCF != GuardCFLevel::Off) createGuardCFTables(); - if (config->mingw) { + if (config->autoImport) createRuntimePseudoRelocs(); + if (config->mingw) insertCtorDtorSymbols(); - } } // Create .idata section for the DLL-imported symbol table. @@ -1722,6 +1722,15 @@ sc->getRuntimePseudoRelocs(rels); } + if (!config->pseudoRelocs) { + // Not writing any pseudo relocs; if some were needed, error out and + // indicate what required them. + for (const RuntimePseudoReloc &rpr : rels) + error("automatic dllimport of " + rpr.sym->getName() + " in " + + toString(rpr.target->file) + " requires pseudo relocations"); + return; + } + if (!rels.empty()) log("Writing " + Twine(rels.size()) + " runtime pseudo relocations"); PseudoRelocTableChunk *table = make(rels); diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp --- a/lld/MinGW/Driver.cpp +++ b/lld/MinGW/Driver.cpp @@ -295,6 +295,16 @@ else add("-opt:noref"); + if (args.hasFlag(OPT_enable_auto_import, OPT_disable_auto_import, true)) + add("-auto-import"); + else + add("-auto-import:no"); + if (args.hasFlag(OPT_enable_runtime_pseudo_reloc, + OPT_disable_runtime_pseudo_reloc, true)) + add("-runtime-pseudo-reloc"); + else + add("-runtime-pseudo-reloc:no"); + if (auto *a = args.getLastArg(OPT_icf)) { StringRef s = a->getValue(); if (s == "all") diff --git a/lld/MinGW/Options.td b/lld/MinGW/Options.td --- a/lld/MinGW/Options.td +++ b/lld/MinGW/Options.td @@ -20,7 +20,15 @@ HelpText<"Add a directory to the library search path">; def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">; def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">; +def disable_auto_import: F<"disable-auto-import">, + HelpText<"Don't automatically import data symbols from other DLLs without dllimport">; +def disable_runtime_pseudo_reloc: F<"disable-runtime-pseudo-reloc">, + HelpText<"Don't do automatic imports that require runtime fixups">; def dynamicbase: F<"dynamicbase">, HelpText<"Enable ASLR">; +def enable_auto_import: F<"enable-auto-import">, + HelpText<"Automatically import data symbols from other DLLs where needed">; +def enable_runtime_pseudo_reloc: F<"enable-runtime-pseudo-reloc">, + HelpText<"Allow automatic imports that require runtime fixups">; defm entry: Eq<"entry", "Name of entry point symbol">, MetaVarName<"">; def exclude_all_symbols: F<"exclude-all-symbols">, HelpText<"Don't automatically export any symbols">; @@ -94,7 +102,6 @@ def: F<"build-id">; def: F<"disable-auto-image-base">; def: F<"enable-auto-image-base">; -def: F<"enable-auto-import">, HelpText<"Ignored; listed for libtool compatibility">; def: F<"end-group">; def: Flag<["--"], "full-shutdown">; def: F<"high-entropy-va">; diff --git a/lld/test/COFF/autoimport-refptr.s b/lld/test/COFF/autoimport-refptr.s --- a/lld/test/COFF/autoimport-refptr.s +++ b/lld/test/COFF/autoimport-refptr.s @@ -4,13 +4,20 @@ # RUN: llvm-mc -triple=x86_64-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj # RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib -# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -defsym listptrs=1 -filetype=obj -o %t.obj # RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s # RUN: llvm-objdump -d %t.exe | FileCheck --check-prefix=DISASM %s # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=CONTENTS %s +## Check that we can autoimport these variables with pseudo relocs disabled. +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -defsym listptrs=0 -filetype=obj -o %t.noptrs.obj +# RUN: lld-link -lldmingw -runtime-pseudo-reloc:no -out:%t.exe -entry:main %t.noptrs.obj %t-lib.lib + +## Check that we can't autoimport them with autoimport disabled. +# RUN: not lld-link -lldmingw -auto-import:no -out:%t.exe -entry:main %t.noptrs.obj %t-lib.lib 2>&1 | FileCheck --check-prefix=NO-AUTOIMPORT %s + # IMPORTS: Import { # IMPORTS-NEXT: Name: autoimport-refptr.s.tmp-lib.dll # IMPORTS-NEXT: ImportLookupTableRVA: 0x2050 @@ -36,6 +43,8 @@ # CONTENTS: 140003000 08200040 01000000 08200040 01000000 # CONTENTS: 140003010 2a000000 +# NO-AUTOIMPORT: error: undefined symbol: variable + .global main .global localvar .text @@ -47,9 +56,11 @@ ret .data +.if listptrs==1 relocs: .quad __RUNTIME_PSEUDO_RELOC_LIST__ .quad __RUNTIME_PSEUDO_RELOC_LIST_END__ +.endif localvar: .int 42 diff --git a/lld/test/COFF/autoimport-x86.s b/lld/test/COFF/autoimport-x86.s --- a/lld/test/COFF/autoimport-x86.s +++ b/lld/test/COFF/autoimport-x86.s @@ -4,9 +4,12 @@ # RUN: llvm-mc -triple=x86_64-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj # RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib -# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj +# RUN: llvm-mc -triple=x86_64-windows-gnu -defsym listptrs=1 %s -filetype=obj -o %t.obj # RUN: lld-link -lldmingw -debug:symtab -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose +# RUN: llvm-mc -triple=x86_64-windows-gnu -defsym listptrs=0 %s -filetype=obj -o %t.noptrs.obj +# RUN: not lld-link -lldmingw -runtime-pseudo-reloc:no -debug:symtab -out:%t.exe -entry:main %t.noptrs.obj %t-lib.lib 2>&1 | FileCheck --check-prefix=DISABLED %s + # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s # RUN: llvm-objdump -d %t.exe | FileCheck --check-prefix=DISASM %s # RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=CONTENTS %s @@ -46,6 +49,8 @@ # the symbol table. # SYMBOLS-NOT: variable +# DISABLED: error: automatic dllimport of variable in {{.*}}/autoimport-x86.s.tmp.noptrs.obj requires pseudo relocations + .global main .text main: @@ -54,6 +59,8 @@ .data ptr: .quad variable +.if listptrs==1 relocs: .quad __RUNTIME_PSEUDO_RELOC_LIST__ .quad __RUNTIME_PSEUDO_RELOC_LIST_END__ +.endif diff --git a/lld/test/MinGW/driver.test b/lld/test/MinGW/driver.test --- a/lld/test/MinGW/driver.test +++ b/lld/test/MinGW/driver.test @@ -223,3 +223,21 @@ RUN: not ld.lld -m i386pep 2>&1 | FileCheck -check-prefix NO_INPUT_FILES %s NO_INPUT_FILES: error: no input files + +RUN: ld.lld -### -m i386pep foo.o | FileCheck -check-prefix ENABLE_AUTO_IMPORT %s +RUN: ld.lld -### -m i386pep foo.o --disable-auto-import --enable-auto-import | FileCheck -check-prefix ENABLE_AUTO_IMPORT %s +RUN: ld.lld -### -m i386pep foo.o -enable-auto-import | FileCheck -check-prefix ENABLE_AUTO_IMPORT %s +ENABLE_AUTO_IMPORT: -auto-import{{ }} + +RUN: ld.lld -### -m i386pep foo.o --disable-auto-import | FileCheck -check-prefix DISABLE_AUTO_IMPORT %s +RUN: ld.lld -### -m i386pep foo.o -disable-auto-import | FileCheck -check-prefix DISABLE_AUTO_IMPORT %s +DISABLE_AUTO_IMPORT: -auto-import:no + +RUN: ld.lld -### -m i386pep foo.o | FileCheck -check-prefix ENABLE_RUNTIME_PSEUDO_RELOC %s +RUN: ld.lld -### -m i386pep foo.o --disable-runtime-pseudo-reloc --enable-runtime-pseudo-reloc | FileCheck -check-prefix ENABLE_RUNTIME_PSEUDO_RELOC %s +RUN: ld.lld -### -m i386pep foo.o -enable-runtime-pseudo-reloc | FileCheck -check-prefix ENABLE_RUNTIME_PSEUDO_RELOC %s +ENABLE_RUNTIME_PSEUDO_RELOC: -runtime-pseudo-reloc{{ }} + +RUN: ld.lld -### -m i386pep foo.o --disable-runtime-pseudo-reloc | FileCheck -check-prefix DISABLE_RUNTIME_PSEUDO_RELOC %s +RUN: ld.lld -### -m i386pep foo.o -disable-runtime-pseudo-reloc | FileCheck -check-prefix DISABLE_RUNTIME_PSEUDO_RELOC %s +DISABLE_RUNTIME_PSEUDO_RELOC: -runtime-pseudo-reloc:no