[arm] Rework tls detection on android in order to be more strict
authorVlad Brezae <brezaevlad@gmail.com>
Thu, 19 Nov 2015 19:48:07 +0000 (21:48 +0200)
committerVlad Brezae <brezaevlad@gmail.com>
Fri, 4 Dec 2015 21:20:37 +0000 (16:20 -0500)
Unify the tls implementation across platform using a TlsImplementation structure which maps a potential pthread_getspecific implementation to the corresponding fastpaths. Some implementations might require an additional check of the kuser_get_tls kernel helper.

mono/mini/mini-arm-tls.h
mono/mini/mini-arm.c

index 30b2494dfc70c21ad396339e5e8cec5f8c86af6f..a61d699cf17f0bc629f7435ddaeff0aac160b8cc 100644 (file)
@@ -16,4 +16,65 @@ void mono_fallback_set_tls_key (int, int);
 void mono_fast_get_tls_key_end (void);
 void mono_fast_set_tls_key_end (void);
 
+
+/* Structure that maps a possible  tls implementation to the corresponding thunks */
+typedef struct {
+       guint32 *expected_code;
+       int expected_code_length;
+       gboolean check_kernel_helper;
+       gpointer get_tls_thunk;
+       gpointer get_tls_thunk_end;
+       gpointer set_tls_thunk;
+       gpointer set_tls_thunk_end;
+} MonoTlsImplementation;
+
+
+static MonoTlsImplementation known_tls_implementations [] = {
+#if defined(HAVE_KW_THREAD) && defined(__linux__)
+       { NULL, 0, TRUE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end }
+#elif defined(TARGET_IOS)
+       { (guint32[]) {0x1f70ee1d, 0x0103f021, 0x0020f851, 0xbf004770}, 16, FALSE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end }
+#elif defined(TARGET_ANDROID)
+       { (guint32[]) {0xe2403003, 0xe353003c, 0xe92d4010, 0xe1a04000, 0x9a000001, 0xe3a00000, 0xe8bd8010, 0xe3e00a0f, 0xe240101f, 0xe12fff31, 0xe7900104, 0xe8bd8010}, 48, TRUE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end}, /* 1.5 */
+       { (guint32[]) {0xe2402003, 0xe1a03000, 0xe352003c, 0x8a000002, 0xee1d0f70, 0xe7900103, 0xe12fff1e}, 28, FALSE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end}, /* 4.2 */
+       { (guint32[]) {0xe2403007, 0xe3530084, 0x8a000002, 0xee1d1f70, 0xe7910100, 0xe12fff1e, 0xe3a00000, 0xe12fff1e}, 32, FALSE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end}, /* 4.4 */
+       { (guint32[]) {0x2b8c1fc3, 0xee1dd804, 0xf8511f70, 0x47700020, 0x47702000}, 20, FALSE, mono_fast_get_tls_key, mono_fast_get_tls_key_end, mono_fast_set_tls_key, mono_fast_set_tls_key_end} /* 5.0 */
+#endif
+};
+
+static gboolean
+known_kernel_helper (void)
+{
+#ifdef __linux__
+       const guint32* kuser_get_tls = (void*)0xffff0fe0; /* linux kernel user helper on arm */
+       guint32 expected [] = {0xee1d0f70, 0xe12fff1e};
+
+       /* Expecting mrc + bx lr in the kuser_get_tls kernel helper */
+       return memcmp (kuser_get_tls, expected, 8) == 0;
+#else
+       g_error ("Trying to check linux kernel helper on non linux platform"); 
+       return FALSE;
+#endif
+}
+
+static MonoTlsImplementation
+mono_arm_get_tls_implementation (void)
+{
+       /* Discard thumb bit */
+       guint32* pthread_getspecific_addr = (guint32*) ((guint32)pthread_getspecific & 0xfffffffe);
+       int i;
+
+       if (!mini_get_debug_options ()->arm_use_fallback_tls) {
+               for (i = 0; i < sizeof (known_tls_implementations) / sizeof (MonoTlsImplementation); i++) {
+                       if (memcmp (pthread_getspecific_addr, known_tls_implementations [i].expected_code, known_tls_implementations [i].expected_code_length) == 0) {
+                               if ((known_tls_implementations [i].check_kernel_helper && known_kernel_helper ()) ||
+                                               !known_tls_implementations [i].check_kernel_helper)
+                                       return known_tls_implementations [i];
+                       }
+               }
+       }
+
+       g_warning ("No fast tls on device. Using fallbacks.\n");
+       return (MonoTlsImplementation) { NULL, 0, FALSE, mono_fallback_get_tls_key, NULL, mono_fallback_set_tls_key, NULL };
+}
 #endif
