[COFF] Cope with weak aliases produced by GNU tools

When GNU tools create a weak alias, they produce a strong symbol
named .weak.<weaksymbol>.<relatedstrongsymbol>.

GNU ld allows many such weak alternatives for the same weak symbol, and
the linker picks the first one encountered.

This can't be reproduced by assembling from .s files, since llvm-mc
produces symbols named .weak.<weaksymbol>.default in these cases.

Differential Revision: https://reviews.llvm.org/D52601

git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@343704 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
index 3dd522b..7c83214 100644
--- a/COFF/InputFiles.cpp
+++ b/COFF/InputFiles.cpp
@@ -54,8 +54,16 @@
 static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F,
                                  Symbol *Source, Symbol *Target) {
   if (auto *U = dyn_cast<Undefined>(Source)) {
-    if (U->WeakAlias && U->WeakAlias != Target)
+    if (U->WeakAlias && U->WeakAlias != Target) {
+      // Weak aliases as produced by GCC are named in the form
+      // .weak.<weaksymbol>.<othersymbol>, where <othersymbol> is the name
+      // of another symbol emitted near the weak symbol.
+      // Just use the definition from the first object file that defined
+      // this weak symbol.
+      if (Config->MinGW)
+        return;
       Symtab->reportDuplicate(Source, F);
+    }
     U->WeakAlias = Target;
   }
 }
diff --git a/test/COFF/Inputs/gnu-weak.o b/test/COFF/Inputs/gnu-weak.o
new file mode 100644
index 0000000..997f004
--- /dev/null
+++ b/test/COFF/Inputs/gnu-weak.o
Binary files differ
diff --git a/test/COFF/Inputs/gnu-weak2.o b/test/COFF/Inputs/gnu-weak2.o
new file mode 100644
index 0000000..15b5d4d
--- /dev/null
+++ b/test/COFF/Inputs/gnu-weak2.o
Binary files differ
diff --git a/test/COFF/gnu-weak.test b/test/COFF/gnu-weak.test
new file mode 100644
index 0000000..20284d7
--- /dev/null
+++ b/test/COFF/gnu-weak.test
@@ -0,0 +1,52 @@
+RUN: lld-link -lldmingw %S/Inputs/gnu-weak.o %S/Inputs/gnu-weak2.o -out:%t.exe
+
+GNU ld can handle several definitions of the same weak symbol, and
+unless there is a strong definition of it, it just picks the first
+weak definition encountered.
+
+For each of the weak definitions, GNU tools produce a regular symbol
+named .weak.<weaksymbol>.<othersymbol>, where the other symbol name is
+another symbol defined close by.
+
+This can't be reproduced by assembling with llvm-mc, as llvm-mc always
+produces similar regular symbols named .weak.<weaksymbol>.default.
+
+The bundled object files can be produced from test code that looks like
+this:
+
+$ cat gnu-weak.c
+void weakfunc(void) __attribute__((weak));
+void otherfunc(void);
+
+__attribute__((weak)) void weakfunc() {
+}
+
+int main(int argc, char* argv[]) {
+    otherfunc();
+    weakfunc();
+    return 0;
+}
+void mainCRTStartup(void) {
+    main(0, (char**)0);
+}
+void __main(void) {
+}
+
+$ cat gnu-weak2.c
+void weakfunc(void) __attribute__((weak));
+
+__attribute__((weak)) void weakfunc() {
+}
+
+void otherfunc(void) {
+}
+
+$ x86_64-w64-mingw32-gcc -c -O2 gnu-weak.c
+$ x86_64-w64-mingw32-gcc -c -O2 gnu-weak2.c
+
+$ x86_64-w64-mingw32-nm gnu-weak.o | grep weakfunc
+0000000000000000 T .weak.weakfunc.main
+                 w weakfunc
+$ x86_64-w64-mingw32-nm gnu-weak2.o | grep weakfunc
+0000000000000000 T .weak.weakfunc.otherfunc
+                 w weakfunc