[PATCH] D51500: [MS ABI] Fix mangling incompatibility with dynamic initializer stubs.

Zachary Turner via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 30 11:52:41 PDT 2018


zturner created this revision.
zturner added reviewers: rnk, majnemer.
Herald added a subscriber: erik.pilkington.

Given this code:

  class Foo {
  public:
  
  public:
    Foo() = default;
    virtual ~Foo() = default;
  };
  
  class Bar : public Foo {
    static Bar Shared;
  
    Bar() = default;
  
  public:
  
    static Bar *get() { return &Shared; }
  
    int X = 0;
  };
  
  Bar Bar::Shared;
  
  int main(int argc, char **argv) {
    return Bar::get()->X;
  }

Compile and dump the dynamic initializer symbols with both clang-cl and cl.  You get the following:

  $ clang-cl /Z7 /EHsc /c foo.cpp && dumpbin /symbols foo.obj | grep __E
  052 00000000 SECT1  notype ()    Static       | ??__EShared at Bar@@0V1 at A@YAXXZ (??__EShared at Bar@@0V1 at A@YAXXZ)
  
  $ cl /Z7 /EHsc /c foo.cpp && dumpbin /symbols foo.obj | grep __E
  
  03B 00000000 SECT11 notype ()    Static       | ??__E?Shared at Bar@@0V1 at A@@YAXXZ (void __cdecl `dynamic initializer for 'private: static class Bar Bar::Shared''(void))

As we can see, clang-cl produces a different mangling which cannot be demangled by `undname`.  AFAICT, this was not done for compatibility with an old version, and is in fact just broken (I tested back to MSVC 2013).

It makes sense that they would put the `?` there, because it's a disambiguator between static data member and global.  Previously my demangling code was a little hacky right here because I thought there was no disambiguator.

After this patch, we can run the same clang-cl command again and undname can demangle our symbol name.

  $ clang-cl /Z7 /EHsc /c foo.cpp && dumpbin /symbols foo.obj | grep __E
  052 00000000 SECT1  notype ()    Static       | ??__E?Shared at Bar@@0V1 at A@@YAXXZ (void __cdecl `dynamic initializer for 'private: static class Bar Bar::Shared''(void))


https://reviews.llvm.org/D51500

Files:
  clang/lib/AST/MicrosoftMangle.cpp
  clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
  clang/test/CodeGenCXX/pragma-init_seg.cpp


Index: clang/test/CodeGenCXX/pragma-init_seg.cpp
===================================================================
--- clang/test/CodeGenCXX/pragma-init_seg.cpp
+++ clang/test/CodeGenCXX/pragma-init_seg.cpp
@@ -44,15 +44,15 @@
 template <typename T> const int A<T>::x = f();
 template struct A<int>;
 // CHECK: @"?x@?$A at H@explicit_template_instantiation@@2HB" = weak_odr dso_local global i32 0, comdat, align 4
-// CHECK: @__cxx_init_fn_ptr.4 = private constant void ()* @"??__Ex@?$A at H@explicit_template_instantiation@@2HB at YAXXZ", section ".asdf", comdat($"?x@?$A at H@explicit_template_instantiation@@2HB")
+// CHECK: @__cxx_init_fn_ptr.4 = private constant void ()* @"??__E?x@?$A at H@explicit_template_instantiation@@2HB@@YAXXZ", section ".asdf", comdat($"?x@?$A at H@explicit_template_instantiation@@2HB")
 }
 
 namespace implicit_template_instantiation {
 template <typename T> struct A { static const int x; };
 template <typename T> const int A<T>::x = f();
 int g() { return A<int>::x; }
 // CHECK: @"?x@?$A at H@implicit_template_instantiation@@2HB" = linkonce_odr dso_local global i32 0, comdat, align 4
-// CHECK: @__cxx_init_fn_ptr.5 = private constant void ()* @"??__Ex@?$A at H@implicit_template_instantiation@@2HB at YAXXZ", section ".asdf", comdat($"?x@?$A at H@implicit_template_instantiation@@2HB")
+// CHECK: @__cxx_init_fn_ptr.5 = private constant void ()* @"??__E?x@?$A at H@implicit_template_instantiation@@2HB@@YAXXZ", section ".asdf", comdat($"?x@?$A at H@implicit_template_instantiation@@2HB")
 }
 
 // ... and here's where we emitted user level ctors.