index 2798808809f1167c428ac397f996c6d98be4ecf8..a030c4950d15b803e3f41d2f868d53128ef0f373 100644 (file)
@@ -645,30 +645,6 @@ emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
 
 #endif /* #ifndef DISABLE_JIT */
 
-#ifndef MONO_CROSS_COMPILE
-static gboolean
-mono_arm_have_fast_tls (void)
-{
-       if (mini_get_debug_options ()->arm_use_fallback_tls)
-               return FALSE;
-#if (defined(HAVE_KW_THREAD) && defined(__linux__)) \
-       || defined(TARGET_ANDROID)
-       guint32* kuser_get_tls = (void*)0xffff0fe0;
-       guint32 expected [] = {0xee1d0f70, 0xe12fff1e};
-
-       /* Expecting mrc + bx lr in the kuser_get_tls kernel helper */
-       return memcmp (kuser_get_tls, expected, 8) == 0;
-#elif defined(TARGET_IOS)
-       guint32 expected [] = {0x1f70ee1d, 0x0103f021, 0x0020f851, 0xbf004770};
-       /* Discard thumb bit */
-       guint32* pthread_getspecific_addr = (guint32*) ((guint32)pthread_getspecific & 0xfffffffe);
-       return memcmp ((void*)pthread_getspecific_addr, expected, 16) == 0;
-#else
-       return FALSE;
-#endif
-}
-#endif
-
 /*
  * mono_arm_have_tls_get:
  *
@@ -5986,15 +5962,17 @@ mono_arch_register_lowlevel_calls (void)
 
 #ifndef MONO_CROSS_COMPILE
        if (mono_arm_have_tls_get ()) {
-               if (mono_arm_have_fast_tls ()) {
-                       mono_register_jit_icall (mono_fast_get_tls_key, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
-                       mono_register_jit_icall (mono_fast_set_tls_key, "mono_set_tls_key", mono_create_icall_signature ("void ptr ptr"), TRUE);
+               MonoTlsImplementation tls_imp = mono_arm_get_tls_implementation ();
+
+               mono_register_jit_icall (tls_imp.get_tls_thunk, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
+               mono_register_jit_icall (tls_imp.set_tls_thunk, "mono_set_tls_key", mono_create_icall_signature ("void ptr ptr"), TRUE);
 
+               if (tls_imp.get_tls_thunk_end) {
                        mono_tramp_info_register (
                                mono_tramp_info_create (
                                        "mono_get_tls_key",
-                                       (guint8*)mono_fast_get_tls_key,
-                                       (guint8*)mono_fast_get_tls_key_end - (guint8*)mono_fast_get_tls_key,
+                                       (guint8*)tls_imp.get_tls_thunk,
+                                       (guint8*)tls_imp.get_tls_thunk_end - (guint8*)tls_imp.get_tls_thunk,
                                        NULL,
                                        mono_arch_get_cie_program ()
                                        ),
@@ -6003,17 +5981,13 @@ mono_arch_register_lowlevel_calls (void)
                        mono_tramp_info_register (
                                mono_tramp_info_create (
                                        "mono_set_tls_key",
-                                       (guint8*)mono_fast_set_tls_key,
-                                       (guint8*)mono_fast_set_tls_key_end - (guint8*)mono_fast_set_tls_key,
+                                       (guint8*)tls_imp.set_tls_thunk,
+                                       (guint8*)tls_imp.set_tls_thunk_end - (guint8*)tls_imp.set_tls_thunk,
                                        NULL,
                                        mono_arch_get_cie_program ()
                                        ),
                                NULL
                                );
-               } else {
-                       g_warning ("No fast tls on device. Using fallbacks.");
-                       mono_register_jit_icall (mono_fallback_get_tls_key, "mono_get_tls_key", mono_create_icall_signature ("ptr ptr"), TRUE);
-                       mono_register_jit_icall (mono_fallback_set_tls_key, "mono_set_tls_key", mono_create_icall_signature ("void ptr ptr"), TRUE);
                }
        }
 #endif