]> granicus.if.org Git - gc/commitdiff
Workaround invalid '_end' symbol on Android clang 3.5+
authorIvan Maidanski <ivmai@mail.ru>
Fri, 23 Oct 2015 09:24:21 +0000 (12:24 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Mon, 1 Feb 2016 07:04:29 +0000 (10:04 +0300)
* include/gc.h (GC_INIT_CONF_ROOTS): Handle Android clang (3.5-3.6)
case when "_end" symbol has incorrect address but "__end__" is defined
(by bfd linker only); declare "__end__" symbol as weak.
* include/private/gcconfig.h (DATAEND): Redefine for Android/clang;
define __end__ as weak symbol.
* os_dep.c (_end): Remove declaration (declared in gcconfig.h).
* os_dep.c (GC_init_linux_data_start): Define new local variable
(data_end); set it to DATAEND; use it instead of _end.

include/gc.h
include/private/gcconfig.h
os_dep.c

index 2ed29184665241f2af9f789561639d5c4f144cef..2a604942a7a82e825ecdc9df48044d78bbd3b486 100644 (file)
@@ -1610,23 +1610,29 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
 # define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND)
 #elif (defined(PLATFORM_ANDROID) || defined(__ANDROID__)) \
       && !defined(GC_NOT_DLL)
-# pragma weak __data_start
-  extern int __data_start[], _end[];
 # pragma weak _etext
+# pragma weak __data_start
 # pragma weak __dso_handle
-  extern int _etext[], __dso_handle[];
-  /* Explicitly register caller static data roots (__data_start points  */
-  /* to the beginning typically but NDK "gold" linker could provide it  */
-  /* incorrectly, so the workaround is to check the value and use       */
-  /* __dso_handle as an alternative data start reference if provided).  */
-  /* It also works for Android/x86 target where __data_start is not     */
-  /* defined currently (regardless of linker used).                     */
+  extern int _etext[], __data_start[], __dso_handle[];
+# pragma weak __end__
+  extern int __end__[], _end[];
+  /* Explicitly register caller static data roots.  Workaround for      */
+  /* __data_start: NDK "gold" linker might miss it or place it          */
+  /* incorrectly, __dso_handle is an alternative data start reference.  */
+  /* Workaround for _end: NDK Clang 3.5+ does not place it at correct   */
+  /* offset (as of NDK r10e) but "bfd" linker provides __end__ symbol   */
+  /* that could be used instead.                                        */
 # define GC_INIT_CONF_ROOTS \
                 (void)((GC_word)__data_start < (GC_word)_etext \
-                        && (GC_word)_etext < (GC_word)__dso_handle ? \
-                            (GC_add_roots(__dso_handle, _end), 0) : \
-                       (GC_word)__data_start != 0 ? \
-                            (GC_add_roots(__data_start, _end), 0) : 0)
+                        && (GC_word)_etext < (GC_word)__dso_handle \
+                        ? (__end__ != 0 \
+                            ? (GC_add_roots(__dso_handle, __end__), 0) \
+                            : (GC_word)__dso_handle < (GC_word)_end \
+                            ? (GC_add_roots(__dso_handle, _end), 0) : 0) \
+                        : __data_start != 0 ? (__end__ != 0 \
+                            ? (GC_add_roots(__data_start, __end__), 0) \
+                            : (GC_word)__data_start < (GC_word)_end \
+                            ? (GC_add_roots(__data_start, _end), 0) : 0) : 0)
 #else
 # define GC_INIT_CONF_ROOTS /* empty */
 #endif
index b5ed075d387f9ee62c794aa17f857a89a5f2934b..56392365f1dff344ec08cfe0d77dde6764ab957b 100644 (file)
 # define DATAEND (ptr_t)(end)
 #endif
 
+/* Workaround for Android NDK clang 3.5+ (as of NDK r10e) which does    */
+/* not provide correct _end symbol.  Unfortunately, alternate __end__   */
+/* symbol is provided only by NDK "bfd" linker.                         */
+#if defined(PLATFORM_ANDROID) && defined(__clang__)
+# undef DATAEND
+# pragma weak __end__
+  extern int __end__[];
+# define DATAEND (__end__ != 0 ? (ptr_t)__end__ : (ptr_t)_end)
+#endif
+
 #if defined(PLATFORM_ANDROID) && !defined(THREADS) \
     && !defined(USE_GET_STACKBASE_FOR_MAIN)
   /* Always use pthread_attr_getstack on Android ("-lpthread" option is  */
index 3217f985e01090a174dff421b86b41897f92a939..ba1337866c82528c8428ceacbd8c3b175453190c 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
@@ -415,7 +415,6 @@ GC_INNER char * GC_get_maps(void)
       extern int _etext[], __dso_handle[];
 #   endif
 # endif /* LINUX */
-  extern int _end[];
 
   ptr_t GC_data_start = NULL;
 
@@ -423,10 +422,12 @@ GC_INNER char * GC_get_maps(void)
 
   GC_INNER void GC_init_linux_data_start(void)
   {
+    ptr_t data_end = DATAEND;
+
 #   if (defined(LINUX) || defined(HURD)) && !defined(IGNORE_PROG_DATA_START)
       /* Try the easy approaches first: */
 #     ifdef PLATFORM_ANDROID
-        /* Workaround for "gold" (default) linker (as of Android NDK r9b).      */
+        /* Workaround for "gold" (default) linker (as of Android NDK r10e). */
         if ((word)__data_start < (word)_etext
             && (word)_etext < (word)__dso_handle) {
           GC_data_start = (ptr_t)(__dso_handle);
@@ -434,18 +435,18 @@ GC_INNER char * GC_get_maps(void)
             GC_log_printf(
                 "__data_start is wrong; using __dso_handle as data start\n");
 #         endif
-          GC_ASSERT((word)GC_data_start <= (word)_end);
+          GC_ASSERT((word)GC_data_start <= (word)data_end);
           return;
         }
 #     endif
       if ((ptr_t)__data_start != 0) {
           GC_data_start = (ptr_t)(__data_start);
-          GC_ASSERT((word)GC_data_start <= (word)_end);
+          GC_ASSERT((word)GC_data_start <= (word)data_end);
           return;
       }
       if ((ptr_t)data_start != 0) {
           GC_data_start = (ptr_t)(data_start);
-          GC_ASSERT((word)GC_data_start <= (word)_end);
+          GC_ASSERT((word)GC_data_start <= (word)data_end);
           return;
       }
 #     ifdef DEBUG_ADD_DEL_ROOTS
@@ -456,11 +457,11 @@ GC_INNER char * GC_get_maps(void)
     if (GC_no_dls) {
       /* Not needed, avoids the SIGSEGV caused by       */
       /* GC_find_limit which complicates debugging.     */
-      GC_data_start = (ptr_t)_end; /* set data root size to 0 */
+      GC_data_start = data_end; /* set data root size to 0 */
       return;
     }
 
-    GC_data_start = GC_find_limit((ptr_t)(_end), FALSE);
+    GC_data_start = GC_find_limit(data_end, FALSE);
   }
 #endif /* SEARCH_FOR_DATA_START */