From c0838af754543a6a5aa8170e84e30b109a7c036b Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 25 Apr 2019 14:02:26 +0000 Subject: [PATCH] lld-link: Implement /swaprun: flag r191276 added this to old LLD, but it never made it to new LLD -- except that the flag was in Options.td, so it was silently ignored. I figured it should be easy to implement, so I did that instead of removing the flags from Options.td. I then discovered that link.exe also supports comma-separated lists of 'cd' and 'net', which made the parsing code a bit annoying. The Alias technique in Options.td is to get nice help output. Differential Revision: https://reviews.llvm.org/D61067 llvm-svn: 359192 --- lld/COFF/Config.h | 2 ++ lld/COFF/Driver.cpp | 2 ++ lld/COFF/Driver.h | 3 +++ lld/COFF/DriverUtils.cpp | 21 +++++++++++++++++++++ lld/COFF/Options.td | 8 ++++++-- lld/COFF/Writer.cpp | 4 ++++ lld/test/COFF/options.test | 40 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 78 insertions(+), 2 deletions(-) diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index b13ef3a7..ecd579f 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -205,6 +205,8 @@ struct Configuration { bool IntegrityCheck = false; bool KillAt = false; bool Repro = false; + bool SwaprunCD = false; + bool SwaprunNet = false; }; extern Configuration *Config; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 96c9ba3..4c45ad9 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1375,6 +1375,8 @@ void LinkerDriver::link(ArrayRef ArgsArr) { Config->IntegrityCheck = Args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false); Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); + for (auto *Arg : Args.filtered(OPT_swaprun)) + parseSwaprun(Arg->getValue()); Config->TerminalServerAware = !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); Config->DebugDwarf = Debug == DebugKind::Dwarf; diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 02c8067..f9448bd 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -167,6 +167,9 @@ void parseManifest(StringRef Arg); // Parses a string in the form of "level=|uiAccess=" void parseManifestUAC(StringRef Arg); +// Parses a string in the form of "cd|net[,(cd|net)]*" +void parseSwaprun(StringRef Arg); + // Create a resource file containing a manifest XML. std::unique_ptr createManifestRes(); void createSideBySideManifest(); diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index a2f1008..ca3f878 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -315,6 +315,27 @@ void parseManifestUAC(StringRef Arg) { } } +// Parses a string in the form of "cd|net[,(cd|net)]*" +// Results are directly written to Config. +void parseSwaprun(StringRef Arg) { + do { + StringRef Swaprun, NewArg; + std::tie(Swaprun, NewArg) = Arg.split(','); + if (Swaprun.equals_lower("cd")) + Config->SwaprunCD = true; + else if (Swaprun.equals_lower("net")) + Config->SwaprunNet = true; + else if (Swaprun.empty()) + error("/swaprun: missing argument"); + else + error("/swaprun: invalid argument: " + Swaprun); + // To catch trailing commas, e.g. `/spawrun:cd,` + if (NewArg.empty() && Arg.endswith(",")) + error("/swaprun: missing argument"); + Arg = NewArg; + } while (!Arg.empty()); +} + // An RAII temporary file class that automatically removes a temporary file. namespace { class TemporaryFile { diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index 58b2dca..0013bb4 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -103,8 +103,12 @@ def noentry : F<"noentry">, def profile : F<"profile">; def repro : F<"Brepro">, HelpText<"Use a hash of the executable as the PE header timestamp">; -def swaprun_cd : F<"swaprun:cd">; -def swaprun_net : F<"swaprun:net">; +def swaprun : P<"swaprun", + "Comma-separated list of 'cd' or 'net'">; +def swaprun_cd : F<"swaprun:cd">, Alias, AliasArgs<["cd"]>, + HelpText<"Make loader run output binary from swap instead of from CD">; +def swaprun_net : F<"swaprun:net">, Alias, AliasArgs<["net"]>, + HelpText<"Make loader run output binary from swap instead of from network">; def verbose : F<"verbose">; def wholearchive_flag : F<"wholearchive">; diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index ff1363e..af2e423 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -1217,6 +1217,10 @@ template void Writer::writeHeader() { COFF->Characteristics |= IMAGE_FILE_DLL; if (!Config->Relocatable) COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; + if (Config->SwaprunCD) + COFF->Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; + if (Config->SwaprunNet) + COFF->Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP; COFF->SizeOfOptionalHeader = sizeof(PEHeaderTy) + sizeof(data_directory) * NumberOfDataDirectory; diff --git a/lld/test/COFF/options.test b/lld/test/COFF/options.test index 6b9f2ca..695e3d3 100644 --- a/lld/test/COFF/options.test +++ b/lld/test/COFF/options.test @@ -50,6 +50,46 @@ NXCOMPAT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NONXCOMPAT %s NONXCOMPAT-NOT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT +# RUN: lld-link /out:%t.exe /entry:main /swaprun:CD %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=SWAPCD %s +# RUN: lld-link /out:%t.exe /entry:main /swaprun:cd,net %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=SWAPCD %s +SWAPCD: IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP + +# RUN: lld-link /out:%t.exe /entry:main %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOSWAPCD %s +NOSWAPCD-NOT: IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP + +# RUN: lld-link /out:%t.exe /entry:main /swaprun:NeT %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=SWAPNET %s +# RUN: lld-link /out:%t.exe /entry:main /swaprun:net,cd,cd,net %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=SWAPNET %s +SWAPNET: IMAGE_FILE_NET_RUN_FROM_SWAP + +# RUN: lld-link /out:%t.exe /entry:main %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOSWAPNET %s +NOSWAPNET-NOT: IMAGE_FILE_NET_RUN_FROM_SWAP + +# RUN: not lld-link /out:%t.exe /entry:main /swaprun: %t.obj 2>&1 | \ +# RUN: FileCheck -check-prefix=SWAPERR1 %s +# RUN: not lld-link /out:%t.exe /entry:main /swaprun:cd, %t.obj 2>&1 | \ +# RUN: FileCheck -check-prefix=SWAPERR1 %s +# RUN: not lld-link /out:%t.exe /entry:main /swaprun:,, %t.obj 2>&1 | \ +# RUN: FileCheck -check-prefix=SWAPERR1 %s +# RUN: not lld-link /out:%t.exe /entry:main /swaprun:,cd %t.obj 2>&1 | \ +# RUN: FileCheck -check-prefix=SWAPERR1 %s +SWAPERR1: /swaprun: missing argument + +# RUN: not lld-link /out:%t.exe /entry:main /swaprun:foo %t.obj 2>&1 | \ +# RUN: FileCheck -check-prefix=SWAPERR2 %s +# RUN: not lld-link /out:%t.exe /entry:main /swaprun:cd,foo,net %t.obj 2>&1 | \ +# RUN: FileCheck -check-prefix=SWAPERR2 %s +SWAPERR2: /swaprun: invalid argument: foo + +# RUN: not lld-link /out:%t.exe /entry:main /swaprun:cdfoo,net %t.obj 2>&1 | \ +# RUN: FileCheck -check-prefix=SWAPERR3 %s +SWAPERR3: /swaprun: invalid argument: cdfoo + # RUN: lld-link /out:%t.exe /entry:main %t.obj # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=TSAWARE %s # RUN: lld-link /out:%t.exe /entry:main /tsaware %t.obj -- 2.7.4