[lld] r221499 - [PECOFF] Improve subsystem inference

Rui Ueyama ruiu at google.com
Thu Nov 6 15:50:48 PST 2014


Author: ruiu
Date: Thu Nov  6 17:50:48 2014
New Revision: 221499

URL: http://llvm.org/viewvc/llvm-project?rev=221499&view=rev
Log:
[PECOFF] Improve subsystem inference

If /subsystem option is not given, the linker needs to infer the
subsystem based on the entry point symbol. If it fails to infer
that, the linker should error out on it.

LLD was almost correct, but it would fail to infer the subsystem
if the entry point is specified with /entry. This is because the
subsystem inference was coupled with the entry point function
searching (if no entry point name is specified, the linker needs
to find the right entry name).

This patch makes the subsystem inference an independent pass to
fix the issue. Now, as long as an entry point function is defined,
LLD can infer the subsystem no matter how it resolved the entry
point.

I don't think scanning all the defined symbols is fast, although
it shouldn't be that slow. The file class there does not provide
any easy way to find an atom by name, so this is what we can do
at this moment. I'd like to revisit this later to make it more
efficient.

Added:
    lld/trunk/lib/ReaderWriter/PECOFF/InferSubsystemPass.h
Modified:
    lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
    lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
    lld/trunk/test/pecoff/alternatename.test

Added: lld/trunk/lib/ReaderWriter/PECOFF/InferSubsystemPass.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/InferSubsystemPass.h?rev=221499&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/InferSubsystemPass.h (added)
+++ lld/trunk/lib/ReaderWriter/PECOFF/InferSubsystemPass.h Thu Nov  6 17:50:48 2014
@@ -0,0 +1,66 @@
+//===- lib/ReaderWriter/PECOFF/InferSubsystemPass.h ----------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_PE_COFF_INFER_SUBSYSTEM_PASS_H
+#define LLD_READER_WRITER_PE_COFF_INFER_SUBSYSTEM_PASS_H
+
+#include "Atoms.h"
+#include "lld/Core/Pass.h"
+#include <vector>
+
+namespace lld {
+namespace pecoff {
+
+// Infers subsystem from entry point function name.
+class InferSubsystemPass : public lld::Pass {
+public:
+  InferSubsystemPass(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
+
+  void perform(std::unique_ptr<MutableFile> &file) override {
+    if (_ctx.getSubsystem() != WindowsSubsystem::IMAGE_SUBSYSTEM_UNKNOWN)
+      return;
+
+    if (_ctx.isDll()) {
+      _ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI);
+      return;
+    }
+
+    // Scan the resolved symbols to infer the subsystem.
+    const std::string wWinMain = _ctx.decorateSymbol("wWinMainCRTStartup");
+    const std::string wWinMainAt = _ctx.decorateSymbol("wWinMainCRTStartup@");
+    const std::string winMain = _ctx.decorateSymbol("WinMainCRTStartup");
+    const std::string winMainAt = _ctx.decorateSymbol("WinMainCRTStartup@");
+    const std::string wmain = _ctx.decorateSymbol("wmainCRTStartup");
+    const std::string wmainAt = _ctx.decorateSymbol("wmainCRTStartup@");
+    const std::string main = _ctx.decorateSymbol("mainCRTStartup");
+    const std::string mainAt = _ctx.decorateSymbol("mainCRTStartup@");
+
+    for (const DefinedAtom *atom : file->definedAtoms()) {
+      if (atom->name() == wWinMain || atom->name().startswith(wWinMainAt) ||
+          atom->name() == winMain || atom->name().startswith(winMainAt)) {
+        _ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI);
+        return;
+      }
+      if (atom->name() == wmain || atom->name().startswith(wmainAt) ||
+          atom->name() == main || atom->name().startswith(mainAt)) {
+        _ctx.setSubsystem(WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_CUI);
+        return;
+      }
+    }
+    llvm::report_fatal_error("Failed to infer subsystem");
+  }
+
+private:
+  PECOFFLinkingContext &_ctx;
+};
+
+} // namespace pecoff
+} // namespace lld
+
+#endif

Modified: lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h?rev=221499&r1=221498&r2=221499&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/LinkerGeneratedSymbolFile.h Thu Nov  6 17:50:48 2014
@@ -326,8 +326,7 @@ private:
     return _undefinedAtoms;
   }
 
