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

Nico Weber via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 7 12:10:28 PDT 2018


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
+...




More information about the llvm-commits mailing list