Index: clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
===================================================================
--- clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
+++ clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
@@ -3,8 +3,8 @@
 // CHECK: @llvm.global_ctors = appending global [5 x { i32, void ()*, i8* }] [
 // CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__Eselectany1@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?selectany1@@3US@@A", i32 0, i32 0) },
 // CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__Eselectany2@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?selectany2@@3US@@A", i32 0, i32 0) },
-// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__Es@?$ExportedTemplate at H@@2US@@A at YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate at H@@2US@@A", i32 0, i32 0) },
-// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__Efoo@?$B at H@@2VA@@A at YAXXZ", i8* bitcast (%class.A* @"?foo@?$B at H@@2VA@@A" to i8*) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?s@?$ExportedTemplate at H@@2US@@A@@YAXXZ", i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate at H@@2US@@A", i32 0, i32 0) },
+// CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @"??__E?foo@?$B at H@@2VA@@A@@YAXXZ", i8* bitcast (%class.A* @"?foo@?$B at H@@2VA@@A" to i8*) },
 // CHECK: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_microsoft_abi_static_initializers.cpp, i8* null }
 // CHECK: ]
 
@@ -231,18 +231,18 @@
   DynamicDLLImportInitVSMangling::switch_test3();
 }
 
-// CHECK: define linkonce_odr dso_local void @"??__Efoo@?$B at H@@2VA@@A at YAXXZ"() {{.*}} comdat
+// CHECK: define linkonce_odr dso_local void @"??__E?foo@?$B at H@@2VA@@A@@YAXXZ"() {{.*}} comdat
 // CHECK-NOT: and
 // CHECK-NOT: ?_Bfoo@
 // CHECK: call x86_thiscallcc %class.A* @"??0A@@QAE at XZ"
-// CHECK: call i32 @atexit(void ()* @"??__Ffoo@?$B at H@@2VA@@A at YAXXZ")
+// CHECK: call i32 @atexit(void ()* @"??__F?foo@?$B at H@@2VA@@A@@YAXXZ")
 // CHECK: ret void
 
 // CHECK: define linkonce_odr dso_local x86_thiscallcc %class.A* @"??0A@@QAE at XZ"({{.*}}) {{.*}} comdat
 
 // CHECK: define linkonce_odr dso_local x86_thiscallcc void @"??1A@@QAE at XZ"({{.*}}) {{.*}} comdat
 
-// CHECK: define internal void @"??__Ffoo@?$B at H@@2VA@@A at YAXXZ"
+// CHECK: define internal void @"??__F?foo@?$B at H@@2VA@@A@@YAXXZ"
 // CHECK: call x86_thiscallcc void @"??1A@@QAE at XZ"{{.*}}foo
 // CHECK: ret void
 
Index: clang/lib/AST/MicrosoftMangle.cpp
===================================================================
--- clang/lib/AST/MicrosoftMangle.cpp
+++ clang/lib/AST/MicrosoftMangle.cpp
@@ -3217,10 +3217,13 @@
   msvc_hashing_ostream MHO(Out);
   MicrosoftCXXNameMangler Mangler(*this, MHO);
   Mangler.getStream() << "??__" << CharCode;
-  Mangler.mangleName(D);
   if (D->isStaticDataMember()) {
+    Mangler.getStream() << '?';
+    Mangler.mangleName(D);
     Mangler.mangleVariableEncoding(D);
-    Mangler.getStream() << '@';
+    Mangler.getStream() << "@@";
+  } else {
+    Mangler.mangleName(D);
   }
   // This is the function class mangling.  These stubs are global, non-variadic,
   // cdecl functions that return void and take no args.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D51500.163386.patch
Type: text/x-patch
Size: 4801 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20180830/d4622ea4/attachment.bin>


More information about the llvm-commits mailing list