[x86/Linux] Fix IL_STUB_PInvoke with RetBuf (dotnet/coreclr#10144)
authorHanjoung Lee <waterets@gmail.com>
Thu, 16 Mar 2017 03:29:34 +0000 (12:29 +0900)
committerJan Kotas <jkotas@microsoft.com>
Thu, 16 Mar 2017 03:29:34 +0000 (20:29 -0700)
* [x86/Linux] Fix IL_STUB_PInvoke with RetBuf

Fix calling convention and IL_STUB_PInvoke for native functions
which was problematic for native functions that has
a RetBuf argument(struct size <= 8) on x86/Linux.

Fix dotnet/coreclr#10027

Commit migrated from https://github.com/dotnet/coreclr/commit/9422f47c5de802d877c08f9f5118471b375239b1

src/coreclr/src/vm/callingconvention.h
src/coreclr/src/vm/dllimport.cpp
src/coreclr/src/vm/i386/cgencpu.h
src/coreclr/src/vm/ilmarshalers.h

index c9a27c2..cde2ba4 100644 (file)
@@ -1701,6 +1701,17 @@ inline BOOL HasRetBuffArg(MetaSig * pSig)
     return argit.HasRetBuffArg();
 }
 
+#ifdef UNIX_X86_ABI
+// For UNIX_X86_ABI and unmanaged function, we always need RetBuf if the return type is VALUETYPE
+inline BOOL HasRetBuffArgUnmanagedFixup(MetaSig * pSig)
+{
+    WRAPPER_NO_CONTRACT;
+    // We cannot just pSig->GetReturnType() here since it will return ELEMENT_TYPE_VALUETYPE for enums
+    CorElementType type = pSig->GetRetTypeHandleThrowing().GetVerifierCorElementType();
+    return type == ELEMENT_TYPE_VALUETYPE;
+}
+#endif
+
 inline BOOL IsRetBuffPassedAsFirstArg()
 {
     WRAPPER_NO_CONTRACT;
index ba56831..c0a73e8 100644 (file)
@@ -3684,8 +3684,15 @@ static void CreateNDirectStubWorker(StubState*         pss,
         // return buffer in correct register.
         // The return structure secret arg comes first, however byvalue return is processed at
         // the end because it could be the HRESULT-swapped argument which always comes last.
+
+#ifdef UNIX_X86_ABI
+        // For functions with value type class, managed and unmanaged calling convention differ
+        fMarshalReturnValueFirst = HasRetBuffArgUnmanagedFixup(&msig);
+#else // UNIX_X86_ABI
         fMarshalReturnValueFirst = HasRetBuffArg(&msig);
-#endif
+#endif // UNIX_X86_ABI
+
+#endif // defined(_TARGET_X86_) || defined(_TARGET_ARM_)
 
     }
     
index ac23953..ff76d99 100644 (file)
@@ -483,10 +483,15 @@ inline BOOL IsUnmanagedValueTypeReturnedByRef(UINT sizeofvaluetype)
 {
     LIMITED_METHOD_CONTRACT;
 
+#ifndef UNIX_X86_ABI
     // odd-sized small structures are not 
     //  enregistered e.g. struct { char a,b,c; }
     return (sizeofvaluetype > 8) ||
         (sizeofvaluetype & (sizeofvaluetype - 1)); // check that the size is power of two
+#else
+    // For UNIX_X86_ABI, we always return the value type by reference regardless of its size
+    return true;
+#endif
 }
 
 #include <pshpack1.h>
index 7c7f9a6..5ac5e41 100644 (file)
@@ -607,12 +607,15 @@ public:
 
             // for X86 and AMD64-Windows we bash the return type from struct to U1, U2, U4 or U8
             // and use byrefNativeReturn for all other structs.
+            // for UNIX_X86_ABI, we always need a return buffer argument for any size of structs.
             switch (nativeSize)
             {
+#ifndef UNIX_X86_ABI
                 case 1: typ = ELEMENT_TYPE_U1; break;
                 case 2: typ = ELEMENT_TYPE_U2; break;
                 case 4: typ = ELEMENT_TYPE_U4; break;
                 case 8: typ = ELEMENT_TYPE_U8; break;
+#endif
                 default: byrefNativeReturn = true; break;
             }
 #endif