diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -123,6 +123,7 @@ set(ANDROID 1) endif() pythonize_bool(ANDROID) +pythonize_bool(ANDROID_HAS_ELF_TLS) set(ANDROID_NDK_VERSION 18 CACHE STRING "Set this to the Android NDK version that you are using") @@ -274,6 +275,10 @@ endif() # Provide some common commmandline flags for Sanitizer runtimes. +if(ANDROID) + append_list_if(ANDROID_HAS_ELF_TLS -DANDROID_HAS_ELF_TLS=1 SANITIZER_COMMON_CFLAGS) +endif() + if(NOT WIN32) append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC SANITIZER_COMMON_CFLAGS) endif() diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -6,6 +6,8 @@ include(CheckSymbolExists) include(TestBigEndian) +option(ANDROID_HAS_ELF_TLS "If true, disable emulated-tls and use LLD as linker for compiler-rt and tests on Android." OFF) + function(check_linker_flag flag out_var) cmake_push_check_state() set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${flag}") diff --git a/compiler-rt/lib/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt --- a/compiler-rt/lib/asan/CMakeLists.txt +++ b/compiler-rt/lib/asan/CMakeLists.txt @@ -86,6 +86,10 @@ set(ASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) if(ANDROID) + if(ANDROID_HAS_ELF_TLS) + list(APPEND ASAN_CFLAGS -fno-emulated-tls) + list(APPEND ASAN_DYNAMIC_LINK_FLAGS -fuse-ld=lld) + endif() # Put most Sanitizer shared libraries in the global group. For more details, see # android-changes-for-ndk-developers.md#changes-to-library-search-order if (COMPILER_RT_HAS_Z_GLOBAL) @@ -232,7 +236,9 @@ -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers) # The Solaris 11.4 linker supports a subset of GNU ld version scripts, # but requires a special option to enable it. - if (COMPILER_RT_HAS_GNU_VERSION_SCRIPT_COMPAT) + # This is not used/compatible with LLD. + # We force `lld` on ANDROID (line 90) when ELF-TLS is available. + if (COMPILER_RT_HAS_GNU_VERSION_SCRIPT_COMPAT AND NOT ANDROID_HAS_ELF_TLS) list(APPEND VERSION_SCRIPT_FLAG -Wl,-z,gnu-version-script-compat) endif() set_property(SOURCE diff --git a/compiler-rt/lib/asan/tests/CMakeLists.txt b/compiler-rt/lib/asan/tests/CMakeLists.txt --- a/compiler-rt/lib/asan/tests/CMakeLists.txt +++ b/compiler-rt/lib/asan/tests/CMakeLists.txt @@ -91,6 +91,9 @@ endif() if(ANDROID) list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS -pie) + if(ANDROID_HAS_ELF_TLS) + list(APPEND ASAN_UNITTEST_COMMON_LINK_FLAGS -fuse-ld=lld) + endif() endif() set(ASAN_UNITTEST_INSTRUMENTED_LINK_FLAGS diff --git a/compiler-rt/lib/lsan/CMakeLists.txt b/compiler-rt/lib/lsan/CMakeLists.txt --- a/compiler-rt/lib/lsan/CMakeLists.txt +++ b/compiler-rt/lib/lsan/CMakeLists.txt @@ -1,6 +1,7 @@ include_directories(..) set(LSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +set(LSAN_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) append_rtti_flag(OFF LSAN_CFLAGS) set(LSAN_COMMON_SOURCES @@ -33,6 +34,11 @@ set(LSAN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +if(ANDROID AND ANDROID_HAS_ELF_TLS) + list(APPEND LSAN_CFLAGS -fno-emulated-tls) + list(APPEND LSAN_LINK_FLAGS -fuse-ld=lld) +endif() + add_compiler_rt_object_libraries(RTLSanCommon OS ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${LSAN_COMMON_SUPPORTED_ARCH} @@ -61,7 +67,7 @@ RTSanitizerCommonCoverage RTSanitizerCommonSymbolizer CFLAGS ${LSAN_CFLAGS} - LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} + LINK_FLAGS ${LSAN_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS} LINK_LIBS ${LSAN_LINK_LIBS} PARENT_TARGET lsan) else() @@ -78,6 +84,7 @@ $ ADDITIONAL_HEADERS ${LSAN_HEADERS} CFLAGS ${LSAN_CFLAGS} + LINK_FLAGS ${LSAN_LINK_FLAGS} PARENT_TARGET lsan) endforeach() endif() diff --git a/compiler-rt/test/asan/lit.cfg.py b/compiler-rt/test/asan/lit.cfg.py --- a/compiler-rt/test/asan/lit.cfg.py +++ b/compiler-rt/test/asan/lit.cfg.py @@ -123,8 +123,18 @@ win_runtime_feature = "win32-static-asan" config.available_features.add(win_runtime_feature) +if config.android and (config.target_arch == 'aarch64' or config.target_arch == 'arm') and config.android_has_elf_tls: + # Bionic needs to overalign the TLS segment - 64 for ARM64 and 32 for ARM32. + # (See https://android.googlesource.com/platform/bionic/+/master/libc/bionic/bionic_elf_tls.cpp#120) + # The newer NDKs will link with the right crtbegin but the bots are still using older ones, so we have to do this + # manually. + # FIXME: remove this once the bots are updated. + crt_file_path=config.test_source_root + "../sanitizer_common/android_arm_crtbegin.S " +else: + crt_file_path="" + def build_invocation(compile_flags): - return " " + " ".join([config.clang] + compile_flags) + " " + return " " + " ".join([config.clang] + compile_flags) + " " + crt_file_path config.substitutions.append( ("%clang ", build_invocation(target_cflags)) ) config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) ) diff --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py --- a/compiler-rt/test/lit.common.cfg.py +++ b/compiler-rt/test/lit.common.cfg.py @@ -356,9 +356,17 @@ env['ANDROID_SERIAL'] = config.android_serial config.environment['ANDROID_SERIAL'] = config.android_serial + # These are needed for tests to upload/download temp files, such as + # suppression-files, to device. + config.substitutions.append( ('%device_rundir', "/data/local/tmp/Output") ) + config.substitutions.append( ('%push_to_device', "%s -s '%s' push " % (adb, env['ANDROID_SERIAL']) ) ) + config.substitutions.append( ('%pull_from_device', "%s -s '%s' pull " % (adb, env['ANDROID_SERIAL']) ) ) + config.substitutions.append( ('%adb_shell ', "%s -s '%s' shell " % (adb, env['ANDROID_SERIAL']) ) ) + adb = os.environ.get('ADB', 'adb') try: android_api_level_str = subprocess.check_output([adb, "shell", "getprop", "ro.build.version.sdk"], env=env).rstrip() + android_api_codename = subprocess.check_output([adb, "shell", "getprop", "ro.build.version.codename"], env=env).rstrip().decode("utf-8") except (subprocess.CalledProcessError, OSError): lit_config.fatal("Failed to read ro.build.version.sdk (using '%s' as adb)" % adb) try: @@ -369,12 +377,27 @@ config.available_features.add('android-26') if android_api_level >= 28: config.available_features.add('android-28') + if android_api_level >= 31 or android_api_codename == 'S': + config.available_features.add('android-thread-properties-api') + + if 'android-thread-properties-api' in config.available_features: + # Presence of the thread-properties API implis ELF-TLS support. + # In that case, we must use lld because Bionic's TLS layout is not compatible with the Gold convention. + # The buildbot script will guarantee lld is built/included. + # The check for `has_lld` somehow missed that it exists and always marked tests as "unsupported". + config.use_lld = True + config.has_lld = True # Prepare the device. android_tmpdir = '/data/local/tmp/Output' subprocess.check_call([adb, "shell", "mkdir", "-p", android_tmpdir], env=env) for file in config.android_files_to_push: subprocess.check_call([adb, "push", file, android_tmpdir], env=env) +else: + config.substitutions.append( ('%device_rundir', "") ) + config.substitutions.append( ('%push_to_device', "echo ") ) + config.substitutions.append( ('%pull_from_device', "echo ") ) + config.substitutions.append( ('%adb_shell', "echo ") ) if config.host_os == 'Linux': # detect whether we are using glibc, and which version @@ -388,7 +411,7 @@ from distutils.version import LooseVersion ver = LooseVersion(ver_line.split()[-1].decode()) # 2.27 introduced some incompatibilities - if ver >= LooseVersion("2.27"): + if ver >= LooseVersion("2.27") and not config.android: config.available_features.add("glibc-2.27") sancovcc_path = os.path.join(config.llvm_tools_dir, "sancov") diff --git a/compiler-rt/test/lit.common.configured.in b/compiler-rt/test/lit.common.configured.in --- a/compiler-rt/test/lit.common.configured.in +++ b/compiler-rt/test/lit.common.configured.in @@ -40,6 +40,7 @@ set_default("use_lto", config.use_thinlto) set_default("use_newpm", False) set_default("android", @ANDROID_PYBOOL@) +set_default("android_has_elf_tls", $ANDROID_HAS_ELF_TLS_PYBOOL@) set_default("android_ndk_version", @ANDROID_NDK_VERSION@) set_default("android_serial", "@ANDROID_SERIAL_FOR_TESTING@") set_default("android_files_to_push", []) diff --git a/compiler-rt/test/sanitizer_common/android_arm_crtbegin.S b/compiler-rt/test/sanitizer_common/android_arm_crtbegin.S new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/android_arm_crtbegin.S @@ -0,0 +1,7 @@ +#if defined(__arm__) +.section .tdata,"awT",%progbits +.p2align 5 +#elif defined(__aarch64__) +.section .tdata,"awT",%progbits +.p2align 6 +#endif