[RFC PATCH v2] vcruntime140: Add the new MSVC 2015 compiler specific DLL.

Martin Storsjo martin at martin.st
Tue Oct 20 03:45:46 CDT 2015


Since MSVC 2015/Windows 10, the C runtime has now been split into two
parts, ucrtbase, which is the generic C runtime which is now considered
a system component, and vcruntimeX which is specific to the compiler
version.

This DLL is built using only a small subset of the msvcrt source
files. In particular, the DLL should not use most of the global
CRT state as a normal msvcrt carries - the only TLS state handled
is for exceptions.

The functions in main.c are simplified versions of the corresponding
ones from msvcrt. Additionally, two stub functions (relating to telemetry)
are added; they are required for a plain empty exe built with MSVC 2015
with dynamic C runtime to start up with the builtin vcruntime140.dll.

Some functions that are available in the full msvcrt, that vcruntime140.dll
should export, are not included since they haven't been split off to be
buildable without the full internals of msvcrt yet. Those functions are:
_CxxThrowException
__AdjustPointer
__RTCastToVoid
__RTDynamicCast
__RTtypeid
_chkesp
_get_unexpected

Signed-off-by: Martin Storsjo <martin at martin.st>
---
Changed since last version: Moved main-vcruntime.c to the vcruntime140
directory; skipped the separate memory.c and included all of it in the
vcruntime main.c instead. Removed a leftover commented out statement.

