From d37782627772fe13927baa282276c0af591f2b75 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 3 Oct 2018 17:01:39 +0000 Subject: [PATCH] lld-link: Several tweaks to default entry point selection. Three related changes: 1. link.exe uses the presence of main and wmain to decide if it should call mainCRTStartup or wmainCRTStartup, even if /nodefaultlib is passed. For compatibility, remove FindMain logic. 2. Default to the non-wide entrypoint if main is not found. This has two effects: 2a. In normal links, lld-link now prints lld-link: error: undefined symbol: _main >>> referenced by f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:78 >>> libcmt.lib(exe_main.obj):("int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)) >>> referenced by f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:283 >>> libcmt.lib(exe_main.obj):("int __cdecl __scrt_common_main_seh(void)" (?__scrt_common_main_seh@@YAHXZ)) instead of lld-link: error: entry point must be defined This is arguably a better error message, since it now mentions that _main is missing. (This matches link.exe's diagnostic in this case.) 2b. With /nodefautlib, we now default to mainCRTStartup if no main() is present, again matching link.exe. This makes r337407 obsolete. This means if you have a cc file containing both mainCRTStartup and wmainCRTStartup and you pass /nodefaultlib /subsystem:console, lld-link will now call mainCRTStartup, matching link.exe 3. Print a warning if both main and wmain are present, similar to link.exe's LNK4067. Differential Revision: https://reviews.llvm.org/D52832 llvm-svn: 343698 --- lld/COFF/Driver.cpp | 30 ++++++++++++++++-------------- lld/test/COFF/entry-inference.test | 8 ++++++++ lld/test/COFF/entry-inference4.test | 20 ++++++++++++++++---- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 15ed19b..290e1fd 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -430,26 +430,28 @@ StringRef LinkerDriver::findDefaultEntry() { 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 ""; + if (findUnderscoreMangle("wWinMain")) { + if (!findUnderscoreMangle("WinMain")) + return mangle("wWinMainCRTStartup"); + warn("found both wWinMain and WinMain; using latter"); + } + return mangle("WinMainCRTStartup"); + } + if (findUnderscoreMangle("wmain")) { + if (!findUnderscoreMangle("main")) + return mangle("wmainCRTStartup"); + warn("found both wmain and main; using latter"); + } + return mangle("mainCRTStartup"); } WindowsSubsystem LinkerDriver::inferSubsystem() { if (Config->DLL) return IMAGE_SUBSYSTEM_WINDOWS_GUI; + // Note that link.exe infers the subsystem from the presence of these + // functions even if /entry: or /nodefaultlib are passed which causes them + // to not be called. bool HaveMain = findUnderscoreMangle("main"); bool HaveWMain = findUnderscoreMangle("wmain"); bool HaveWinMain = findUnderscoreMangle("WinMain"); diff --git a/lld/test/COFF/entry-inference.test b/lld/test/COFF/entry-inference.test index 294870b..b58a23a 100644 --- a/lld/test/COFF/entry-inference.test +++ b/lld/test/COFF/entry-inference.test @@ -1,18 +1,26 @@ # RUN: sed -e s/ENTRYNAME/main/ %s | yaml2obj > %t.obj # RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1 # RUN: FileCheck -check-prefix=MAIN %s < %t.log +# RUN: not lld-link /nodefaultlib /out:%t.exe %t.obj > %t.log 2>&1 +# RUN: FileCheck -check-prefix=MAIN %s < %t.log # RUN: sed s/ENTRYNAME/wmain/ %s | yaml2obj > %t.obj # RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1 # RUN: FileCheck -check-prefix=WMAIN %s < %t.log +# RUN: not lld-link /nodefaultlib /out:%t.exe %t.obj > %t.log 2>&1 +# RUN: FileCheck -check-prefix=WMAIN %s < %t.log # RUN: sed s/ENTRYNAME/WinMain/ %s | yaml2obj > %t.obj # RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1 # RUN: FileCheck -check-prefix=WINMAIN %s < %t.log +# RUN: not lld-link /nodefaultlib /out:%t.exe %t.obj > %t.log 2>&1 +# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log # RUN: sed s/ENTRYNAME/wWinMain/ %s | yaml2obj > %t.obj # RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1 # RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log +# RUN: not lld-link /nodefaultlib /out:%t.exe %t.obj > %t.log 2>&1 +# RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log # MAIN: error: : undefined symbol: mainCRTStartup # WMAIN: error: : undefined symbol: wmainCRTStartup diff --git a/lld/test/COFF/entry-inference4.test b/lld/test/COFF/entry-inference4.test index 513c9cf..6b6a581 100644 --- a/lld/test/COFF/entry-inference4.test +++ b/lld/test/COFF/entry-inference4.test @@ -14,10 +14,22 @@ # 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: : undefined symbol: mainCRTStartup -# WMAIN: error: : undefined symbol: wmainCRTStartup -# WINMAIN: error: : undefined symbol: WinMainCRTStartup -# WWINMAIN: error: : undefined symbol: wWinMainCRTStartup +# RUN: sed 's/ENTRY1/wmain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj +# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1 +# RUN: FileCheck -check-prefix=MAINWMAIN %s < %t.log + +# RUN: sed 's/ENTRY1/wWinMain/;s/ENTRY2/WinMain/' %s | yaml2obj > %t.obj +# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1 +# RUN: FileCheck -check-prefix=WINMAINWWINMAIN %s < %t.log + +# MAIN: error: : undefined symbol: mainCRTStartup +# WMAIN: error: : undefined symbol: wmainCRTStartup +# MAINWMAIN: warning: found both wmain and main; using latter +# MAINWMAIN: error: : undefined symbol: mainCRTStartup +# WINMAIN: error: : undefined symbol: WinMainCRTStartup +# WWINMAIN: error: : undefined symbol: wWinMainCRTStartup +# WINMAINWWINMAIN: warning: found both wWinMain and WinMain; using latter +# WINMAINWWINMAIN: error: : undefined symbol: WinMainCRTStartup --- !COFF header: -- 2.7.4