From b746e637bf21f652b078b822e969e783075450f9 Mon Sep 17 00:00:00 2001 From: Ivan Maidanski Date: Fri, 27 Dec 2013 01:41:05 +0400 Subject: [PATCH] Fix data roots registration for Android/x86 and NDK ARM 'gold' linker * include/gc.h (_etext, __dso_handle): Declare weak symbol (only if Android). * os_dep.c (_etext, __dso_handle): Likewise. * include/gc.h (GC_INIT_CONF_ROOTS): If __data_start is incorrect (less than _etext or missing but __dso_handle (which is typically located at data section start) is greater than _etext as observed for code produced by "gold" linker of Android NDK r9b) then use __dso_handle as the lowest bound of registered data root instead of __data_start (only if Android); update comment. * os_dep.c (GC_init_linux_data_start): Likewise. * os_dep.c (__data_start, data_start): Reformat code. --- include/gc.h | 18 +++++++++++++++--- os_dep.c | 23 ++++++++++++++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/include/gc.h b/include/gc.h index ff8ff329..9af396eb 100644 --- a/include/gc.h +++ b/include/gc.h @@ -1614,11 +1614,23 @@ 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) - /* 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 diff --git a/os_dep.c b/os_dep.c index 2730205d..7fbeda3e 100644 --- a/os_dep.c +++ b/os_dep.c @@ -441,11 +441,15 @@ GC_INNER char * GC_get_maps(void) /* 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[]; @@ -457,6 +461,19 @@ GC_INNER char * GC_get_maps(void) { # 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); -- 2.40.0