-  // Returns the entry point function name. It also sets the inferred
-  // subsystem if it's unknown.
+  // Returns the entry point function name.
   std::string getEntry() const {
     StringRef opt = _ctx->getEntrySymbolName();
     if (!opt.empty()) {
@@ -344,11 +343,8 @@ private:
     const std::string WinMainCRTStartup = "WinMainCRTStartup";
     const std::string wmainCRTStartup = "wmainCRTStartup";
     const std::string mainCRTStartup = "mainCRTStartup";
-    auto windows = WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI;
-    auto console = WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_CUI;
 
     if (_ctx->isDll()) {
-      _ctx->setSubsystem(windows);
       if (_ctx->getMachineType() == llvm::COFF::IMAGE_FILE_MACHINE_I386)
         return "_DllMainCRTStartup at 12";
       return "_DllMainCRTStartup";
@@ -365,21 +361,14 @@ private:
 
     switch (_ctx->getSubsystem()) {
     case WindowsSubsystem::IMAGE_SUBSYSTEM_UNKNOWN: {
-      if (defined("wWinMain")) {
-        _ctx->setSubsystem(windows);
+      if (defined("wWinMain"))
         return wWinMainCRTStartup;
-      }
-      if (defined("WinMain")) {
-        _ctx->setSubsystem(windows);
+      if (defined("WinMain"))
         return WinMainCRTStartup;
-      }
-      if (defined("wmain")) {
-        _ctx->setSubsystem(console);
+      if (defined("wmain"))
         return wmainCRTStartup;
-      }
       if (!defined("main"))
         llvm::errs() << "Cannot infer subsystem; assuming /subsystem:console\n";
-      _ctx->setSubsystem(console);
       return mainCRTStartup;
     }
     case WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI:

Modified: lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp?rev=221499&r1=221498&r2=221499&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp Thu Nov  6 17:50:48 2014
@@ -11,6 +11,7 @@
 #include "EdataPass.h"
 #include "GroupedSectionsPass.h"
 #include "IdataPass.h"
+#include "InferSubsystemPass.h"
 #include "LinkerGeneratedSymbolFile.h"
 #include "LoadConfigPass.h"
 #include "lld/Core/PassManager.h"
@@ -287,6 +288,7 @@ void PECOFFLinkingContext::addPasses(Pas
   pm.add(std::unique_ptr<Pass>(new LayoutPass(registry())));
   pm.add(std::unique_ptr<Pass>(new pecoff::LoadConfigPass(*this)));
   pm.add(std::unique_ptr<Pass>(new pecoff::GroupedSectionsPass()));
+  pm.add(std::unique_ptr<Pass>(new pecoff::InferSubsystemPass(*this)));
 }
 
 } // end namespace lld

Modified: lld/trunk/test/pecoff/alternatename.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/pecoff/alternatename.test?rev=221499&r1=221498&r2=221499&view=diff
==============================================================================
--- lld/trunk/test/pecoff/alternatename.test (original)
+++ lld/trunk/test/pecoff/alternatename.test Thu Nov  6 17:50:48 2014
@@ -2,17 +2,19 @@
 # RUN: yaml2obj %p/Inputs/alternatename2.obj.yaml > %t2.obj
 # RUN: yaml2obj %p/Inputs/alternatename3.obj.yaml > %t3.obj
 #
-# RUN: lld -flavor link /force /out:%t1.exe /alternatename:_main=_foo -- %t1.obj
+# RUN: lld -flavor link /force /out:%t1.exe /alternatename:_main=_foo \
+# RUN:   /subsystem:console -- %t1.obj
 # RUN: llvm-objdump -d %t1.exe | FileCheck -check-prefix=CHECK1 %s
 #
-# RUN: lld -flavor link /force /out:%t2.exe /alternatename:_main=_foo  -- %t1.obj %t2.obj
+# RUN: lld -flavor link /force /out:%t2.exe /alternatename:_main=_foo \
+# RUN:   /subsystem:console -- %t1.obj %t2.obj
 # RUN: llvm-objdump -d %t2.exe | FileCheck -check-prefix=CHECK2 %s
 #
-# RUN: lld -flavor link /force /out:%t3.exe -- %t3.obj
+# RUN: lld -flavor link /force /out:%t3.exe /subsystem:console -- %t3.obj
 # RUN: llvm-objdump -d %t3.exe | FileCheck -check-prefix=CHECK3 %s
 #
 # RUN: lld -flavor link /force /out:%t4.exe /alternatename:_main=_foo \
-# RUN:   /alternatename:_xyz=_foo -- %t1.obj
+# RUN:   /alternatename:_xyz=_foo /subsystem:console -- %t1.obj
 # RUN: llvm-objdump -d %t4.exe | FileCheck -check-prefix=CHECK4 %s
 
 CHECK1:      nop





More information about the llvm-commits mailing list