# define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND)
#elif (defined(PLATFORM_ANDROID) || defined(__ANDROID__)) \
&& !defined(GC_NOT_DLL)
- /* Required if GC is built as shared lib with -D IGNORE_DYNAMIC_LOADING. */
# pragma weak __data_start
extern int __data_start[], _end[];
-# define GC_INIT_CONF_ROOTS (void)((GC_word)(__data_start) != 0 ? \
- (GC_add_roots(__data_start, _end), 0) : 0)
+# pragma weak _etext
+# 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). */
+# 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)
#else
# define GC_INIT_CONF_ROOTS /* empty */
#endif
/* define data_start as a weak symbol. The latter is technically */
/* broken, since the user program may define data_start, in which */
/* case we lose. Nonetheless, we try both, preferring __data_start.*/
- /* We assume gcc-compatible pragmas. */
+ /* We assume gcc-compatible pragmas. */
# pragma weak __data_start
- extern int __data_start[];
# pragma weak data_start
- extern int data_start[];
+ extern int __data_start[], data_start[];
+# ifdef PLATFORM_ANDROID
+# pragma weak _etext
+# pragma weak __dso_handle
+ extern int _etext[], __dso_handle[];
+# endif
# endif /* LINUX */
extern int _end[];
{
# 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). */
+ if ((word)__data_start < (word)_etext
+ && (word)_etext < (word)__dso_handle) {
+ GC_data_start = (ptr_t)(__dso_handle);
+# ifdef DEBUG_ADD_DEL_ROOTS
+ GC_log_printf(
+ "__data_start is wrong; using __dso_handle as data start\n");
+# endif
+ GC_ASSERT((word)GC_data_start <= (word)_end);
+ return;
+ }
+# endif
if ((ptr_t)__data_start != 0) {
GC_data_start = (ptr_t)(__data_start);
GC_ASSERT((word)GC_data_start <= (word)_end);