[lld] r339165 - lld-link: Take /SUBSYSTEM into account for automatic /ENTRY detection.

Hans Wennborg via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 30 01:26:53 PDT 2018


Merged this, along with r338877 and r338911, to 7.0 in r341035.

On Tue, Aug 7, 2018 at 9:10 PM, Nico Weber via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
> Author: nico
> Date: Tue Aug  7 12:10:28 2018
> New Revision: 339165
>
> URL: http://llvm.org/viewvc/llvm-project?rev=339165&view=rev
> Log:
> lld-link: Take /SUBSYSTEM into account for automatic /ENTRY detection.
>
> If /subsystem:windows is passed, link.exe only looks for WinMain and wWinMain,
> and if /subsystem:console is passed it only looks for main and wmain. lld-link
> used to look for all 4 in both cases. This patch makes lld-link match
> link.exe's behavior.
>
> This requires that the subsystem is known by the time findDefaultEntry() gets
> called. findDefaultEntry() is called before the main link loop, so that the
> loop can mark the entry point as undefined. That means inferSubsystem() has to
> be called above the main loop as well. This in turn means /subsystem: from
> .drectve sections only has an effect on entry point inference for obj files
> passed to lld-link directly (and not in obj files found later in .lib files).
> link.exe seems to ignore /subsystem: for obj files from lib files completely
> (while in lld it's ignored only for entry point detection but it still
> overrides /subsystem: flags passed on the command line for the value that gets
> written in the output file).
>
> Also, if the subsytem isn't needed (e.g. when only writing a /def: lib file and
> not writing a coff file), link.exe doesn't complain if the subsystem isn't
> known, so both subsystem and entry point handling should be below the early
> return lld has for that case.
>
> Fixes PR36523.
> https://reviews.llvm.org/D50316
>
> Added:
>     lld/trunk/test/COFF/entry-inference4.test
> Modified:
>     lld/trunk/COFF/Driver.cpp
>     lld/trunk/test/COFF/entry-inference3.test
>     lld/trunk/test/COFF/entry-inference332.test
>
> Modified: lld/trunk/COFF/Driver.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=339165&r1=339164&r2=339165&view=diff
> ==============================================================================
> --- lld/trunk/COFF/Driver.cpp (original)
> +++ lld/trunk/COFF/Driver.cpp Tue Aug  7 12:10:28 2018
> @@ -426,20 +426,23 @@ Symbol *LinkerDriver::addUndefined(Strin
>  // each of which corresponds to a user-defined "main" function. This function
>  // infers an entry point from a user-defined "main" function.
>  StringRef LinkerDriver::findDefaultEntry() {
> -  // User-defined main functions and their corresponding entry points.
> -  static const char *Entries[][2] = {
> -      {"main", "mainCRTStartup"},
> -      {"wmain", "wmainCRTStartup"},
> -      {"WinMain", "WinMainCRTStartup"},
> -      {"wWinMain", "wWinMainCRTStartup"},
> -  };
> -  for (auto E : Entries) {
> -    // As a special case, if /nodefaultlib is given, we directly look for an
> -    // entry point. This is because, if no default library is linked, users
> -    // need to define an entry point instead of a "main".
> -    if (findUnderscoreMangle(E[Config->NoDefaultLibAll]))
> -      return mangle(E[1]);
> -  }
> +  assert(Config->Subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&
> +         "must handle /subsystem before calling this");
> +
> +  // As a special case, if /nodefaultlib is given, we directly look for an
> +  // entry point. This is because, if no default library is linked, users
> +  // need to define an entry point instead of a "main".
> +  bool FindMain = !Config->NoDefaultLibAll;
> +  if (Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
> +    if (findUnderscoreMangle(FindMain ? "WinMain" : "WinMainCRTStartup"))
> +      return mangle("WinMainCRTStartup");
> +    if (findUnderscoreMangle(FindMain ? "wWinMain" : "wWinMainCRTStartup"))
> +      return mangle("wWinMainCRTStartup");
> +  }
> +  if (findUnderscoreMangle(FindMain ? "main" : "mainCRTStartup"))
> +    return mangle("mainCRTStartup");
> +  if (findUnderscoreMangle(FindMain ? "wmain" : "wmainCRTStartup"))
> +    return mangle("wmainCRTStartup");
>    return "";
>  }
>
> @@ -1204,25 +1207,6 @@ void LinkerDriver::link(ArrayRef<const c
>      error("/dynamicbase:no is not compatible with " +
>            machineToStr(Config->Machine));
>
> -  // Handle /entry and /dll
> -  if (auto *Arg = Args.getLastArg(OPT_entry)) {
> -    Config->Entry = addUndefined(mangle(Arg->getValue()));
> -  } else if (!Config->Entry && !Config->NoEntry) {
> -    if (Args.hasArg(OPT_dll)) {
> -      StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup at 12"
> -                                              : "_DllMainCRTStartup";
> -      Config->Entry = addUndefined(S);
> -    } else {
> -      // Windows specific -- If entry point name is not given, we need to
> -      // infer that from user-defined entry name.
> -      StringRef S = findDefaultEntry();
> -      if (S.empty())
> -        fatal("entry point must be defined");
> -      Config->Entry = addUndefined(S);
> -      log("Entry name inferred: " + S);
> -    }
> -  }
> -
>    // Handle /export
>    for (auto *Arg : Args.filtered(OPT_export)) {
>      Export E = parseExport(Arg->getValue());
> @@ -1248,6 +1232,34 @@ void LinkerDriver::link(ArrayRef<const c
>      return;
>    }
>
> +  // Windows specific -- if no /subsystem is given, we need to infer
> +  // that from entry point name.  Must happen before /entry handling,
> +  // and after the early return when just writing an import library.
> +  if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
> +    Config->Subsystem = inferSubsystem();
> +    if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
> +      fatal("subsystem must be defined");
> +  }
> +
> +  // Handle /entry and /dll
> +  if (auto *Arg = Args.getLastArg(OPT_entry)) {
> +    Config->Entry = addUndefined(mangle(Arg->getValue()));
> +  } else if (!Config->Entry && !Config->NoEntry) {
> +    if (Args.hasArg(OPT_dll)) {
> +      StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup at 12"
> +                                              : "_DllMainCRTStartup";
> +      Config->Entry = addUndefined(S);
> +    } else {
> +      // Windows specific -- If entry point name is not given, we need to
> +      // infer that from user-defined entry name.
> +      StringRef S = findDefaultEntry();
> +      if (S.empty())
> +        fatal("entry point must be defined");
> +      Config->Entry = addUndefined(S);
> +      log("Entry name inferred: " + S);
> +    }
> +  }
> +
>    // Handle /delayload
>    for (auto *Arg : Args.filtered(OPT_delayload)) {
>      Config->DelayLoads.insert(StringRef(Arg->getValue()).lower());
> @@ -1353,14 +1365,6 @@ void LinkerDriver::link(ArrayRef<const c
>    if (errorCount())
>      return;
>
> -  // Windows specific -- if no /subsystem is given, we need to infer
> -  // that from entry point name.
> -  if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
> -    Config->Subsystem = inferSubsystem();
> -    if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
> -      fatal("subsystem must be defined");
> -  }
> -
>    // Handle /safeseh.
>    if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) {
>      for (ObjFile *File : ObjFile::Instances)
>
> Modified: lld/trunk/test/COFF/entry-inference3.test
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/entry-inference3.test?rev=339165&r1=339164&r2=339165&view=diff
> ==============================================================================
> --- lld/trunk/test/COFF/entry-inference3.test (original)
> +++ lld/trunk/test/COFF/entry-inference3.test Tue Aug  7 12:10:28 2018
> @@ -1,9 +1,9 @@
>  # RUN: sed -e s/ENTRYNAME/mainCRTStartup/ %s | yaml2obj > %t.obj
> -# RUN: not lld-link /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
> +# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
>  # RUN: FileCheck %s < %t.log
>
>  # RUN: sed -e s/ENTRYNAME/?mainCRTStartup@@YAHXZ/ %s | yaml2obj > %t.obj
> -# RUN: not lld-link /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
> +# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
>  # RUN: FileCheck %s < %t.log
>
>  # CHECK: Entry name inferred: mainCRTStartup
>
> Modified: lld/trunk/test/COFF/entry-inference332.test
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/entry-inference332.test?rev=339165&r1=339164&r2=339165&view=diff
> ==============================================================================
> --- lld/trunk/test/COFF/entry-inference332.test (original)
> +++ lld/trunk/test/COFF/entry-inference332.test Tue Aug  7 12:10:28 2018
> @@ -1,9 +1,9 @@
>  # RUN: sed -e s/ENTRYNAME/_mainCRTStartup/ %s | yaml2obj > %t.obj
> -# RUN: not lld-link /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
> +# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
>  # RUN: FileCheck %s < %t.log
>
>  # RUN: sed -e s/ENTRYNAME/?mainCRTStartup@@YAHXZ/ %s | yaml2obj > %t.obj
> -# RUN: not lld-link /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
> +# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
>  # RUN: FileCheck %s < %t.log
>
>  # CHECK: Entry name inferred: _mainCRTStartup
>
> Added: lld/trunk/test/COFF/entry-inference4.test
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/entry-inference4.test?rev=339165&view=auto
> ==============================================================================
> --- lld/trunk/test/COFF/entry-inference4.test (added)
> +++ lld/trunk/test/COFF/entry-inference4.test Tue Aug  7 12:10:28 2018
> @@ -0,0 +1,56 @@
> +# RUN: sed 's/ENTRY1/WinMain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj
> +# RUN: not lld-link /subsystem:windows /out:%t.exe %t.obj > %t.log 2>&1
> +# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log
> +
> +# RUN: sed 's/ENTRY1/wWinMain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj
> +# RUN: not lld-link /subsystem:windows /out:%t.exe %t.obj > %t.log 2>&1
> +# RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log
> +
> +# RUN: sed 's/ENTRY1/WinMain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj
> +# RUN: not lld-link /subsystem:console /out:%t.exe %t.obj > %t.log 2>&1
> +# RUN: FileCheck -check-prefix=MAIN %s < %t.log
> +
> +# RUN: sed 's/ENTRY1/WinMain/;s/ENTRY2/wmain/' %s | yaml2obj > %t.obj
> +# RUN: not lld-link /subsystem:console /out:%t.exe %t.obj > %t.log 2>&1
> +# RUN: FileCheck -check-prefix=WMAIN %s < %t.log
> +
> +# MAIN:     error: <root>: undefined symbol: mainCRTStartup
> +# WMAIN:    error: <root>: undefined symbol: wmainCRTStartup
> +# WINMAIN:  error: <root>: undefined symbol: WinMainCRTStartup
> +# WWINMAIN: error: <root>: undefined symbol: wWinMainCRTStartup
> +
> +--- !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:     B82A000000C3
> +symbols:
> +  - Name:            .text
> +    Value:           0
> +    SectionNumber:   1
> +    SimpleType:      IMAGE_SYM_TYPE_NULL
> +    ComplexType:     IMAGE_SYM_DTYPE_NULL
> +    StorageClass:    IMAGE_SYM_CLASS_STATIC
> +    SectionDefinition:
> +      Length:          6
> +      NumberOfRelocations: 0
> +      NumberOfLinenumbers: 0
> +      CheckSum:        0
> +      Number:          0
> +  - Name:            ENTRY1
> +    Value:           0
> +    SectionNumber:   1
> +    SimpleType:      IMAGE_SYM_TYPE_NULL
> +    ComplexType:     IMAGE_SYM_DTYPE_NULL
> +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
> +  - Name:            ENTRY2
> +    Value:           0
> +    SectionNumber:   1
> +    SimpleType:      IMAGE_SYM_TYPE_NULL
> +    ComplexType:     IMAGE_SYM_DTYPE_NULL
> +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
> +...
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list