On i386, the --entry parameter to GNU ld is supposed to be a decorated symbol name, while it is an undecorated name in link.exe.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
lld COFF linker also does a trick for the leading underscore, so you may not need to handle that in the shim driver. Can't you link your program without line 131-133?
I know this was going to be an issue when I saw your other patch that had a line in the clang driver to add the underscore. :)
Technically this is incorrect but gcc and binutils do this so, for compatibility we should (same issue we had with llvm-dlltool)
LGTM.
There's lots of tricks back and forth for the leading underscore - the COFF linker unconditionally adds it here:
// Symbol names are mangled by appending "_" prefix on x86. StringRef LinkerDriver::mangle(StringRef Sym) { assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN); if (Config->Machine == I386) return Saver.save("_" + Sym); return Sym; } // Handle /entry and /dll if (auto *Arg = Args.getLastArg(OPT_entry)) { Config->Entry = addUndefined(mangle(Arg->getValue()));
We can't make this to work with heuristics because then you'll pick the wrong one when there's ambiguity.
I tested the behaviour in GNU ld and link.exe like this:
$ cat entry.c int puts(const char* str); int entry(void) { puts("entry no underscore"); return 0; } int _entry(void) { puts("entry single underscore"); return 0; } int __entry(void) { puts("entry double underscore"); return 0; } $ cl entry.c -c -Foentry-msvc.o Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x86 Copyright (C) Microsoft Corporation. All rights reserved. entry.c $ llvm-nm -g entry-msvc.o 00000040 T ___entry 00000020 T __entry 00000000 T _entry U _puts $ link entry-msvc.o -entry:entry -out:entry-link.exe -subsystem:console ucrt.lib $ wine entry-link.exe entry no underscore $ link entry-msvc.o -entry:_entry -out:entry-link.exe -subsystem:console ucrt.lib $ wine entry-link.exe entry single underscore $ i686-w64-mingw32-gcc -c entry.c -o entry-gcc.o $ i686-w64-mingw32-ld --entry entry entry-gcc.o -o entry-ld.exe -lmsvcrt i686-w64-mingw32-ld: warning: cannot find entry symbol entry; defaulting to 0000000000401000 $ i686-w64-mingw32-ld --entry _entry entry-gcc.o -o entry-ld.exe -lmsvcrt $ wine entry-ld.exe entry no underscore $ i686-w64-mingw32-ld --entry __entry entry-gcc.o -o entry-ld.exe -lmsvcrt $ wine entry-ld.exe entry single underscore
And to answer this part of the question... Normally the clang frontend doesn't pass the --entry option at all, so for a normal executable, things work as they are. However, when linking DLLs, the clang frontend passes this option, and things currently fail (for i386 DLLs).
To add to the confusion, the DLL entry point in MSVC is by default named _DllMainCRTStartup (which after i386 mangling ends up as __DllMainCRTStartup@12. In MinGW (and as in the defaults in the clang MinGW frontend), the DLL entry point is named DllMainCRTStartup which on i386 ends up as _DllMainCRTStartup@12.
Does gcc also pass the entry? If not then we should remove that from clang for consistency.
(Though that is unrelated to your point that --entry should work as it does on ld)
GCC doesn't pass it when creating exe's but does when creating dll's - exactly what clang does.
LGTM
MinGW/Driver.cpp | ||
---|---|---|
131 ↗ | (On Diff #114683) | A->getValue() could be an empty string if you specify -e '', so you want to guard against it. I'd do if (auto *A = Args.getLastArg(OPT_entry)) { StringRef S = A->getValue(); if (Args.getLastArgValue(OPT_m) == "i386pe" && S.startswith('_')) |
MinGW/Driver.cpp | ||
---|---|---|
131 ↗ | (On Diff #114683) | Thanks, will change and commit in that form. |