In this build configuration, some functions use simpler error handling
- instead of calling _amsg_exit, it calls ExitProcess directly.
(_amsg_exit checks the error mode, which is state that lives within
ucrtbase.dll; vcruntime140.dll shouldn't have a separate copy of that
state, and there's no function in ucrtbase.dll that would allow quering it.)
---
 configure.ac                        |   1 +
 dlls/msvcrt/except.c                |   4 +
 dlls/msvcrt/except_i386.c           |   4 +
 dlls/vcruntime140/Makefile.in       |  12 ++
 dlls/vcruntime140/main.c            | 224 ++++++++++++++++++++++++++++++++++++
 dlls/vcruntime140/vcruntime140.spec |  87 ++++++++++++++
 6 files changed, 332 insertions(+)
 create mode 100644 dlls/vcruntime140/Makefile.in
 create mode 100644 dlls/vcruntime140/main.c
 create mode 100644 dlls/vcruntime140/vcruntime140.spec

diff --git a/configure.ac b/configure.ac
index de8cde5..c74ff18 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3364,6 +3364,7 @@ WINE_CONFIG_DLL(vcomp100)
 WINE_CONFIG_DLL(vcomp110)
 WINE_CONFIG_DLL(vcomp120)
 WINE_CONFIG_DLL(vcomp90)
+WINE_CONFIG_DLL(vcruntime140)
 WINE_CONFIG_DLL(vdhcp.vxd,enable_win16)
 WINE_CONFIG_DLL(vdmdbg,,[implib])
 WINE_CONFIG_DLL(ver.dll16,enable_win16)
diff --git a/dlls/msvcrt/except.c b/dlls/msvcrt/except.c
index f5c8b03..62dcf81 100644
--- a/dlls/msvcrt/except.c
+++ b/dlls/msvcrt/except.c
@@ -39,6 +39,10 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(seh);
 
+#ifdef VCRUNTIME
+#define MSVCRT__exit _exit
+#endif
+
 static MSVCRT_security_error_handler security_error_handler;
 
 static MSVCRT___sighandler_t sighandlers[MSVCRT_NSIG] = { MSVCRT_SIG_DFL };
diff --git a/dlls/msvcrt/except_i386.c b/dlls/msvcrt/except_i386.c
index 1625854..35e03a5 100644
--- a/dlls/msvcrt/except_i386.c
+++ b/dlls/msvcrt/except_i386.c
@@ -331,7 +331,11 @@ static void cxx_local_unwind( cxx_exception_frame* frame, const cxx_function_des
         if (trylevel < 0 || trylevel >= descr->unwind_count)
         {
             ERR( "invalid trylevel %d\n", trylevel );
+#ifdef VCRUNTIME
+            abort();
+#else
             MSVCRT_terminate();
+#endif
         }
         handler = descr->unwind_table[trylevel].handler;
         if (handler)
diff --git a/dlls/vcruntime140/Makefile.in b/dlls/vcruntime140/Makefile.in
new file mode 100644
index 0000000..c27d6dc
--- /dev/null
+++ b/dlls/vcruntime140/Makefile.in
@@ -0,0 +1,12 @@
+EXTRADEFS = -D_MT -D_MSVCR_VER=140 -DVCRUNTIME
+MODULE    = vcruntime140.dll
+DELAYIMPORTS = advapi32 user32
+PARENTSRC = ../msvcrt
+
+C_SRCS = \
+	except.c \
+	except_arm.c \
+	except_i386.c \
+	except_x86_64.c \
+	main.c \
+	undname.c
diff --git a/dlls/vcruntime140/main.c b/dlls/vcruntime140/main.c
new file mode 100644
index 0000000..9a64aea
--- /dev/null
+++ b/dlls/vcruntime140/main.c
@@ -0,0 +1,224 @@
+/*
+ * msvcrt.dll initialisation functions
+ *
+ * Copyright 2000 Jon Griffiths
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include "msvcrt.h"
+#include "winternl.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
+
+/* Index to TLS */
+DWORD msvcrt_tls_index;
+
+static const char* msvcrt_get_reason(DWORD reason)
+{
+  switch (reason)
+  {
+  case DLL_PROCESS_ATTACH: return "DLL_PROCESS_ATTACH";
+  case DLL_PROCESS_DETACH: return "DLL_PROCESS_DETACH";
+  case DLL_THREAD_ATTACH:  return "DLL_THREAD_ATTACH";
+  case DLL_THREAD_DETACH:  return "DLL_THREAD_DETACH";
+  }
+  return "UNKNOWN";
+}
+
+static inline BOOL msvcrt_init_tls(void)
+{
+  msvcrt_tls_index = TlsAlloc();
+
+  if (msvcrt_tls_index == TLS_OUT_OF_INDEXES)
+  {
+    ERR("TlsAlloc() failed!\n");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+static inline BOOL msvcrt_free_tls(void)
+{
+  if (!TlsFree(msvcrt_tls_index))
+  {
+    ERR("TlsFree() failed!\n");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+static inline void msvcrt_free_tls_mem(void)
+{
+  thread_data_t *tls = TlsGetValue(msvcrt_tls_index);
+
+  HeapFree(GetProcessHeap(), 0, tls);
+}
+
+/*********************************************************************
+ *                  Init
+ */
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+  TRACE("(%p, %s, %p) pid(%x), tid(%x), tls(%u)\n",
+        hinstDLL, msvcrt_get_reason(fdwReason), lpvReserved,
+        GetCurrentProcessId(), GetCurrentThreadId(),
+        msvcrt_tls_index);
+
+  switch (fdwReason)
+  {
+  case DLL_PROCESS_ATTACH:
+    if(!msvcrt_init_tls()) {
+      return FALSE;
+    }
+    TRACE("finished process init\n");
+    break;
+  case DLL_THREAD_ATTACH:
+    break;
+  case DLL_PROCESS_DETACH:
+    if (lpvReserved) break;
+    msvcrt_free_tls_mem();
+    if (!msvcrt_free_tls())
+      return FALSE;
+    TRACE("finished process free\n");
+    break;
+  case DLL_THREAD_DETACH:
+    msvcrt_free_tls_mem();
+    TRACE("finished thread free\n");
+    break;
+  }
+  return TRUE;
+}
+
+/*********************************************************************
+ *              msvcrt_get_thread_data
+ *
+ * Return the thread local storage structure.
+ */
+thread_data_t *msvcrt_get_thread_data(void)
+{
+    thread_data_t *ptr;
+    DWORD err = GetLastError();  /* need to preserve last error */
+
+    if (!(ptr = TlsGetValue( msvcrt_tls_index )))
+    {
+        if (!(ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ptr) )))
+            ExitProcess( _RT_THREAD );
+        if (!TlsSetValue( msvcrt_tls_index, ptr )) ExitProcess( _RT_THREAD );
+        ptr->tid = GetCurrentThreadId();
+        ptr->handle = INVALID_HANDLE_VALUE;
+        ptr->random_seed = 1;
+    }
+    SetLastError( err );
+    return ptr;
+}
+
+/*********************************************************************
+ *                  memcmp (MSVCRT.@)
+ */
+int __cdecl MSVCRT_memcmp(const void *ptr1, const void *ptr2, MSVCRT_size_t n)
+{
+    return memcmp(ptr1, ptr2, n);
+}
+
+/*********************************************************************
+ *                  memcpy   (MSVCRT.@)
+ */
+void * __cdecl MSVCRT_memcpy(void *dst, const void *src, MSVCRT_size_t n)
+{
+    return memmove(dst, src, n);
+}
+
+/*********************************************************************
+ *                  memmove (MSVCRT.@)
+ */
+void * __cdecl MSVCRT_memmove(void *dst, const void *src, MSVCRT_size_t n)
+{
+    return memmove(dst, src, n);
+}
+
+/*********************************************************************
+ *		    memset (MSVCRT.@)
+ */
+void* __cdecl MSVCRT_memset(void *dst, int c, MSVCRT_size_t n)
+{
+    return memset(dst, c, n);
+}
+
+/*********************************************************************
+ *		    strchr (MSVCRT.@)
+ */
+char* __cdecl MSVCRT_strchr(const char *str, int c)
+{
+    return strchr(str, c);
+}
+
+/*********************************************************************
+ *                  strrchr (MSVCRT.@)
+ */
+char* __cdecl MSVCRT_strrchr(const char *str, int c)
+{
+    return strrchr(str, c);
+}
+
+/*********************************************************************
+ *                  memchr   (MSVCRT.@)
+ */
+void* __cdecl MSVCRT_memchr(const void *ptr, int c, MSVCRT_size_t n)
+{
+    return memchr(ptr, c, n);
+}
+
+/*********************************************************************
+ *                  strstr   (MSVCRT.@)
+ */
+char* __cdecl MSVCRT_strstr(const char *haystack, const char *needle)
+{
+    return strstr(haystack, needle);
+}
+
+/*********************************************************************
+ *              wcschr (MSVCRT.@)
+ */
+MSVCRT_wchar_t* CDECL MSVCRT_wcschr(const MSVCRT_wchar_t *str, MSVCRT_wchar_t ch)
+{
+    return strchrW(str, ch);
+}
+
+/*********************************************************************
+ *              wcsstr (MSVCRT.@)
+ */
+MSVCRT_wchar_t* CDECL MSVCRT_wcsstr(const MSVCRT_wchar_t *str, const MSVCRT_wchar_t *sub)
+{
+    return strstrW(str, sub);
+}
+
+/*********************************************************************
+ *              __telemetry_main_invoke_trigger
+ */
+void CDECL __telemetry_main_invoke_trigger(const HINSTANCE hinst)
+{
+    TRACE("(%p)\n", hinst);
+}
+
+/*********************************************************************
+ *              __telemetry_main_return_trigger
+ */
+void CDECL __telemetry_main_return_trigger(const HINSTANCE hinst)
+{
+    TRACE("(%p)\n", hinst);
+}
diff --git a/dlls/vcruntime140/vcruntime140.spec b/dlls/vcruntime140/vcruntime140.spec
new file mode 100644
index 0000000..9a9cc03
--- /dev/null
+++ b/dlls/vcruntime140/vcruntime140.spec
@@ -0,0 +1,87 @@
+@ stub _CreateFrameInfo
+@ stub _CxxThrowException
+@ cdecl -arch=i386 -norelay _EH_prolog()
+@ stub _FindAndUnlinkFrame
+@ stub _IsExceptionObjectToBeDestroyed
+@ stub _NLG_Dispatch2
+@ stub _NLG_Return
+@ stub _NLG_Return2
+@ stub _SetWinRTOutOfMemoryExceptionCallback
+@ stub __AdjustPointer
+@ stub __BuildCatchObject
+@ stub __BuildCatchObjectHelper
+@ stdcall -arch=x86_64 __C_specific_handler(ptr long ptr ptr) ntdll.__C_specific_handler
+@ stub __C_specific_handler_noexcept
+@ cdecl -arch=i386,x86_64,arm __CxxDetectRethrow(ptr)
+@ stub __CxxExceptionFilter
+@ cdecl -arch=i386,x86_64,arm -norelay __CxxFrameHandler(ptr ptr ptr ptr)
+@ cdecl -arch=i386,x86_64,arm -norelay __CxxFrameHandler2(ptr ptr ptr ptr) __CxxFrameHandler
+@ cdecl -arch=i386,x86_64,arm -norelay __CxxFrameHandler3(ptr ptr ptr ptr) __CxxFrameHandler
+@ stdcall -arch=i386 __CxxLongjmpUnwind(ptr)
+@ cdecl -arch=i386,x86_64,arm __CxxQueryExceptionSize()
+@ stub __CxxRegisterExceptionObject
+@ stub __CxxUnregisterExceptionObject
+@ stub __DestructExceptionObject
+@ stub __FrameUnwindFilter
+@ stub __GetPlatformExceptionInfo
+@ stub __NLG_Dispatch2
+@ stub __NLG_Return2
+@ stub __RTCastToVoid
+@ stub __RTDynamicCast
+@ stub __RTtypeid
+@ stub __TypeMatch
+@ stub __current_exception
+@ stub __current_exception_context
+@ stub __intrinsic_setjmp
+@ stub __intrinsic_setjmpex
+@ stub __processing_throw
+@ stub __report_gsfailure
+@ stub __std_exception_copy
+@ stub __std_exception_destroy
+@ stub __std_terminate
+@ stub __std_type_info_compare
+@ stub __std_type_info_destroy_list
+@ stub __std_type_info_hash
+@ stub __std_type_info_name
+@ cdecl __telemetry_main_invoke_trigger(ptr)
+@ cdecl __telemetry_main_return_trigger(ptr)
+@ cdecl __unDName(ptr str long ptr ptr long)
+@ cdecl __unDNameEx(ptr str long ptr ptr ptr long)
+@ cdecl __uncaught_exception() MSVCRT___uncaught_exception
+@ stub __uncaught_exceptions
+@ stub __vcrt_GetModuleFileNameW
+@ stub __vcrt_GetModuleHandleW
+@ stub __vcrt_InitializeCriticalSectionEx
+@ stub __vcrt_LoadLibraryExW
+@ stub _chkesp
+@ cdecl -arch=i386 _except_handler2(ptr ptr ptr ptr)
+@ cdecl -arch=i386 _except_handler3(ptr ptr ptr ptr)
+@ cdecl -arch=i386 _except_handler4_common(ptr ptr ptr ptr ptr ptr)
+@ stub _get_purecall_handler
+@ stub _get_unexpected
+@ cdecl -arch=i386 _global_unwind2(ptr)
+@ stub _is_exception_typeof
+@ cdecl -arch=i386 _local_unwind2(ptr long)
+@ cdecl -arch=i386 _local_unwind4(ptr ptr long)
+@ cdecl -arch=i386 _longjmpex(ptr long) MSVCRT_longjmp
+@ cdecl -arch=x86_64 _local_unwind(ptr ptr)
+@ stub _purecall
+@ stdcall -arch=i386 _seh_longjmp_unwind4(ptr)
+@ stdcall -arch=i386 _seh_longjmp_unwind(ptr)
+@ stub _set_purecall_handler
+@ stub _set_se_translator
+@ cdecl -arch=i386 -norelay _setjmp3(ptr long) MSVCRT__setjmp3
+@ cdecl -arch=i386,x86_64,arm longjmp(ptr long) MSVCRT_longjmp
+@ cdecl memchr(ptr long long) MSVCRT_memchr
+@ cdecl memcmp(ptr ptr long) MSVCRT_memcmp
+@ cdecl memcpy(ptr ptr long) MSVCRT_memcpy
+@ cdecl memmove(ptr ptr long) MSVCRT_memmove
+@ cdecl memset(ptr long long) MSVCRT_memset
+@ stub set_unexpected
+@ cdecl strchr(str long) MSVCRT_strchr
+@ cdecl strrchr(str long) MSVCRT_strrchr
+@ cdecl strstr(str str) MSVCRT_strstr
+@ stub unexpected
+@ cdecl wcschr(wstr long) MSVCRT_wcschr
+@ cdecl wcsrchr(wstr long) ntdll.wcsrchr
+@ cdecl wcsstr(wstr wstr) MSVCRT_wcsstr
-- 
1.8.1.2




More information about the wine-patches mailing list