This is an archive of the discontinued LLVM Phabricator instance.

[LLD] [MinGW] Pass the undecorated entry point name to the COFF linker
ClosedPublic

Authored by mstorsjo on Sep 11 2017, 1:59 PM.

Diff Detail

Repository
rL LLVM

Event Timeline

mstorsjo created this revision.Sep 11 2017, 1:59 PM
ruiu edited edge metadata.Sep 11 2017, 2:09 PM

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?

martell accepted this revision.Sep 11 2017, 2:09 PM

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.

This revision is now accepted and ready to land.Sep 11 2017, 2:09 PM
In D37710#867043, @ruiu wrote:

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?

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
In D37710#867043, @ruiu wrote:

Can't you link your program without line 131-133?

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.

In D37710#867043, @ruiu wrote:

Can't you link your program without line 131-133?

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)

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.

GCC doesn't pass it when creating exe's but does when creating dll's - exactly what clang does.

ruiu accepted this revision.Sep 12 2017, 9:42 AM

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('_'))
mstorsjo added inline comments.Sep 12 2017, 12:24 PM
MinGW/Driver.cpp
131 ↗(On Diff #114683)

Thanks, will change and commit in that form.

This revision was automatically updated to reflect the committed changes.