[lld] r343877 - [COFF] Cope with GCC produced weak aliases referring to comdat functions

Martin Storsjo via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 5 12:43:16 PDT 2018


Author: mstorsjo
Date: Fri Oct  5 12:43:16 2018
New Revision: 343877

URL: http://llvm.org/viewvc/llvm-project?rev=343877&view=rev
Log:
[COFF] Cope with GCC produced weak aliases referring to comdat functions

For certain cases of inline functions written to comdat sections,
GCC 5.x produces a weak symbol in addition, which would end up
undefined in some cases.

This no longer seems to happen with GCC 6.x or newer though.

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

Added:
    lld/trunk/test/COFF/Inputs/inline-weak.o
    lld/trunk/test/COFF/Inputs/inline-weak2.o
    lld/trunk/test/COFF/comdat-weak.test
Modified:
    lld/trunk/COFF/InputFiles.cpp

Modified: lld/trunk/COFF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.cpp?rev=343877&r1=343876&r2=343877&view=diff
==============================================================================
--- lld/trunk/COFF/InputFiles.cpp (original)
+++ lld/trunk/COFF/InputFiles.cpp Fri Oct  5 12:43:16 2018
@@ -280,6 +280,13 @@ Symbol *ObjFile::createRegular(COFFSymbo
     COFFObj->getSymbolName(Sym, Name);
     if (SC)
       return Symtab->addRegular(this, Name, Sym.getGeneric(), SC);
+    // For MinGW symbols named .weak.* that point to a discarded section,
+    // don't create an Undefined symbol. If nothing ever refers to the symbol,
+    // everything should be fine. If something actually refers to the symbol
+    // (e.g. the undefined weak alias), linking will fail due to undefined
+    // references at the end.
+    if (Config->MinGW && Name.startswith(".weak."))
+      return nullptr;
     return Symtab->addUndefined(Name, this, false);
   }
   if (SC)

Added: lld/trunk/test/COFF/Inputs/inline-weak.o
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/inline-weak.o?rev=343877&view=auto
==============================================================================
Binary files lld/trunk/test/COFF/Inputs/inline-weak.o (added) and lld/trunk/test/COFF/Inputs/inline-weak.o Fri Oct  5 12:43:16 2018 differ

Added: lld/trunk/test/COFF/Inputs/inline-weak2.o
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/Inputs/inline-weak2.o?rev=343877&view=auto
==============================================================================
Binary files lld/trunk/test/COFF/Inputs/inline-weak2.o (added) and lld/trunk/test/COFF/Inputs/inline-weak2.o Fri Oct  5 12:43:16 2018 differ

Added: lld/trunk/test/COFF/comdat-weak.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/comdat-weak.test?rev=343877&view=auto
==============================================================================
--- lld/trunk/test/COFF/comdat-weak.test (added)
+++ lld/trunk/test/COFF/comdat-weak.test Fri Oct  5 12:43:16 2018
@@ -0,0 +1,82 @@
+RUN: lld-link -lldmingw %S/Inputs/inline-weak.o %S/Inputs/inline-weak2.o -out:%t.exe
+
+When compiling certain forms of templated inline functions, some
+versions of GCC (tested with 5.4) produces a weak symbol for the function.
+Newer versions of GCC don't do this though.
+
+The bundled object files are an example of that, they can be produced
+with test code like this:
+
+$ cat inline-weak.h
+class MyClass {
+public:
+    template<typename... _Args> int get(_Args&&... args) {
+        return a;
+    }
+private:
+    int a;
+};
+
+$ cat inline-weak.cpp
+#include "inline-weak.h"
+
+int get(MyClass& a);
+
+int main(int argc, char* argv[]) {
+    MyClass a;
+    int ret = a.get();
+    ret += get(a);
+    return ret;
+}
+extern "C" void mainCRTStartup(void) {
+    main(0, (char**)0);
+}
+extern "C" void __main(void) {
+}
+
+$ cat inline-weak2.cpp
+#include "inline-weak.h"
+
+int get(MyClass& a) {
+    return a.get();
+}
+
+$ x86_64-w64-mingw32-g++ -std=c++11 -c inline-weak.cpp
+$ x86_64-w64-mingw32-g++ -std=c++11 -c inline-weak2.cpp
+
+$ x86_64-w64-mingw32-nm inline-weak.o | grep MyClass3get
+0000000000000000 p .pdata$_ZN7MyClass3getIJEEEiDpOT_
+0000000000000000 t .text$_ZN7MyClass3getIJEEEiDpOT_
+0000000000000000 T .weak._ZN7MyClass3getIIEEEiDpOT_.main
+0000000000000000 r .xdata$_ZN7MyClass3getIJEEEiDpOT_
+                 w _ZN7MyClass3getIIEEEiDpOT_
+0000000000000000 T _ZN7MyClass3getIJEEEiDpOT_
+
+$ x86_64-w64-mingw32-nm inline-weak2.o | grep MyClass3get
+0000000000000000 p .pdata$_ZN7MyClass3getIJEEEiDpOT_
+0000000000000000 t .text$_ZN7MyClass3getIJEEEiDpOT_
+0000000000000000 T .weak._ZN7MyClass3getIIEEEiDpOT_._Z3getR7MyClass
+0000000000000000 r .xdata$_ZN7MyClass3getIJEEEiDpOT_
+                 w _ZN7MyClass3getIIEEEiDpOT_
+0000000000000000 T _ZN7MyClass3getIJEEEiDpOT_
+
+This can't be reproduced by assembling .s files with llvm-mc, since that
+always produces a symbol named .weak.<weaksymbol>.default, therefore
+the test uses prebuilt object files instead.
+
+In these cases, the undefined weak symbol points to the regular symbol
+.weak._ZN7MyClass3getIIEEEiDpOT_.<othersymbol>, where <othersymbol>
+varies among the object files that emit the same function. This regular
+symbol points to the same location as the comdat function
+_ZN7MyClass3getIJEEEiDpOT_.
+
+When linking, the comdat section from the second object file gets
+discarded, as it matches the one that already exists. This means that
+the uniquely named symbol .weak.<weakname>.<othername> points to a
+discarded section chunk.
+
+Previously, this would have triggered adding an Undefined symbol for
+this case, which would later break linking. However, also previously,
+if the second object file is linked in via a static library, this
+leftover symbol is retained as a Lazy symbol, which would make the link
+succeed.




More information about the llvm-commits mailing list