diff options
author | Nico Weber <nicolasweber@gmx.de> | 2018-08-07 19:10:28 +0000 |
---|---|---|
committer | Nico Weber <nicolasweber@gmx.de> | 2018-08-07 19:10:28 +0000 |
commit | f4f5b7eea37926ba8bf9de31c9e9b5aa1e9c746c (patch) | |
tree | e3193d41eb3841ac4e9e3ed34bfbad417d3bb90c | |
parent | 3b2f6a4b29c92c4d4fafe4964ad164f600608f28 (diff) | |
download | bcm5719-llvm-f4f5b7eea37926ba8bf9de31c9e9b5aa1e9c746c.tar.gz bcm5719-llvm-f4f5b7eea37926ba8bf9de31c9e9b5aa1e9c746c.zip |
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
llvm-svn: 339165
-rw-r--r-- | lld/COFF/Driver.cpp | 84 | ||||
-rw-r--r-- | lld/test/COFF/entry-inference3.test | 4 | ||||
-rw-r--r-- | lld/test/COFF/entry-inference332.test | 4 | ||||
-rw-r--r-- | lld/test/COFF/entry-inference4.test | 56 |
4 files changed, 104 insertions, 44 deletions
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 22e7082023f..c21f0b4e3c9 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -426,20 +426,23 @@ Symbol *LinkerDriver::addUndefined(StringRef Name) { // 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 char *> ArgsArr) { 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@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 char *> ArgsArr) { 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@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 char *> ArgsArr) { 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) diff --git a/lld/test/COFF/entry-inference3.test b/lld/test/COFF/entry-inference3.test index b5ecef8c8d7..53550f75c6c 100644 --- a/lld/test/COFF/entry-inference3.test +++ b/lld/test/COFF/entry-inference3.test @@ -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 diff --git a/lld/test/COFF/entry-inference332.test b/lld/test/COFF/entry-inference332.test index 5ce31c6b58d..75c557af47e 100644 --- a/lld/test/COFF/entry-inference332.test +++ b/lld/test/COFF/entry-inference332.test @@ -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 diff --git a/lld/test/COFF/entry-inference4.test b/lld/test/COFF/entry-inference4.test new file mode 100644 index 00000000000..513c9cf8f86 --- /dev/null +++ b/lld/test/COFF/entry-inference4.test @@ -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 +... |