From: Ivan Maidanski Date: Fri, 23 Oct 2015 09:24:21 +0000 (+0300) Subject: Workaround invalid '_end' symbol on Android clang 3.5+ X-Git-Tag: gc7_4_4~66 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=907b0ff8db180896876226146140dd31f44bbe37;p=gc Workaround invalid '_end' symbol on Android clang 3.5+ * 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. --- diff --git a/include/gc.h b/include/gc.h index 2ed29184..2a604942 100644 --- a/include/gc.h +++ b/include/gc.h @@ -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 diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h index b5ed075d..56392365 100644 --- a/include/private/gcconfig.h +++ b/include/private/gcconfig.h @@ -2473,6 +2473,16 @@ # 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 */ diff --git a/os_dep.c b/os_dep.c index 3217f985..ba133786 100644 --- 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 */