summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libc/Android.mk51
-rw-r--r--libc/NOTICE156
-rw-r--r--libc/SYSCALLS.TXT12
-rw-r--r--libc/arch-arm/arm.mk1
-rw-r--r--libc/arch-arm/bionic/__bionic_clone.S2
-rw-r--r--libc/arch-arm/bionic/libgcc_protect_unwind.c93
-rw-r--r--libc/arch-arm/cortex-a53/cortex-a53.mk1
-rw-r--r--libc/arch-arm/cortex-a9/bionic/memset.S29
-rw-r--r--libc/arch-arm/generic/bionic/memcmp.S24
-rw-r--r--libc/arch-arm/generic/bionic/memcpy.S62
-rw-r--r--libc/arch-arm/generic/bionic/memset.S24
-rw-r--r--libc/arch-arm/generic/bionic/strcpy.S10
-rw-r--r--libc/arch-arm/krait/bionic/memset.S7
-rw-r--r--libc/arch-arm/syscalls/___clock_nanosleep.S (renamed from libc/arch-arm/syscalls/__clock_nanosleep.S)5
-rw-r--r--libc/arch-arm/syscalls/___fgetxattr.S (renamed from libc/arch-arm/syscalls/fgetxattr.S)5
-rw-r--r--libc/arch-arm/syscalls/___fsetxattr.S (renamed from libc/arch-arm/syscalls/fsetxattr.S)5
-rw-r--r--libc/arch-arm/syscalls/___rt_sigqueueinfo.S (renamed from libc/arch-arm/syscalls/__rt_sigqueueinfo.S)5
-rw-r--r--libc/arch-arm/syscalls/ftruncate.S14
-rw-r--r--libc/arch-arm/syscalls/process_vm_readv.S22
-rw-r--r--libc/arch-arm/syscalls/process_vm_writev.S22
-rw-r--r--libc/arch-arm64/arm64.mk2
-rw-r--r--libc/arch-arm64/bionic/libgcc_compat.c15
-rw-r--r--libc/arch-arm64/cortex-a53/cortex-a53.mk1
-rw-r--r--libc/arch-arm64/generic/bionic/memchr.S6
-rw-r--r--libc/arch-arm64/generic/bionic/strchr.S6
-rw-r--r--libc/arch-arm64/syscalls/___clock_nanosleep.S (renamed from libc/arch-arm64/syscalls/__clock_nanosleep.S)6
-rw-r--r--libc/arch-arm64/syscalls/___fgetxattr.S (renamed from libc/arch-arm64/syscalls/fgetxattr.S)5
-rw-r--r--libc/arch-arm64/syscalls/___fsetxattr.S (renamed from libc/arch-arm64/syscalls/fsetxattr.S)5
-rw-r--r--libc/arch-arm64/syscalls/___rt_sigqueueinfo.S (renamed from libc/arch-arm64/syscalls/__rt_sigqueueinfo.S)6
-rw-r--r--libc/arch-arm64/syscalls/process_vm_readv.S14
-rw-r--r--libc/arch-arm64/syscalls/process_vm_writev.S14
-rw-r--r--libc/arch-common/bionic/asm_multiarch.h4
-rw-r--r--libc/arch-common/bionic/crtend.S7
-rw-r--r--libc/arch-common/bionic/crtend_so.S14
-rw-r--r--libc/arch-mips/bionic/setjmp.S2
-rw-r--r--libc/arch-mips/mips.mk8
-rw-r--r--libc/arch-mips/string/memcpy.S1157
-rw-r--r--libc/arch-mips/string/memcpy.c91
-rw-r--r--libc/arch-mips/string/memset.S568
-rw-r--r--libc/arch-mips/string/strcmp.S260
-rw-r--r--libc/arch-mips/syscalls/___clock_nanosleep.S (renamed from libc/arch-mips/syscalls/__clock_nanosleep.S)5
-rw-r--r--libc/arch-mips/syscalls/___fgetxattr.S (renamed from libc/arch-mips/syscalls/fgetxattr.S)5
-rw-r--r--libc/arch-mips/syscalls/___fsetxattr.S (renamed from libc/arch-mips/syscalls/fsetxattr.S)5
-rw-r--r--libc/arch-mips/syscalls/___rt_sigqueueinfo.S (renamed from libc/arch-mips/syscalls/__rt_sigqueueinfo.S)5
-rw-r--r--libc/arch-mips/syscalls/process_vm_readv.S (renamed from libc/arch-mips/syscalls/ftruncate.S)6
-rw-r--r--libc/arch-mips/syscalls/process_vm_writev.S19
-rw-r--r--libc/arch-mips64/bionic/stat.cpp64
-rw-r--r--libc/arch-mips64/mips64.mk10
-rw-r--r--libc/arch-mips64/string/memcpy.S423
-rw-r--r--libc/arch-mips64/string/memset.S242
-rw-r--r--libc/arch-mips64/string/mips-string-ops.h148
-rw-r--r--libc/arch-mips64/string/mips_strlen.c224
-rw-r--r--libc/arch-mips64/syscalls/___clock_nanosleep.S (renamed from libc/arch-mips64/syscalls/__clock_nanosleep.S)6
-rw-r--r--libc/arch-mips64/syscalls/___fgetxattr.S (renamed from libc/arch-mips64/syscalls/fgetxattr.S)5
-rw-r--r--libc/arch-mips64/syscalls/___fsetxattr.S (renamed from libc/arch-mips64/syscalls/fsetxattr.S)5
-rw-r--r--libc/arch-mips64/syscalls/___rt_sigqueueinfo.S (renamed from libc/arch-mips64/syscalls/__rt_sigqueueinfo.S)6
-rw-r--r--libc/arch-mips64/syscalls/process_vm_readv.S25
-rw-r--r--libc/arch-mips64/syscalls/process_vm_writev.S25
-rw-r--r--libc/arch-x86/syscalls/___clock_nanosleep.S (renamed from libc/arch-x86/syscalls/__clock_nanosleep.S)5
-rw-r--r--libc/arch-x86/syscalls/___fgetxattr.S (renamed from libc/arch-x86/syscalls/fgetxattr.S)5
-rw-r--r--libc/arch-x86/syscalls/___fsetxattr.S (renamed from libc/arch-x86/syscalls/fsetxattr.S)5
-rw-r--r--libc/arch-x86/syscalls/___rt_sigqueueinfo.S (renamed from libc/arch-x86/syscalls/__rt_sigqueueinfo.S)5
-rw-r--r--libc/arch-x86/syscalls/ftruncate.S26
-rw-r--r--libc/arch-x86/syscalls/process_vm_readv.S46
-rw-r--r--libc/arch-x86/syscalls/process_vm_writev.S46
-rw-r--r--libc/arch-x86_64/string/ssse3-strcmp-slm.S4
-rw-r--r--libc/arch-x86_64/syscalls/___clock_nanosleep.S (renamed from libc/arch-x86_64/syscalls/__clock_nanosleep.S)6
-rw-r--r--libc/arch-x86_64/syscalls/___fgetxattr.S (renamed from libc/arch-x86_64/syscalls/fgetxattr.S)5
-rw-r--r--libc/arch-x86_64/syscalls/___fsetxattr.S (renamed from libc/arch-x86_64/syscalls/fsetxattr.S)5
-rw-r--r--libc/arch-x86_64/syscalls/___rt_sigqueueinfo.S (renamed from libc/arch-x86_64/syscalls/__rt_sigqueueinfo.S)6
-rw-r--r--libc/arch-x86_64/syscalls/process_vm_readv.S16
-rw-r--r--libc/arch-x86_64/syscalls/process_vm_writev.S16
-rw-r--r--libc/bionic/bionic_systrace.cpp85
-rw-r--r--libc/bionic/clock_nanosleep.cpp4
-rw-r--r--libc/bionic/debug_mapinfo.cpp70
-rw-r--r--libc/bionic/debug_mapinfo.h3
-rw-r--r--libc/bionic/dirent.cpp8
-rw-r--r--libc/bionic/dlmalloc.h12
-rw-r--r--libc/bionic/fgetxattr.cpp (renamed from linker/linker_environ.h)39
-rw-r--r--libc/bionic/fsetxattr.cpp59
-rw-r--r--libc/bionic/ftruncate.cpp31
-rw-r--r--libc/bionic/libc_init_common.cpp211
-rw-r--r--libc/bionic/libc_init_common.h4
-rw-r--r--libc/bionic/libc_init_static.cpp1
-rw-r--r--libc/bionic/libc_logging.cpp1
-rw-r--r--libc/bionic/malloc_debug_leak.cpp8
-rw-r--r--libc/bionic/ndk_cruft.cpp25
-rw-r--r--libc/bionic/pthread_mutex.cpp12
-rw-r--r--libc/bionic/sigqueue.cpp4
-rw-r--r--libc/bionic/system_properties.cpp10
-rw-r--r--libc/dns/include/resolv_netid.h29
-rw-r--r--libc/dns/net/getaddrinfo.c91
-rw-r--r--libc/dns/net/gethnamaddr.c6
-rw-r--r--libc/include/android/dlext.h10
-rw-r--r--libc/include/elf.h10
-rw-r--r--libc/include/pthread.h11
-rw-r--r--libc/include/sys/_system_properties.h25
-rw-r--r--libc/include/sys/personality.h2
-rw-r--r--libc/include/sys/procfs.h (renamed from libc/arch-mips/string/memset.c)42
-rw-r--r--libc/include/sys/ptrace.h24
-rw-r--r--libc/include/sys/ucontext.h8
-rw-r--r--libc/include/sys/uio.h9
-rw-r--r--libc/include/sys/wait.h3
-rw-r--r--libc/libc.map1456
-rw-r--r--libc/private/ScopedFd.h59
-rw-r--r--libc/stdio/stdio.c2
-rw-r--r--libc/stdlib/atexit.c13
-rw-r--r--libc/stdlib/atexit.h13
-rwxr-xr-xlibc/tools/check-symbols.py5
-rw-r--r--libc/upstream-openbsd/android/include/openbsd-compat.h1
-rw-r--r--libc/version_script.txt5
-rw-r--r--libc/zoneinfo/tzdatabin496043 -> 491816 bytes
-rw-r--r--libdl/Android.mk2
-rw-r--r--libdl/libdl.c4
-rw-r--r--libdl/libdl.map39
-rw-r--r--libm/Android.mk7
-rw-r--r--libm/NOTICE108
-rw-r--r--libm/libm.map378
-rw-r--r--linker/Android.mk5
-rw-r--r--linker/NOTICE76
-rw-r--r--linker/debugger.cpp9
-rw-r--r--linker/dlfcn.cpp49
-rw-r--r--linker/linker.cpp613
-rw-r--r--linker/linker.h30
-rw-r--r--linker/linker_debug.h2
-rw-r--r--linker/linker_environ.cpp192
-rw-r--r--linker/linker_mips.cpp76
-rw-r--r--linker/linker_phdr.cpp26
-rw-r--r--linker/linker_phdr.h3
-rw-r--r--linker/linker_sdk_versions.cpp34
-rw-r--r--tests/Android.mk15
-rw-r--r--tests/dlext_test.cpp4
-rw-r--r--tests/dlfcn_test.cpp93
-rw-r--r--tests/gtest_main.cpp10
-rw-r--r--tests/libdl_test.cpp34
-rw-r--r--tests/libs/Android.mk32
-rw-r--r--tests/libs/dlsym_from_this_functions.cpp52
-rw-r--r--tests/libs/dlsym_from_this_symbol.cpp (renamed from tests/libs/dlsym_from_this.cpp)15
-rw-r--r--tests/libs/dlsym_from_this_symbol2.cpp18
-rw-r--r--tests/pthread_dlfcn_test.cpp83
-rw-r--r--tests/pthread_test.cpp127
-rw-r--r--tests/sys_personality_test.cpp2
-rw-r--r--tests/sys_procfs_test.cpp39
-rw-r--r--tests/sys_uio_test.cpp27
-rw-r--r--tests/sys_xattr_test.cpp100
-rw-r--r--tests/unistd_test.cpp7
-rw-r--r--tools/relocation_packer/Android.mk3
-rw-r--r--tools/relocation_packer/src/elf_file.cc27
-rw-r--r--tools/relocation_packer/src/elf_traits.h4
-rwxr-xr-xtools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.sobin113651 -> 113651 bytes
150 files changed, 5824 insertions, 3097 deletions
diff --git a/libc/Android.mk b/libc/Android.mk
index 20874cb..f0c5e9f 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -129,8 +129,11 @@ libc_bionic_ndk_src_files := \
bionic/fchmod.cpp \
bionic/fchmodat.cpp \
bionic/ffs.cpp \
+ bionic/fgetxattr.cpp \
bionic/flockfile.cpp \
bionic/fpclassify.cpp \
+ bionic/fsetxattr.cpp \
+ bionic/ftruncate.cpp \
bionic/futimens.cpp \
bionic/getcwd.cpp \
bionic/gethostname.cpp \
@@ -547,14 +550,16 @@ libc_thread_atexit_impl_src_files := \
libc_arch_static_src_files := \
bionic/dl_iterate_phdr_static.cpp \
-# Various kinds of LP32 cruft.
+# Various kinds of cruft.
# ========================================================
-libc_bionic_src_files_32 += \
+libc_common_src_files += \
+ bionic/ndk_cruft.cpp \
+
+libc_bionic_ndk_src_files_32 += \
bionic/mmap.cpp \
libc_common_src_files_32 += \
bionic/legacy_32_bit_support.cpp \
- bionic/ndk_cruft.cpp \
bionic/time64.c \
libc_netbsd_src_files_32 += \
@@ -942,13 +947,6 @@ LOCAL_SRC_FILES := $(libc_bionic_src_files)
LOCAL_CFLAGS := $(libc_common_cflags) \
-Wframe-larger-than=2048 \
-# ssse3-strcmp-slm.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_x86_64 += -no-integrated-as
-
-# memcpy.S, memchr.S, etc. do not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
LOCAL_C_INCLUDES := $(libc_common_c_includes) bionic/libstdc++/include
@@ -961,6 +959,7 @@ LOCAL_ADDRESS_SANITIZER := false
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
+$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_bionic_src_files))
include $(BUILD_STATIC_LIBRARY)
@@ -976,13 +975,6 @@ LOCAL_SRC_FILES := $(libc_bionic_ndk_src_files)
LOCAL_CFLAGS := $(libc_common_cflags) \
-Wframe-larger-than=2048 \
-# ssse3-strcmp-slm.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_x86_64 += -no-integrated-as
-
-# memcpy.S, memchr.S, etc. do not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
LOCAL_C_INCLUDES := $(libc_common_c_includes) bionic/libstdc++/include
@@ -995,7 +987,7 @@ LOCAL_ADDRESS_SANITIZER := false
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
-$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_bionic_src_files))
+$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_bionic_ndk_src_files))
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -1031,13 +1023,6 @@ LOCAL_SRC_FILES := $(libc_pthread_src_files)
LOCAL_CFLAGS := $(libc_common_cflags) \
-Wframe-larger-than=2048 \
-# ssse3-strcmp-slm.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_x86_64 += -no-integrated-as
-
-# memcpy.S, memchr.S, etc. do not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
LOCAL_CPPFLAGS := $(libc_common_cppflags) -Wold-style-cast
LOCAL_C_INCLUDES := $(libc_common_c_includes)
@@ -1356,12 +1341,15 @@ LOCAL_CLANG := $(use_clang)
LOCAL_REQUIRED_MODULES := tzdata
LOCAL_ADDITIONAL_DEPENDENCIES := \
$(libc_common_additional_dependencies) \
- $(LOCAL_PATH)/version_script.txt \
+ $(LOCAL_PATH)/libc.map \
# Leave the symbols in the shared library so that stack unwinders can produce
# meaningful name resolution.
LOCAL_STRIP_MODULE := keep_symbols
+# Do not pack libc.so relocations; see http://b/20645321 for details.
+LOCAL_PACK_MODULE_RELOCATIONS := false
+
# WARNING: The only library libc.so should depend on is libdl.so! If you add other libraries,
# make sure to add -Wl,--exclude-libs=libgcc.a to the LOCAL_LDFLAGS for those libraries. This
# ensures that symbols that are pulled into those new libraries from libgcc.a are not declared
@@ -1381,16 +1369,16 @@ LOCAL_CXX_STL := none
LOCAL_SYSTEM_SHARED_LIBRARIES :=
# Don't re-export new/delete and friends, even if the compiler really wants to.
-LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
+LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/libc.map
# We'd really like to do this for all architectures, but since this wasn't done
# before, these symbols must continue to be exported on LP32 for binary
# compatibility.
-# TODO: disabled for http://b/20065774.
-#LOCAL_LDFLAGS_64 := -Wl,--exclude-libs,libgcc.a
+LOCAL_LDFLAGS_64 := -Wl,--exclude-libs,libgcc.a
# TODO: This is to work around b/19059885. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
+LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
$(eval $(call patch-up-arch-specific-flags,LOCAL_SRC_FILES,libc_arch_dynamic_src_files))
@@ -1520,7 +1508,8 @@ LOCAL_CFLAGS := $(libc_common_cflags)
LOCAL_CPPFLAGS := $(libc_common_cppflags)
# TODO: This is to work around b/19059885. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
+LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
LOCAL_SRC_FILES := $(libstdcxx_common_src_files)
LOCAL_MODULE:= libstdc++
diff --git a/libc/NOTICE b/libc/NOTICE
index 1fa31c2..dbe3944 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -307,34 +307,6 @@ SUCH DAMAGE.
-------------------------------------------------------------------
-Copyright (C) 2008-2010 The Android Open Source Project
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
--------------------------------------------------------------------
-
Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -455,22 +427,6 @@ Android adaptation and tweak by Jim Huang <jserv@0xlab.org>.
-------------------------------------------------------------------
Copyright (C) 2011 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
--------------------------------------------------------------------
-
-Copyright (C) 2011 The Android Open Source Project
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -688,6 +644,50 @@ SUCH DAMAGE.
-------------------------------------------------------------------
+Copyright (C) 2015 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2015 The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
Copyright (c) 1980, 1983, 1988, 1993
The Regents of the University of California. All rights reserved.
@@ -2550,33 +2550,6 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
-Copyright (c) 1995, 1996 Carnegie-Mellon University.
-All rights reserved.
-
-Author: Chris G. Demetriou
-
-Permission to use, copy, modify and distribute this software and
-its documentation is hereby granted, provided that both the copyright
-notice and this permission notice appear in all copies of the
-software, derivative works or modified versions, and any portions
-thereof, and that both notices appear in supporting documentation.
-
-CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
-CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
-FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
-
-Carnegie Mellon requests users of this software to return to
-
- Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- School of Computer Science
- Carnegie Mellon University
- Pittsburgh PA 15213-3890
-
-any improvements or extensions that they make and grant Carnegie the
-rights to redistribute these changes.
-
--------------------------------------------------------------------
-
Copyright (c) 1996 by Internet Software Consortium.
Permission to use, copy, modify, and distribute this software for any
@@ -3795,6 +3768,22 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-------------------------------------------------------------------
+Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+-------------------------------------------------------------------
+
Copyright (c) 2007-2008 Michael G Schwern
This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
@@ -4733,31 +4722,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
-Copyright 2000 David E. O'Brien, John D. Polstra.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
--------------------------------------------------------------------
-
Copyright 2008 Android Open Source Project (source port randomization)
Copyright (c) 1985, 1989, 1993
The Regents of the University of California. All rights reserved.
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 33e30eb..2e2cd11 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -122,8 +122,8 @@ int fdatasync(int) all
int fchown:fchown32(int, uid_t, gid_t) arm,x86
int fchown:fchown(int, uid_t, gid_t) arm64,mips,mips64,x86_64
void sync(void) all
-int fsetxattr(int, const char*, const void*, size_t, int) all
-ssize_t fgetxattr(int, const char*, void*, size_t) all
+int ___fsetxattr:fsetxattr(int, const char*, const void*, size_t, int) all
+ssize_t ___fgetxattr:fgetxattr(int, const char*, void*, size_t) all
ssize_t flistxattr(int, char*, size_t) all
int fremovexattr(int, const char*) all
@@ -151,7 +151,6 @@ int utimensat(int, const char*, const struct timespec times[2], int) all
off_t lseek(int, off_t, int) arm,mips,x86
int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,mips,x86
off_t lseek|lseek64(int, off_t, int) arm64,mips64,x86_64
-int ftruncate(int, off_t) arm,mips,x86
int ftruncate64(int, off64_t) arm,mips,x86
int ftruncate|ftruncate64(int, off_t) arm64,mips64,x86_64
ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count) arm,mips,x86
@@ -204,7 +203,7 @@ clock_t times(struct tms*) all
int nanosleep(const struct timespec*, struct timespec*) all
int clock_settime(clockid_t, const struct timespec*) all
int clock_getres(clockid_t, struct timespec*) all
-int __clock_nanosleep:clock_nanosleep(clockid_t, int, const struct timespec*, struct timespec*) all
+int ___clock_nanosleep:clock_nanosleep(clockid_t, int, const struct timespec*, struct timespec*) all
int getitimer(int, const struct itimerval*) all
int setitimer(int, const struct itimerval*, struct itimerval*) all
int __timer_create:timer_create(clockid_t clockid, struct sigevent* evp, __kernel_timer_t* timerid) all
@@ -223,7 +222,7 @@ int __rt_sigpending:rt_sigpending(sigset_t*, size_t) all
int __rt_sigprocmask:rt_sigprocmask(int, const sigset_t*, sigset_t*, size_t) all
int __rt_sigsuspend:rt_sigsuspend(const sigset_t*, size_t) all
int __rt_sigtimedwait:rt_sigtimedwait(const sigset_t*, struct siginfo_t*, struct timespec_t*, size_t) all
-int __rt_sigqueueinfo:rt_sigqueueinfo(pid_t, int, siginfo_t*) all
+int ___rt_sigqueueinfo:rt_sigqueueinfo(pid_t, int, siginfo_t*) all
int __signalfd4:signalfd4(int, const sigset_t*, size_t, int) all
# sockets
@@ -309,6 +308,9 @@ int inotify_rm_watch(int, unsigned int) all
int __pselect6:pselect6(int, fd_set*, fd_set*, fd_set*, timespec*, void*) all
int __ppoll:ppoll(pollfd*, unsigned int, timespec*, const sigset_t*, size_t) all
+ssize_t process_vm_readv(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long) all
+ssize_t process_vm_writev(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long) all
+
int __set_tid_address:set_tid_address(int*) all
int setfsgid(gid_t) all
diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
index 6ef81bb..d72a160 100644
--- a/libc/arch-arm/arm.mk
+++ b/libc/arch-arm/arm.mk
@@ -39,7 +39,6 @@ libc_bionic_src_files_arm += \
arch-arm/bionic/__bionic_clone.S \
arch-arm/bionic/_exit_with_stack_teardown.S \
arch-arm/bionic/libgcc_compat.c \
- arch-arm/bionic/libgcc_protect_unwind.c \
arch-arm/bionic/__restore.S \
arch-arm/bionic/setjmp.S \
arch-arm/bionic/syscall.S \
diff --git a/libc/arch-arm/bionic/__bionic_clone.S b/libc/arch-arm/bionic/__bionic_clone.S
index a268f9d..b771357 100644
--- a/libc/arch-arm/bionic/__bionic_clone.S
+++ b/libc/arch-arm/bionic/__bionic_clone.S
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2010 The Android Open Source Project
+ * Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/libc/arch-arm/bionic/libgcc_protect_unwind.c b/libc/arch-arm/bionic/libgcc_protect_unwind.c
deleted file mode 100644
index 6d758fc..0000000
--- a/libc/arch-arm/bionic/libgcc_protect_unwind.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO: This file should go away once unwinder migration to libc++.so is complete.
-
-extern char _Unwind_Backtrace __attribute((visibility("protected")));
-extern char __gnu_Unwind_Find_exidx __attribute((visibility("protected")));
-extern char __gnu_Unwind_Restore_VFP_D __attribute((visibility("protected")));
-extern char __gnu_Unwind_Restore_VFP __attribute((visibility("protected")));
-extern char __gnu_Unwind_Restore_VFP_D_16_to_31 __attribute((visibility("protected")));
-extern char __gnu_Unwind_Restore_WMMXD __attribute((visibility("protected")));
-extern char __gnu_Unwind_Restore_WMMXC __attribute((visibility("protected")));
-extern char _Unwind_GetCFA __attribute((visibility("protected")));
-extern char __gnu_Unwind_RaiseException __attribute((visibility("protected")));
-extern char __gnu_Unwind_ForcedUnwind __attribute((visibility("protected")));
-extern char __gnu_Unwind_Resume __attribute((visibility("protected")));
-extern char __gnu_Unwind_Resume_or_Rethrow __attribute((visibility("protected")));
-extern char _Unwind_Complete __attribute((visibility("protected")));
-extern char _Unwind_DeleteException __attribute((visibility("protected")));
-extern char _Unwind_VRS_Get __attribute((visibility("protected")));
-extern char _Unwind_VRS_Set __attribute((visibility("protected")));
-extern char __gnu_Unwind_Backtrace __attribute((visibility("protected")));
-extern char _Unwind_VRS_Pop __attribute((visibility("protected")));
-extern char __gnu_Unwind_Save_VFP_D __attribute((visibility("protected")));
-extern char __gnu_Unwind_Save_VFP __attribute((visibility("protected")));
-extern char __gnu_Unwind_Save_VFP_D_16_to_31 __attribute((visibility("protected")));
-extern char __gnu_Unwind_Save_WMMXD __attribute((visibility("protected")));
-extern char __gnu_Unwind_Save_WMMXC __attribute((visibility("protected")));
-extern char ___Unwind_RaiseException __attribute((visibility("protected")));
-extern char _Unwind_RaiseException __attribute((visibility("protected")));
-extern char ___Unwind_Resume __attribute((visibility("protected")));
-extern char _Unwind_Resume __attribute((visibility("protected")));
-extern char ___Unwind_Resume_or_Rethrow __attribute((visibility("protected")));
-extern char _Unwind_Resume_or_Rethrow __attribute((visibility("protected")));
-extern char ___Unwind_ForcedUnwind __attribute((visibility("protected")));
-extern char _Unwind_ForcedUnwind __attribute((visibility("protected")));
-extern char ___Unwind_Backtrace __attribute((visibility("protected")));
-extern char _Unwind_GetRegionStart __attribute((visibility("protected")));
-extern char _Unwind_GetLanguageSpecificData __attribute((visibility("protected")));
-extern char _Unwind_GetDataRelBase __attribute((visibility("protected")));
-extern char _Unwind_GetTextRelBase __attribute((visibility("protected")));
-
-void* __bionic_libgcc_unwind_symbols[] = {
- &_Unwind_Backtrace,
- &__gnu_Unwind_Find_exidx,
- &__gnu_Unwind_Restore_VFP_D,
- &__gnu_Unwind_Restore_VFP,
- &__gnu_Unwind_Restore_VFP_D_16_to_31,
- &__gnu_Unwind_Restore_WMMXD,
- &__gnu_Unwind_Restore_WMMXC,
- &_Unwind_GetCFA,
- &__gnu_Unwind_RaiseException,
- &__gnu_Unwind_ForcedUnwind,
- &__gnu_Unwind_Resume,
- &__gnu_Unwind_Resume_or_Rethrow,
- &_Unwind_Complete,
- &_Unwind_DeleteException,
- &_Unwind_VRS_Get,
- &_Unwind_VRS_Set,
- &__gnu_Unwind_Backtrace,
- &_Unwind_VRS_Pop,
- &__gnu_Unwind_Save_VFP_D,
- &__gnu_Unwind_Save_VFP,
- &__gnu_Unwind_Save_VFP_D_16_to_31,
- &__gnu_Unwind_Save_WMMXD,
- &__gnu_Unwind_Save_WMMXC,
- &___Unwind_RaiseException,
- &_Unwind_RaiseException,
- &___Unwind_Resume,
- &_Unwind_Resume,
- &___Unwind_Resume_or_Rethrow,
- &_Unwind_Resume_or_Rethrow,
- &___Unwind_ForcedUnwind,
- &_Unwind_ForcedUnwind,
- &___Unwind_Backtrace,
- &_Unwind_GetRegionStart,
- &_Unwind_GetLanguageSpecificData,
- &_Unwind_GetDataRelBase,
- &_Unwind_GetTextRelBase,
-};
diff --git a/libc/arch-arm/cortex-a53/cortex-a53.mk b/libc/arch-arm/cortex-a53/cortex-a53.mk
new file mode 100644
index 0000000..b5c337c
--- /dev/null
+++ b/libc/arch-arm/cortex-a53/cortex-a53.mk
@@ -0,0 +1 @@
+include bionic/libc/arch-arm/cortex-a7/cortex-a7.mk
diff --git a/libc/arch-arm/cortex-a9/bionic/memset.S b/libc/arch-arm/cortex-a9/bionic/memset.S
index 299f5a2..8ee6ac2 100644
--- a/libc/arch-arm/cortex-a9/bionic/memset.S
+++ b/libc/arch-arm/cortex-a9/bionic/memset.S
@@ -35,6 +35,7 @@
*/
.fpu neon
+ .syntax unified
ENTRY(__memset_chk)
cmp r2, r3
@@ -100,9 +101,9 @@ ENTRY(memset)
1: bge 2f
vst1.32 {d0[0]}, [r0]!
2: movs ip, r2, lsl #31
- strmib r1, [r0], #1
- strcsb r1, [r0], #1
- strcsb r1, [r0], #1
+ strbmi r1, [r0], #1
+ strbcs r1, [r0], #1
+ strbcs r1, [r0], #1
ldmfd sp!, {r0}
bx lr
END(memset)
@@ -131,11 +132,11 @@ ENTRY_PRIVATE(__memset_large_copy)
orr r1, r1, r1, lsr #16
movs r12, r3, lsl #31
- strcsb r1, [r0], #1 /* can't use strh (alignment unknown) */
- strcsb r1, [r0], #1
- strmib r1, [r0], #1
+ strbcs r1, [r0], #1 /* can't use strh (alignment unknown) */
+ strbcs r1, [r0], #1
+ strbmi r1, [r0], #1
subs r2, r2, r3
- ldmlsfd sp!, {r0, r4-r7, lr} /* return */
+ popls {r0, r4-r7, lr} /* return */
bxls lr
/* align the destination to a cache-line */
@@ -155,9 +156,9 @@ ENTRY_PRIVATE(__memset_large_copy)
/* conditionally writes 0 to 7 words (length in r3) */
movs r3, r3, lsl #28
- stmcsia r0!, {r1, lr}
- stmcsia r0!, {r1, lr}
- stmmiia r0!, {r1, lr}
+ stmcs r0!, {r1, lr}
+ stmcs r0!, {r1, lr}
+ stmmi r0!, {r1, lr}
movs r3, r3, lsl #2
strcs r1, [r0], #4
@@ -172,13 +173,13 @@ ENTRY_PRIVATE(__memset_large_copy)
/* conditionally stores 0 to 31 bytes */
movs r2, r2, lsl #28
- stmcsia r0!, {r1,r3,r12,lr}
- stmmiia r0!, {r1, lr}
+ stmcs r0!, {r1,r3,r12,lr}
+ stmmi r0!, {r1, lr}
movs r2, r2, lsl #2
strcs r1, [r0], #4
- strmih r1, [r0], #2
+ strhmi r1, [r0], #2
movs r2, r2, lsl #2
- strcsb r1, [r0]
+ strbcs r1, [r0]
ldmfd sp!, {r0, r4-r7, lr}
bx lr
END(__memset_large_copy)
diff --git a/libc/arch-arm/generic/bionic/memcmp.S b/libc/arch-arm/generic/bionic/memcmp.S
index 70a2a58..c78dbd4 100644
--- a/libc/arch-arm/generic/bionic/memcmp.S
+++ b/libc/arch-arm/generic/bionic/memcmp.S
@@ -40,6 +40,8 @@
* Optimized memcmp() for Cortex-A9.
*/
+.syntax unified
+
ENTRY(memcmp)
pld [r0, #(CACHE_LINE_SIZE * 0)]
pld [r0, #(CACHE_LINE_SIZE * 1)]
@@ -161,25 +163,25 @@ ENTRY(memcmp)
eors r0, r0, ip
ldreq r0, [r4], #4
ldreq ip, [r1, #4]!
- eoreqs r0, r0, lr
+ eorseq r0, r0, lr
ldreq r0, [r4], #4
ldreq lr, [r1, #4]!
- eoreqs r0, r0, ip
+ eorseq r0, r0, ip
ldreq r0, [r4], #4
ldreq ip, [r1, #4]!
- eoreqs r0, r0, lr
+ eorseq r0, r0, lr
ldreq r0, [r4], #4
ldreq lr, [r1, #4]!
- eoreqs r0, r0, ip
+ eorseq r0, r0, ip
ldreq r0, [r4], #4
ldreq ip, [r1, #4]!
- eoreqs r0, r0, lr
+ eorseq r0, r0, lr
ldreq r0, [r4], #4
ldreq lr, [r1, #4]!
- eoreqs r0, r0, ip
+ eorseq r0, r0, ip
ldreq r0, [r4], #4
ldreq ip, [r1, #4]!
- eoreqs r0, r0, lr
+ eorseq r0, r0, lr
bne 2f
subs r2, r2, #32
bhs 0b
@@ -263,17 +265,17 @@ ENTRY(memcmp)
ldreq lr, [r1], #4
ldreq r0, [r4], #4
orreq ip, ip, lr, lsl #16
- eoreqs r0, r0, ip
+ eorseq r0, r0, ip
moveq ip, lr, lsr #16
ldreq lr, [r1], #4
ldreq r0, [r4], #4
orreq ip, ip, lr, lsl #16
- eoreqs r0, r0, ip
+ eorseq r0, r0, ip
moveq ip, lr, lsr #16
ldreq lr, [r1], #4
ldreq r0, [r4], #4
orreq ip, ip, lr, lsl #16
- eoreqs r0, r0, ip
+ eorseq r0, r0, ip
bne 7f
subs r2, r2, #16
bhs 6b
@@ -317,7 +319,7 @@ ENTRY(memcmp)
ldreq r7, [r1], #4
ldreq r0, [r4], #4
orreq ip, ip, r7, lsl r6
- eoreqs r0, r0, ip
+ eorseq r0, r0, ip
bne 7f
subs r2, r2, #8
bhs 6b
diff --git a/libc/arch-arm/generic/bionic/memcpy.S b/libc/arch-arm/generic/bionic/memcpy.S
index b0c79ab..ea5a399 100644
--- a/libc/arch-arm/generic/bionic/memcpy.S
+++ b/libc/arch-arm/generic/bionic/memcpy.S
@@ -37,6 +37,8 @@
* so we have to preserve R0.
*/
+ .syntax unified
+
ENTRY(__memcpy_chk)
cmp r2, r3
bhi __memcpy_chk_fail
@@ -81,12 +83,12 @@ ENTRY(memcpy)
*/
movs r12, r3, lsl #31
sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */
- ldrmib r3, [r1], #1
- ldrcsb r4, [r1], #1
- ldrcsb r12,[r1], #1
- strmib r3, [r0], #1
- strcsb r4, [r0], #1
- strcsb r12,[r0], #1
+ ldrbmi r3, [r1], #1
+ ldrbcs r4, [r1], #1
+ ldrbcs r12,[r1], #1
+ strbmi r3, [r0], #1
+ strbcs r4, [r0], #1
+ strbcs r12,[r0], #1
.Lsrc_aligned:
@@ -109,10 +111,10 @@ ENTRY(memcpy)
/* conditionally copies 0 to 7 words (length in r3) */
movs r12, r3, lsl #28
- ldmcsia r1!, {r4, r5, r6, r7} /* 16 bytes */
- ldmmiia r1!, {r8, r9} /* 8 bytes */
- stmcsia r0!, {r4, r5, r6, r7}
- stmmiia r0!, {r8, r9}
+ ldmcs r1!, {r4, r5, r6, r7} /* 16 bytes */
+ ldmmi r1!, {r8, r9} /* 8 bytes */
+ stmcs r0!, {r4, r5, r6, r7}
+ stmmi r0!, {r8, r9}
tst r3, #0x4
ldrne r10,[r1], #4 /* 4 bytes */
strne r10,[r0], #4
@@ -177,18 +179,18 @@ ENTRY(memcpy)
/* conditionnaly copies 0 to 31 bytes */
movs r12, r2, lsl #28
- ldmcsia r1!, {r4, r5, r6, r7} /* 16 bytes */
- ldmmiia r1!, {r8, r9} /* 8 bytes */
- stmcsia r0!, {r4, r5, r6, r7}
- stmmiia r0!, {r8, r9}
+ ldmcs r1!, {r4, r5, r6, r7} /* 16 bytes */
+ ldmmi r1!, {r8, r9} /* 8 bytes */
+ stmcs r0!, {r4, r5, r6, r7}
+ stmmi r0!, {r8, r9}
movs r12, r2, lsl #30
ldrcs r3, [r1], #4 /* 4 bytes */
- ldrmih r4, [r1], #2 /* 2 bytes */
+ ldrhmi r4, [r1], #2 /* 2 bytes */
strcs r3, [r0], #4
- strmih r4, [r0], #2
+ strhmi r4, [r0], #2
tst r2, #0x1
- ldrneb r3, [r1] /* last byte */
- strneb r3, [r0]
+ ldrbne r3, [r1] /* last byte */
+ strbne r3, [r0]
/* we're done! restore everything and return */
1: ldmfd sp!, {r5-r11}
@@ -228,11 +230,11 @@ ENTRY(memcpy)
* becomes aligned to 32 bits (r5 = nb of words to copy for alignment)
*/
movs r5, r5, lsl #31
- strmib r3, [r0], #1
+ strbmi r3, [r0], #1
movmi r3, r3, lsr #8
- strcsb r3, [r0], #1
+ strbcs r3, [r0], #1
movcs r3, r3, lsr #8
- strcsb r3, [r0], #1
+ strbcs r3, [r0], #1
movcs r3, r3, lsr #8
cmp r2, #4
@@ -363,23 +365,23 @@ ENTRY(memcpy)
.Lpartial_word_tail:
/* we have a partial word in the input buffer */
movs r5, lr, lsl #(31-3)
- strmib r3, [r0], #1
+ strbmi r3, [r0], #1
movmi r3, r3, lsr #8
- strcsb r3, [r0], #1
+ strbcs r3, [r0], #1
movcs r3, r3, lsr #8
- strcsb r3, [r0], #1
+ strbcs r3, [r0], #1
/* Refill spilled registers from the stack. Don't update sp. */
ldmfd sp, {r5-r11}
.Lcopy_last_3_and_return:
movs r2, r2, lsl #31 /* copy remaining 0, 1, 2 or 3 bytes */
- ldrmib r2, [r1], #1
- ldrcsb r3, [r1], #1
- ldrcsb r12,[r1]
- strmib r2, [r0], #1
- strcsb r3, [r0], #1
- strcsb r12,[r0]
+ ldrbmi r2, [r1], #1
+ ldrbcs r3, [r1], #1
+ ldrbcs r12,[r1]
+ strbmi r2, [r0], #1
+ strbcs r3, [r0], #1
+ strbcs r12,[r0]
/* we're done! restore sp and spilled registers and return */
add sp, sp, #28
diff --git a/libc/arch-arm/generic/bionic/memset.S b/libc/arch-arm/generic/bionic/memset.S
index be35de9..d17a9c4 100644
--- a/libc/arch-arm/generic/bionic/memset.S
+++ b/libc/arch-arm/generic/bionic/memset.S
@@ -35,6 +35,8 @@
* memset() returns its first argument.
*/
+ .syntax unified
+
ENTRY(__memset_chk)
cmp r2, r3
bls done
@@ -76,11 +78,11 @@ ENTRY(memset)
orr r1, r1, r1, lsr #16
movs r12, r3, lsl #31
- strcsb r1, [r0], #1 /* can't use strh (alignment unknown) */
- strcsb r1, [r0], #1
- strmib r1, [r0], #1
+ strbcs r1, [r0], #1 /* can't use strh (alignment unknown) */
+ strbcs r1, [r0], #1
+ strbmi r1, [r0], #1
subs r2, r2, r3
- ldmlsfd sp!, {r0, r4-r7, lr} /* return */
+ popls {r0, r4-r7, lr} /* return */
bxls lr
/* align the destination to a cache-line */
@@ -100,9 +102,9 @@ ENTRY(memset)
/* conditionally writes 0 to 7 words (length in r3) */
movs r3, r3, lsl #28
- stmcsia r0!, {r1, lr}
- stmcsia r0!, {r1, lr}
- stmmiia r0!, {r1, lr}
+ stmcs r0!, {r1, lr}
+ stmcs r0!, {r1, lr}
+ stmmi r0!, {r1, lr}
movs r3, r3, lsl #2
strcs r1, [r0], #4
@@ -117,13 +119,13 @@ ENTRY(memset)
/* conditionally stores 0 to 31 bytes */
movs r2, r2, lsl #28
- stmcsia r0!, {r1,r3,r12,lr}
- stmmiia r0!, {r1, lr}
+ stmcs r0!, {r1,r3,r12,lr}
+ stmmi r0!, {r1, lr}
movs r2, r2, lsl #2
strcs r1, [r0], #4
- strmih r1, [r0], #2
+ strhmi r1, [r0], #2
movs r2, r2, lsl #2
- strcsb r1, [r0]
+ strbcs r1, [r0]
ldmfd sp!, {r0, r4-r7, lr}
bx lr
END(memset)
diff --git a/libc/arch-arm/generic/bionic/strcpy.S b/libc/arch-arm/generic/bionic/strcpy.S
index 802a62d..89ea098 100644
--- a/libc/arch-arm/generic/bionic/strcpy.S
+++ b/libc/arch-arm/generic/bionic/strcpy.S
@@ -32,6 +32,8 @@
#include <machine/cpu-features.h>
#include <private/bionic_asm.h>
+.syntax unified
+
ENTRY(strcpy)
pld [r1, #0]
eor r2, r0, r1
@@ -108,15 +110,15 @@ ENTRY(strcpy)
#ifdef __ARMEB__
tst r2, #0xff00
iteet ne
- strneh r2, [ip], #2
+ strhne r2, [ip], #2
lsreq r2, r2, #8
- streqb r2, [ip]
+ strbeq r2, [ip]
tstne r2, #0xff
#else
tst r2, #0xff
itet ne
- strneh r2, [ip], #2
- streqb r2, [ip]
+ strhne r2, [ip], #2
+ strbeq r2, [ip]
tstne r2, #0xff00
#endif
bne 5b
diff --git a/libc/arch-arm/krait/bionic/memset.S b/libc/arch-arm/krait/bionic/memset.S
index e9f6431..a4fbe17 100644
--- a/libc/arch-arm/krait/bionic/memset.S
+++ b/libc/arch-arm/krait/bionic/memset.S
@@ -37,6 +37,7 @@
*/
.fpu neon
+ .syntax unified
ENTRY(__memset_chk)
cmp r2, r3
@@ -98,9 +99,9 @@ ENTRY(memset)
1: bge 2f
vst1.32 {d0[0]}, [r0]!
2: movs ip, r2, lsl #31
- strmib r1, [r0], #1
- strcsb r1, [r0], #1
- strcsb r1, [r0], #1
+ strbmi r1, [r0], #1
+ strbcs r1, [r0], #1
+ strbcs r1, [r0], #1
ldmfd sp!, {r0}
bx lr
END(memset)
diff --git a/libc/arch-arm/syscalls/__clock_nanosleep.S b/libc/arch-arm/syscalls/___clock_nanosleep.S
index ba7ffc4..31420bb 100644
--- a/libc/arch-arm/syscalls/__clock_nanosleep.S
+++ b/libc/arch-arm/syscalls/___clock_nanosleep.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__clock_nanosleep)
+ENTRY(___clock_nanosleep)
mov ip, r7
ldr r7, =__NR_clock_nanosleep
swi #0
@@ -11,4 +11,5 @@ ENTRY(__clock_nanosleep)
bxls lr
neg r0, r0
b __set_errno_internal
-END(__clock_nanosleep)
+END(___clock_nanosleep)
+.hidden ___clock_nanosleep
diff --git a/libc/arch-arm/syscalls/fgetxattr.S b/libc/arch-arm/syscalls/___fgetxattr.S
index 3f1e5fc..e776cd6 100644
--- a/libc/arch-arm/syscalls/fgetxattr.S
+++ b/libc/arch-arm/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
mov ip, r7
ldr r7, =__NR_fgetxattr
swi #0
@@ -11,4 +11,5 @@ ENTRY(fgetxattr)
bxls lr
neg r0, r0
b __set_errno_internal
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-arm/syscalls/fsetxattr.S b/libc/arch-arm/syscalls/___fsetxattr.S
index 0e33ad2..5445191 100644
--- a/libc/arch-arm/syscalls/fsetxattr.S
+++ b/libc/arch-arm/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
mov ip, sp
stmfd sp!, {r4, r5, r6, r7}
.cfi_def_cfa_offset 16
@@ -19,4 +19,5 @@ ENTRY(fsetxattr)
bxls lr
neg r0, r0
b __set_errno_internal
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-arm/syscalls/__rt_sigqueueinfo.S b/libc/arch-arm/syscalls/___rt_sigqueueinfo.S
index c823cee..25b0d57 100644
--- a/libc/arch-arm/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-arm/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
mov ip, r7
ldr r7, =__NR_rt_sigqueueinfo
swi #0
@@ -11,4 +11,5 @@ ENTRY(__rt_sigqueueinfo)
bxls lr
neg r0, r0
b __set_errno_internal
-END(__rt_sigqueueinfo)
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-arm/syscalls/ftruncate.S b/libc/arch-arm/syscalls/ftruncate.S
deleted file mode 100644
index 1bfe2f3..0000000
--- a/libc/arch-arm/syscalls/ftruncate.S
+++ /dev/null
@@ -1,14 +0,0 @@
-/* Generated by gensyscalls.py. Do not edit. */
-
-#include <private/bionic_asm.h>
-
-ENTRY(ftruncate)
- mov ip, r7
- ldr r7, =__NR_ftruncate
- swi #0
- mov r7, ip
- cmn r0, #(MAX_ERRNO + 1)
- bxls lr
- neg r0, r0
- b __set_errno_internal
-END(ftruncate)
diff --git a/libc/arch-arm/syscalls/process_vm_readv.S b/libc/arch-arm/syscalls/process_vm_readv.S
new file mode 100644
index 0000000..48c49dc
--- /dev/null
+++ b/libc/arch-arm/syscalls/process_vm_readv.S
@@ -0,0 +1,22 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_readv)
+ mov ip, sp
+ stmfd sp!, {r4, r5, r6, r7}
+ .cfi_def_cfa_offset 16
+ .cfi_rel_offset r4, 0
+ .cfi_rel_offset r5, 4
+ .cfi_rel_offset r6, 8
+ .cfi_rel_offset r7, 12
+ ldmfd ip, {r4, r5, r6}
+ ldr r7, =__NR_process_vm_readv
+ swi #0
+ ldmfd sp!, {r4, r5, r6, r7}
+ .cfi_def_cfa_offset 0
+ cmn r0, #(MAX_ERRNO + 1)
+ bxls lr
+ neg r0, r0
+ b __set_errno_internal
+END(process_vm_readv)
diff --git a/libc/arch-arm/syscalls/process_vm_writev.S b/libc/arch-arm/syscalls/process_vm_writev.S
new file mode 100644
index 0000000..4c21c43
--- /dev/null
+++ b/libc/arch-arm/syscalls/process_vm_writev.S
@@ -0,0 +1,22 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_writev)
+ mov ip, sp
+ stmfd sp!, {r4, r5, r6, r7}
+ .cfi_def_cfa_offset 16
+ .cfi_rel_offset r4, 0
+ .cfi_rel_offset r5, 4
+ .cfi_rel_offset r6, 8
+ .cfi_rel_offset r7, 12
+ ldmfd ip, {r4, r5, r6}
+ ldr r7, =__NR_process_vm_writev
+ swi #0
+ ldmfd sp!, {r4, r5, r6, r7}
+ .cfi_def_cfa_offset 0
+ cmn r0, #(MAX_ERRNO + 1)
+ bxls lr
+ neg r0, r0
+ b __set_errno_internal
+END(process_vm_writev)
diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk
index 6a2f313..470a038 100644
--- a/libc/arch-arm64/arm64.mk
+++ b/libc/arch-arm64/arm64.mk
@@ -40,8 +40,6 @@ libc_bionic_src_files_arm64 += \
arch-arm64/bionic/syscall.S \
arch-arm64/bionic/vfork.S \
-# Work around for http://b/20065774.
-libc_bionic_src_files_arm64 += arch-arm64/bionic/libgcc_compat.c
libc_crt_target_cflags_arm64 := \
-I$(LOCAL_PATH)/arch-arm64/include
diff --git a/libc/arch-arm64/bionic/libgcc_compat.c b/libc/arch-arm64/bionic/libgcc_compat.c
deleted file mode 100644
index 2dae3f5..0000000
--- a/libc/arch-arm64/bionic/libgcc_compat.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* STOPSHIP: remove this once the flounder blobs have been rebuilt (http://b/20065774). */
-
-#if !defined(__clang__)
-
-extern void __clear_cache(char*, char*);
-extern char _Unwind_Backtrace;
-extern char _Unwind_GetIP;
-
-void* __bionic_libgcc_compat_symbols[] = {
- &__clear_cache,
- &_Unwind_Backtrace,
- &_Unwind_GetIP,
-};
-
-#endif
diff --git a/libc/arch-arm64/cortex-a53/cortex-a53.mk b/libc/arch-arm64/cortex-a53/cortex-a53.mk
new file mode 100644
index 0000000..676e886
--- /dev/null
+++ b/libc/arch-arm64/cortex-a53/cortex-a53.mk
@@ -0,0 +1 @@
+include bionic/libc/arch-arm64/generic/generic.mk
diff --git a/libc/arch-arm64/generic/bionic/memchr.S b/libc/arch-arm64/generic/bionic/memchr.S
index e5ea57d..a00dd8d 100644
--- a/libc/arch-arm64/generic/bionic/memchr.S
+++ b/libc/arch-arm64/generic/bionic/memchr.S
@@ -101,7 +101,7 @@ ENTRY(memchr)
and vhas_chr2.16b, vhas_chr2.16b, vrepmask.16b
addp vend.16b, vhas_chr1.16b, vhas_chr2.16b /* 256->128 */
addp vend.16b, vend.16b, vend.16b /* 128->64 */
- mov synd, vend.2d[0]
+ mov synd, vend.d[0]
/* Clear the soff*2 lower bits */
lsl tmp, soff, #1
lsr synd, synd, tmp
@@ -121,7 +121,7 @@ ENTRY(memchr)
/* Use a fast check for the termination condition */
orr vend.16b, vhas_chr1.16b, vhas_chr2.16b
addp vend.2d, vend.2d, vend.2d
- mov synd, vend.2d[0]
+ mov synd, vend.d[0]
/* We're not out of data, loop if we haven't found the character */
cbz synd, .Lloop
@@ -131,7 +131,7 @@ ENTRY(memchr)
and vhas_chr2.16b, vhas_chr2.16b, vrepmask.16b
addp vend.16b, vhas_chr1.16b, vhas_chr2.16b /* 256->128 */
addp vend.16b, vend.16b, vend.16b /* 128->64 */
- mov synd, vend.2d[0]
+ mov synd, vend.d[0]
/* Only do the clear for the last possible block */
b.hi .Ltail
diff --git a/libc/arch-arm64/generic/bionic/strchr.S b/libc/arch-arm64/generic/bionic/strchr.S
index 469b83c..b54106d 100644
--- a/libc/arch-arm64/generic/bionic/strchr.S
+++ b/libc/arch-arm64/generic/bionic/strchr.S
@@ -109,7 +109,7 @@ ENTRY(strchr)
addp vend1.16b, vend1.16b, vend2.16b // 128->64
lsr tmp1, tmp3, tmp1
- mov tmp3, vend1.2d[0]
+ mov tmp3, vend1.d[0]
bic tmp1, tmp3, tmp1 // Mask padding bits.
cbnz tmp1, .Ltail
@@ -124,7 +124,7 @@ ENTRY(strchr)
orr vend2.16b, vhas_nul2.16b, vhas_chr2.16b
orr vend1.16b, vend1.16b, vend2.16b
addp vend1.2d, vend1.2d, vend1.2d
- mov tmp1, vend1.2d[0]
+ mov tmp1, vend1.d[0]
cbz tmp1, .Lloop
/* Termination condition found. Now need to establish exactly why
@@ -138,7 +138,7 @@ ENTRY(strchr)
addp vend1.16b, vend1.16b, vend2.16b // 256->128
addp vend1.16b, vend1.16b, vend2.16b // 128->64
- mov tmp1, vend1.2d[0]
+ mov tmp1, vend1.d[0]
.Ltail:
/* Count the trailing zeros, by bit reversing... */
rbit tmp1, tmp1
diff --git a/libc/arch-arm64/syscalls/__clock_nanosleep.S b/libc/arch-arm64/syscalls/___clock_nanosleep.S
index 1df15d6..0dcfd4f 100644
--- a/libc/arch-arm64/syscalls/__clock_nanosleep.S
+++ b/libc/arch-arm64/syscalls/___clock_nanosleep.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__clock_nanosleep)
+ENTRY(___clock_nanosleep)
mov x8, __NR_clock_nanosleep
svc #0
@@ -11,5 +11,5 @@ ENTRY(__clock_nanosleep)
b.hi __set_errno_internal
ret
-END(__clock_nanosleep)
-.hidden __clock_nanosleep
+END(___clock_nanosleep)
+.hidden ___clock_nanosleep
diff --git a/libc/arch-arm64/syscalls/fgetxattr.S b/libc/arch-arm64/syscalls/___fgetxattr.S
index 0d6ada7..c0334cc 100644
--- a/libc/arch-arm64/syscalls/fgetxattr.S
+++ b/libc/arch-arm64/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
mov x8, __NR_fgetxattr
svc #0
@@ -11,4 +11,5 @@ ENTRY(fgetxattr)
b.hi __set_errno_internal
ret
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-arm64/syscalls/fsetxattr.S b/libc/arch-arm64/syscalls/___fsetxattr.S
index e69e718..92be8de 100644
--- a/libc/arch-arm64/syscalls/fsetxattr.S
+++ b/libc/arch-arm64/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
mov x8, __NR_fsetxattr
svc #0
@@ -11,4 +11,5 @@ ENTRY(fsetxattr)
b.hi __set_errno_internal
ret
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-arm64/syscalls/__rt_sigqueueinfo.S b/libc/arch-arm64/syscalls/___rt_sigqueueinfo.S
index 2b23e18..85ea132 100644
--- a/libc/arch-arm64/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-arm64/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
mov x8, __NR_rt_sigqueueinfo
svc #0
@@ -11,5 +11,5 @@ ENTRY(__rt_sigqueueinfo)
b.hi __set_errno_internal
ret
-END(__rt_sigqueueinfo)
-.hidden __rt_sigqueueinfo
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-arm64/syscalls/process_vm_readv.S b/libc/arch-arm64/syscalls/process_vm_readv.S
new file mode 100644
index 0000000..1dd113b
--- /dev/null
+++ b/libc/arch-arm64/syscalls/process_vm_readv.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_readv)
+ mov x8, __NR_process_vm_readv
+ svc #0
+
+ cmn x0, #(MAX_ERRNO + 1)
+ cneg x0, x0, hi
+ b.hi __set_errno_internal
+
+ ret
+END(process_vm_readv)
diff --git a/libc/arch-arm64/syscalls/process_vm_writev.S b/libc/arch-arm64/syscalls/process_vm_writev.S
new file mode 100644
index 0000000..fb29cf8
--- /dev/null
+++ b/libc/arch-arm64/syscalls/process_vm_writev.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_writev)
+ mov x8, __NR_process_vm_writev
+ svc #0
+
+ cmn x0, #(MAX_ERRNO + 1)
+ cneg x0, x0, hi
+ b.hi __set_errno_internal
+
+ ret
+END(process_vm_writev)
diff --git a/libc/arch-common/bionic/asm_multiarch.h b/libc/arch-common/bionic/asm_multiarch.h
index 85e1b57..91cb8af 100644
--- a/libc/arch-common/bionic/asm_multiarch.h
+++ b/libc/arch-common/bionic/asm_multiarch.h
@@ -28,9 +28,9 @@
#ifdef __LP64__
# define ASM_PTR_SIZE(x) .quad x
-# define ASM_ALIGN(x)
+# define ASM_ALIGN_TO_PTR_SIZE .balign 8
#else
# define ASM_PTR_SIZE(x) .long x
-# define ASM_ALIGN(x) .align x
+# define ASM_ALIGN_TO_PTR_SIZE .balign 4
#endif
diff --git a/libc/arch-common/bionic/crtend.S b/libc/arch-common/bionic/crtend.S
index a4cf8de..87d1120 100644
--- a/libc/arch-common/bionic/crtend.S
+++ b/libc/arch-common/bionic/crtend.S
@@ -29,12 +29,15 @@
#include "asm_multiarch.h"
.section .preinit_array, "aw"
+ ASM_ALIGN_TO_PTR_SIZE
ASM_PTR_SIZE(0)
.section .init_array, "aw"
+ ASM_ALIGN_TO_PTR_SIZE
ASM_PTR_SIZE(0)
.section .fini_array, "aw"
+ ASM_ALIGN_TO_PTR_SIZE
ASM_PTR_SIZE(0)
#if defined(__linux__) && defined(__ELF__)
@@ -42,7 +45,9 @@
#endif
#if defined(__i386__) || defined(__x86_64__)
.section .eh_frame,"a",@progbits
- ASM_ALIGN(4)
+#if defined(__i386__)
+ .balign 4
+#endif
.type __FRAME_END__, @object
.size __FRAME_END__, 4
__FRAME_END__:
diff --git a/libc/arch-common/bionic/crtend_so.S b/libc/arch-common/bionic/crtend_so.S
index f745109..e7b8cac 100644
--- a/libc/arch-common/bionic/crtend_so.S
+++ b/libc/arch-common/bionic/crtend_so.S
@@ -26,22 +26,14 @@
* SUCH DAMAGE.
*/
-#include "asm_multiarch.h"
-
-#ifndef __arm__
- .section .init_array, "aw"
- ASM_PTR_SIZE(0)
-
- .section .fini_array, "aw"
- ASM_PTR_SIZE(0)
-#endif
-
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
#if defined(__i386__) || defined(__x86_64__)
.section .eh_frame,"a",@progbits
- ASM_ALIGN(4)
+#if defined(__i386__)
+ .balign 4
+#endif
.type __FRAME_END__, @object
.size __FRAME_END__, 4
__FRAME_END__:
diff --git a/libc/arch-mips/bionic/setjmp.S b/libc/arch-mips/bionic/setjmp.S
index bed9562..3ef0f11 100644
--- a/libc/arch-mips/bionic/setjmp.S
+++ b/libc/arch-mips/bionic/setjmp.S
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014-2015 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/libc/arch-mips/mips.mk b/libc/arch-mips/mips.mk
index 33eceab..05e7198 100644
--- a/libc/arch-mips/mips.mk
+++ b/libc/arch-mips/mips.mk
@@ -6,6 +6,9 @@
libc_bionic_src_files_mips += \
arch-mips/string/memcmp.c \
+ arch-mips/string/memcpy.S \
+ arch-mips/string/memset.S \
+ arch-mips/string/strcmp.S \
bionic/__memcpy_chk.cpp \
bionic/__memset_chk.cpp \
bionic/__strcpy_chk.cpp \
@@ -31,7 +34,6 @@ libc_openbsd_src_files_mips += \
upstream-openbsd/lib/libc/string/stpcpy.c \
upstream-openbsd/lib/libc/string/stpncpy.c \
upstream-openbsd/lib/libc/string/strcat.c \
- upstream-openbsd/lib/libc/string/strcmp.c \
upstream-openbsd/lib/libc/string/strcpy.c \
upstream-openbsd/lib/libc/string/strlcat.c \
upstream-openbsd/lib/libc/string/strlcpy.c \
@@ -54,14 +56,10 @@ libc_bionic_src_files_mips += \
ifndef ARCH_MIPS_REV6
libc_bionic_src_files_mips += \
- arch-mips/string/memcpy.S \
- arch-mips/string/memset.S \
arch-mips/string/mips_strlen.c \
else
libc_bionic_src_files_mips += \
- arch-mips/string/memcpy.c \
- arch-mips/string/memset.c \
arch-mips/string/strlen.c \
endif
diff --git a/libc/arch-mips/string/memcpy.S b/libc/arch-mips/string/memcpy.S
index dc91096..0b711bd 100644
--- a/libc/arch-mips/string/memcpy.S
+++ b/libc/arch-mips/string/memcpy.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009
+ * Copyright (c) 2012-2015
* MIPS Technologies, Inc., California.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,397 +27,826 @@
* SUCH DAMAGE.
*/
-/************************************************************************
- *
- * memcpy.S
- * Version: "043009"
- *
- ************************************************************************/
+#ifdef __ANDROID__
+# include <private/bionic_asm.h>
+# define USE_MEMMOVE_FOR_OVERLAP
+# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD_STREAMED
+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
+#elif _LIBC
+# include <sysdep.h>
+# include <regdef.h>
+# include <sys/asm.h>
+# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD_STREAMED
+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
+#elif _COMPILING_NEWLIB
+# include "machine/asm.h"
+# include "machine/regdef.h"
+# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD_STREAMED
+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
+#else
+# include <regdef.h>
+# include <sys/asm.h>
+#endif
+
+/* Check to see if the MIPS architecture we are compiling for supports
+ * prefetching.
+ */
+
+#if (__mips == 4) || (__mips == 5) || (__mips == 32) || (__mips == 64)
+# ifndef DISABLE_PREFETCH
+# define USE_PREFETCH
+# endif
+#endif
+
+#if defined(_MIPS_SIM) && ((_MIPS_SIM == _ABI64) || (_MIPS_SIM == _ABIN32))
+# ifndef DISABLE_DOUBLE
+# define USE_DOUBLE
+# endif
+#endif
+
+
+#if __mips_isa_rev > 5
+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+# undef PREFETCH_STORE_HINT
+# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE_STREAMED
+# endif
+# define R6_CODE
+#endif
+/* Some asm.h files do not have the L macro definition. */
+#ifndef L
+# if _MIPS_SIM == _ABIO32
+# define L(label) $L ## label
+# else
+# define L(label) .L ## label
+# endif
+#endif
-/************************************************************************
- * Include files
- ************************************************************************/
+/* Some asm.h files do not have the PTR_ADDIU macro definition. */
+#ifndef PTR_ADDIU
+# if _MIPS_SIM == _ABIO32
+# define PTR_ADDIU addiu
+# else
+# define PTR_ADDIU daddiu
+# endif
+#endif
-#include <private/bionic_asm.h>
+/* Some asm.h files do not have the PTR_SRA macro definition. */
+#ifndef PTR_SRA
+# if _MIPS_SIM == _ABIO32
+# define PTR_SRA sra
+# else
+# define PTR_SRA dsra
+# endif
+#endif
+/* New R6 instructions that may not be in asm.h. */
+#ifndef PTR_LSA
+# if _MIPS_SIM == _ABIO32
+# define PTR_LSA lsa
+# else
+# define PTR_LSA dlsa
+# endif
+#endif
/*
- * This routine could be optimized for MIPS64. The current code only
- * uses MIPS32 instructions.
+ * Using PREFETCH_HINT_LOAD_STREAMED instead of PREFETCH_LOAD on load
+ * prefetches appears to offer a slight preformance advantage.
+ *
+ * Using PREFETCH_HINT_PREPAREFORSTORE instead of PREFETCH_STORE
+ * or PREFETCH_STORE_STREAMED offers a large performance advantage
+ * but PREPAREFORSTORE has some special restrictions to consider.
+ *
+ * Prefetch with the 'prepare for store' hint does not copy a memory
+ * location into the cache, it just allocates a cache line and zeros
+ * it out. This means that if you do not write to the entire cache
+ * line before writing it out to memory some data will get zero'ed out
+ * when the cache line is written back to memory and data will be lost.
+ *
+ * Also if you are using this memcpy to copy overlapping buffers it may
+ * not behave correctly when using the 'prepare for store' hint. If you
+ * use the 'prepare for store' prefetch on a memory area that is in the
+ * memcpy source (as well as the memcpy destination), then you will get
+ * some data zero'ed out before you have a chance to read it and data will
+ * be lost.
+ *
+ * If you are going to use this memcpy routine with the 'prepare for store'
+ * prefetch you may want to set USE_MEMMOVE_FOR_OVERLAP in order to avoid
+ * the problem of running memcpy on overlapping buffers.
+ *
+ * There are ifdef'ed sections of this memcpy to make sure that it does not
+ * do prefetches on cache lines that are not going to be completely written.
+ * This code is only needed and only used when PREFETCH_STORE_HINT is set to
+ * PREFETCH_HINT_PREPAREFORSTORE. This code assumes that cache lines are
+ * 32 bytes and if the cache line is larger it will not work correctly.
*/
-#if defined(__MIPSEB__)
-# define LWHI lwl /* high part is left in big-endian */
-# define SWHI swl /* high part is left in big-endian */
-# define LWLO lwr /* low part is right in big-endian */
-# define SWLO swr /* low part is right in big-endian */
+
+#ifdef USE_PREFETCH
+# define PREFETCH_HINT_LOAD 0
+# define PREFETCH_HINT_STORE 1
+# define PREFETCH_HINT_LOAD_STREAMED 4
+# define PREFETCH_HINT_STORE_STREAMED 5
+# define PREFETCH_HINT_LOAD_RETAINED 6
+# define PREFETCH_HINT_STORE_RETAINED 7
+# define PREFETCH_HINT_WRITEBACK_INVAL 25
+# define PREFETCH_HINT_PREPAREFORSTORE 30
+
+/*
+ * If we have not picked out what hints to use at this point use the
+ * standard load and store prefetch hints.
+ */
+# ifndef PREFETCH_STORE_HINT
+# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE
+# endif
+# ifndef PREFETCH_LOAD_HINT
+# define PREFETCH_LOAD_HINT PREFETCH_HINT_LOAD
+# endif
+
+/*
+ * We double everything when USE_DOUBLE is true so we do 2 prefetches to
+ * get 64 bytes in that case. The assumption is that each individual
+ * prefetch brings in 32 bytes.
+ */
+
+# ifdef USE_DOUBLE
+# define PREFETCH_CHUNK 64
+# define PREFETCH_FOR_LOAD(chunk, reg) \
+ pref PREFETCH_LOAD_HINT, (chunk)*64(reg); \
+ pref PREFETCH_LOAD_HINT, ((chunk)*64)+32(reg)
+# define PREFETCH_FOR_STORE(chunk, reg) \
+ pref PREFETCH_STORE_HINT, (chunk)*64(reg); \
+ pref PREFETCH_STORE_HINT, ((chunk)*64)+32(reg)
+# else
+# define PREFETCH_CHUNK 32
+# define PREFETCH_FOR_LOAD(chunk, reg) \
+ pref PREFETCH_LOAD_HINT, (chunk)*32(reg)
+# define PREFETCH_FOR_STORE(chunk, reg) \
+ pref PREFETCH_STORE_HINT, (chunk)*32(reg)
+# endif
+/* MAX_PREFETCH_SIZE is the maximum size of a prefetch, it must not be less
+ * than PREFETCH_CHUNK, the assumed size of each prefetch. If the real size
+ * of a prefetch is greater than MAX_PREFETCH_SIZE and the PREPAREFORSTORE
+ * hint is used, the code will not work correctly. If PREPAREFORSTORE is not
+ * used then MAX_PREFETCH_SIZE does not matter. */
+# define MAX_PREFETCH_SIZE 128
+/* PREFETCH_LIMIT is set based on the fact that we never use an offset greater
+ * than 5 on a STORE prefetch and that a single prefetch can never be larger
+ * than MAX_PREFETCH_SIZE. We add the extra 32 when USE_DOUBLE is set because
+ * we actually do two prefetches in that case, one 32 bytes after the other. */
+# ifdef USE_DOUBLE
+# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + 32 + MAX_PREFETCH_SIZE
+# else
+# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + MAX_PREFETCH_SIZE
+# endif
+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) \
+ && ((PREFETCH_CHUNK * 4) < MAX_PREFETCH_SIZE)
+/* We cannot handle this because the initial prefetches may fetch bytes that
+ * are before the buffer being copied. We start copies with an offset
+ * of 4 so avoid this situation when using PREPAREFORSTORE. */
+#error "PREFETCH_CHUNK is too large and/or MAX_PREFETCH_SIZE is too small."
+# endif
+#else /* USE_PREFETCH not defined */
+# define PREFETCH_FOR_LOAD(offset, reg)
+# define PREFETCH_FOR_STORE(offset, reg)
#endif
-#if defined(__MIPSEL__)
-# define LWHI lwr /* high part is right in little-endian */
-# define SWHI swr /* high part is right in little-endian */
-# define LWLO lwl /* low part is left in big-endian */
-# define SWLO swl /* low part is left in big-endian */
+/* Allow the routine to be named something else if desired. */
+#ifndef MEMCPY_NAME
+# define MEMCPY_NAME memcpy
#endif
-LEAF(memcpy,0)
+/* We use these 32/64 bit registers as temporaries to do the copying. */
+#define REG0 t0
+#define REG1 t1
+#define REG2 t2
+#define REG3 t3
+#if defined(_MIPS_SIM) && (_MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIO64)
+# define REG4 t4
+# define REG5 t5
+# define REG6 t6
+# define REG7 t7
+#else
+# define REG4 ta0
+# define REG5 ta1
+# define REG6 ta2
+# define REG7 ta3
+#endif
+/* We load/store 64 bits at a time when USE_DOUBLE is true.
+ * The C_ prefix stands for CHUNK and is used to avoid macro name
+ * conflicts with system header files. */
+
+#ifdef USE_DOUBLE
+# define C_ST sd
+# define C_LD ld
+# if __MIPSEB
+# define C_LDHI ldl /* high part is left in big-endian */
+# define C_STHI sdl /* high part is left in big-endian */
+# define C_LDLO ldr /* low part is right in big-endian */
+# define C_STLO sdr /* low part is right in big-endian */
+# else
+# define C_LDHI ldr /* high part is right in little-endian */
+# define C_STHI sdr /* high part is right in little-endian */
+# define C_LDLO ldl /* low part is left in little-endian */
+# define C_STLO sdl /* low part is left in little-endian */
+# endif
+# define C_ALIGN dalign /* r6 align instruction */
+#else
+# define C_ST sw
+# define C_LD lw
+# if __MIPSEB
+# define C_LDHI lwl /* high part is left in big-endian */
+# define C_STHI swl /* high part is left in big-endian */
+# define C_LDLO lwr /* low part is right in big-endian */
+# define C_STLO swr /* low part is right in big-endian */
+# else
+# define C_LDHI lwr /* high part is right in little-endian */
+# define C_STHI swr /* high part is right in little-endian */
+# define C_LDLO lwl /* low part is left in little-endian */
+# define C_STLO swl /* low part is left in little-endian */
+# endif
+# define C_ALIGN align /* r6 align instruction */
+#endif
+
+/* Bookkeeping values for 32 vs. 64 bit mode. */
+#ifdef USE_DOUBLE
+# define NSIZE 8
+# define NSIZEMASK 0x3f
+# define NSIZEDMASK 0x7f
+#else
+# define NSIZE 4
+# define NSIZEMASK 0x1f
+# define NSIZEDMASK 0x3f
+#endif
+#define UNIT(unit) ((unit)*NSIZE)
+#define UNITM1(unit) (((unit)*NSIZE)-1)
+
+#ifdef __ANDROID__
+LEAF(MEMCPY_NAME, 0)
+#else
+LEAF(MEMCPY_NAME)
+#endif
+ .set nomips16
.set noreorder
- .set noat
/*
* Below we handle the case where memcpy is called with overlapping src and dst.
- * Although memcpy is not required to handle this case, some parts of Android like Skia
- * rely on such usage. We call memmove to handle such cases.
+ * Although memcpy is not required to handle this case, some parts of Android
+ * like Skia rely on such usage. We call memmove to handle such cases.
*/
- subu t0,a0,a1
- sra AT,t0,31
- xor t1,t0,AT
- subu t0,t1,AT
- sltu AT,t0,a2
- beq AT,zero,.Lmemcpy
- la t9,memmove
+#ifdef USE_MEMMOVE_FOR_OVERLAP
+ PTR_SUBU t0,a0,a1
+ PTR_SRA t2,t0,31
+ xor t1,t0,t2
+ PTR_SUBU t0,t1,t2
+ sltu t2,t0,a2
+ beq t2,zero,L(memcpy)
+ nop
+#if defined(__LP64__)
+ daddiu sp,sp,-8
+ SETUP_GP64(0,MEMCPY_NAME)
+ LA t9,memmove
+ RESTORE_GP64
+ jr t9
+ daddiu sp,sp,8
+#else
+ LA t9,memmove
jr t9
- nop
-.Lmemcpy:
- slti AT,a2,8
- bne AT,zero,.Llast8
- move v0,a0 # memcpy returns the dst pointer
+ nop
+#endif
+L(memcpy):
+#endif
+/*
+ * If the size is less than 2*NSIZE (8 or 16), go to L(lastb). Regardless of
+ * size, copy dst pointer to v0 for the return value.
+ */
+ slti t2,a2,(2 * NSIZE)
+ bne t2,zero,L(lastb)
+#if defined(RETURN_FIRST_PREFETCH) || defined(RETURN_LAST_PREFETCH)
+ move v0,zero
+#else
+ move v0,a0
+#endif
-# Test if the src and dst are word-aligned, or can be made word-aligned
+#ifndef R6_CODE
+
+/*
+ * If src and dst have different alignments, go to L(unaligned), if they
+ * have the same alignment (but are not actually aligned) do a partial
+ * load/store to make them aligned. If they are both already aligned
+ * we can start copying at L(aligned).
+ */
xor t8,a1,a0
- andi t8,t8,0x3 # t8 is a0/a1 word-displacement
-
- bne t8,zero,.Lunaligned
- negu a3,a0
-
- andi a3,a3,0x3 # we need to copy a3 bytes to make a0/a1 aligned
- beq a3,zero,.Lchk16w # when a3=0 then the dst (a0) is word-aligned
- subu a2,a2,a3 # now a2 is the remining bytes count
-
- LWHI t8,0(a1)
- addu a1,a1,a3
- SWHI t8,0(a0)
- addu a0,a0,a3
-
-# Now the dst/src are mutually word-aligned with word-aligned addresses
-.Lchk16w:
- andi t8,a2,0x3f # any whole 64-byte chunks?
- # t8 is the byte count after 64-byte chunks
-
- beq a2,t8,.Lchk8w # if a2==t8, no 64-byte chunks
- # There will be at most 1 32-byte chunk after it
- subu a3,a2,t8 # subtract from a2 the reminder
- # Here a3 counts bytes in 16w chunks
- addu a3,a0,a3 # Now a3 is the final dst after 64-byte chunks
-
- addu t0,a0,a2 # t0 is the "past the end" address
-
-# When in the loop we exercise "pref 30,x(a0)", the a0+x should not be past
-# the "t0-32" address
-# This means: for x=128 the last "safe" a0 address is "t0-160"
-# Alternatively, for x=64 the last "safe" a0 address is "t0-96"
-# In the current version we will use "pref 30,128(a0)", so "t0-160" is the limit
- subu t9,t0,160 # t9 is the "last safe pref 30,128(a0)" address
-
- pref 0,0(a1) # bring the first line of src, addr 0
- pref 0,32(a1) # bring the second line of src, addr 32
- pref 0,64(a1) # bring the third line of src, addr 64
- pref 30,32(a0) # safe, as we have at least 64 bytes ahead
-# In case the a0 > t9 don't use "pref 30" at all
- sgtu v1,a0,t9
- bgtz v1,.Lloop16w # skip "pref 30,64(a0)" for too short arrays
- nop
-# otherwise, start with using pref30
- pref 30,64(a0)
-.Lloop16w:
- pref 0,96(a1)
- lw t0,0(a1)
- bgtz v1,.Lskip_pref30_96 # skip "pref 30,96(a0)"
- lw t1,4(a1)
- pref 30,96(a0) # continue setting up the dest, addr 96
-.Lskip_pref30_96:
- lw t2,8(a1)
- lw t3,12(a1)
- lw t4,16(a1)
- lw t5,20(a1)
- lw t6,24(a1)
- lw t7,28(a1)
- pref 0,128(a1) # bring the next lines of src, addr 128
-
- sw t0,0(a0)
- sw t1,4(a0)
- sw t2,8(a0)
- sw t3,12(a0)
- sw t4,16(a0)
- sw t5,20(a0)
- sw t6,24(a0)
- sw t7,28(a0)
-
- lw t0,32(a1)
- bgtz v1,.Lskip_pref30_128 # skip "pref 30,128(a0)"
- lw t1,36(a1)
- pref 30,128(a0) # continue setting up the dest, addr 128
-.Lskip_pref30_128:
- lw t2,40(a1)
- lw t3,44(a1)
- lw t4,48(a1)
- lw t5,52(a1)
- lw t6,56(a1)
- lw t7,60(a1)
- pref 0, 160(a1) # bring the next lines of src, addr 160
-
- sw t0,32(a0)
- sw t1,36(a0)
- sw t2,40(a0)
- sw t3,44(a0)
- sw t4,48(a0)
- sw t5,52(a0)
- sw t6,56(a0)
- sw t7,60(a0)
-
- addiu a0,a0,64 # adding 64 to dest
- sgtu v1,a0,t9
- bne a0,a3,.Lloop16w
- addiu a1,a1,64 # adding 64 to src
+ andi t8,t8,(NSIZE-1) /* t8 is a0/a1 word-displacement */
+ bne t8,zero,L(unaligned)
+ PTR_SUBU a3, zero, a0
+
+ andi a3,a3,(NSIZE-1) /* copy a3 bytes to align a0/a1 */
+ beq a3,zero,L(aligned) /* if a3=0, it is already aligned */
+ PTR_SUBU a2,a2,a3 /* a2 is the remining bytes count */
+
+ C_LDHI t8,0(a1)
+ PTR_ADDU a1,a1,a3
+ C_STHI t8,0(a0)
+ PTR_ADDU a0,a0,a3
+
+#else /* R6_CODE */
+
+/*
+ * Align the destination and hope that the source gets aligned too. If it
+ * doesn't we jump to L(r6_unaligned*) to do unaligned copies using the r6
+ * align instruction.
+ */
+ andi t8,a0,7
+ lapc t9,L(atable)
+ PTR_LSA t9,t8,t9,2
+ jrc t9
+L(atable):
+ bc L(lb0)
+ bc L(lb7)
+ bc L(lb6)
+ bc L(lb5)
+ bc L(lb4)
+ bc L(lb3)
+ bc L(lb2)
+ bc L(lb1)
+L(lb7):
+ lb a3, 6(a1)
+ sb a3, 6(a0)
+L(lb6):
+ lb a3, 5(a1)
+ sb a3, 5(a0)
+L(lb5):
+ lb a3, 4(a1)
+ sb a3, 4(a0)
+L(lb4):
+ lb a3, 3(a1)
+ sb a3, 3(a0)
+L(lb3):
+ lb a3, 2(a1)
+ sb a3, 2(a0)
+L(lb2):
+ lb a3, 1(a1)
+ sb a3, 1(a0)
+L(lb1):
+ lb a3, 0(a1)
+ sb a3, 0(a0)
+
+ li t9,8
+ subu t8,t9,t8
+ PTR_SUBU a2,a2,t8
+ PTR_ADDU a0,a0,t8
+ PTR_ADDU a1,a1,t8
+L(lb0):
+
+ andi t8,a1,(NSIZE-1)
+ lapc t9,L(jtable)
+ PTR_LSA t9,t8,t9,2
+ jrc t9
+L(jtable):
+ bc L(aligned)
+ bc L(r6_unaligned1)
+ bc L(r6_unaligned2)
+ bc L(r6_unaligned3)
+# ifdef USE_DOUBLE
+ bc L(r6_unaligned4)
+ bc L(r6_unaligned5)
+ bc L(r6_unaligned6)
+ bc L(r6_unaligned7)
+# endif
+#endif /* R6_CODE */
+
+L(aligned):
+
+/*
+ * Now dst/src are both aligned to (word or double word) aligned addresses
+ * Set a2 to count how many bytes we have to copy after all the 64/128 byte
+ * chunks are copied and a3 to the dst pointer after all the 64/128 byte
+ * chunks have been copied. We will loop, incrementing a0 and a1 until a0
+ * equals a3.
+ */
+
+ andi t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */
+ beq a2,t8,L(chkw) /* if a2==t8, no 64-byte/128-byte chunks */
+ PTR_SUBU a3,a2,t8 /* subtract from a2 the reminder */
+ PTR_ADDU a3,a0,a3 /* Now a3 is the final dst after loop */
+
+/* When in the loop we may prefetch with the 'prepare to store' hint,
+ * in this case the a0+x should not be past the "t0-32" address. This
+ * means: for x=128 the last "safe" a0 address is "t0-160". Alternatively,
+ * for x=64 the last "safe" a0 address is "t0-96" In the current version we
+ * will use "prefetch hint,128(a0)", so "t0-160" is the limit.
+ */
+#if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+ PTR_ADDU t0,a0,a2 /* t0 is the "past the end" address */
+ PTR_SUBU t9,t0,PREFETCH_LIMIT /* t9 is the "last safe pref" address */
+#endif
+ PREFETCH_FOR_LOAD (0, a1)
+ PREFETCH_FOR_LOAD (1, a1)
+ PREFETCH_FOR_LOAD (2, a1)
+ PREFETCH_FOR_LOAD (3, a1)
+#if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
+ PREFETCH_FOR_STORE (1, a0)
+ PREFETCH_FOR_STORE (2, a0)
+ PREFETCH_FOR_STORE (3, a0)
+#endif
+#if defined(RETURN_FIRST_PREFETCH) && defined(USE_PREFETCH)
+# if PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE
+ sltu v1,t9,a0
+ bgtz v1,L(skip_set)
+ nop
+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*4)
+L(skip_set):
+# else
+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*1)
+# endif
+#endif
+#if defined(RETURN_LAST_PREFETCH) && defined(USE_PREFETCH) \
+ && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*3)
+# ifdef USE_DOUBLE
+ PTR_ADDIU v0,v0,32
+# endif
+#endif
+L(loop16w):
+ C_LD t0,UNIT(0)(a1)
+#if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+ sltu v1,t9,a0 /* If a0 > t9 don't use next prefetch */
+ bgtz v1,L(skip_pref)
+#endif
+ C_LD t1,UNIT(1)(a1)
+#ifndef R6_CODE
+ PREFETCH_FOR_STORE (4, a0)
+ PREFETCH_FOR_STORE (5, a0)
+#else
+ PREFETCH_FOR_STORE (2, a0)
+#endif
+#if defined(RETURN_LAST_PREFETCH) && defined(USE_PREFETCH)
+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*5)
+# ifdef USE_DOUBLE
+ PTR_ADDIU v0,v0,32
+# endif
+#endif
+L(skip_pref):
+ C_LD REG2,UNIT(2)(a1)
+ C_LD REG3,UNIT(3)(a1)
+ C_LD REG4,UNIT(4)(a1)
+ C_LD REG5,UNIT(5)(a1)
+ C_LD REG6,UNIT(6)(a1)
+ C_LD REG7,UNIT(7)(a1)
+#ifndef R6_CODE
+ PREFETCH_FOR_LOAD (4, a1)
+#else
+ PREFETCH_FOR_LOAD (3, a1)
+#endif
+ C_ST t0,UNIT(0)(a0)
+ C_ST t1,UNIT(1)(a0)
+ C_ST REG2,UNIT(2)(a0)
+ C_ST REG3,UNIT(3)(a0)
+ C_ST REG4,UNIT(4)(a0)
+ C_ST REG5,UNIT(5)(a0)
+ C_ST REG6,UNIT(6)(a0)
+ C_ST REG7,UNIT(7)(a0)
+
+ C_LD t0,UNIT(8)(a1)
+ C_LD t1,UNIT(9)(a1)
+ C_LD REG2,UNIT(10)(a1)
+ C_LD REG3,UNIT(11)(a1)
+ C_LD REG4,UNIT(12)(a1)
+ C_LD REG5,UNIT(13)(a1)
+ C_LD REG6,UNIT(14)(a1)
+ C_LD REG7,UNIT(15)(a1)
+#ifndef R6_CODE
+ PREFETCH_FOR_LOAD (5, a1)
+#endif
+ C_ST t0,UNIT(8)(a0)
+ C_ST t1,UNIT(9)(a0)
+ C_ST REG2,UNIT(10)(a0)
+ C_ST REG3,UNIT(11)(a0)
+ C_ST REG4,UNIT(12)(a0)
+ C_ST REG5,UNIT(13)(a0)
+ C_ST REG6,UNIT(14)(a0)
+ C_ST REG7,UNIT(15)(a0)
+ PTR_ADDIU a0,a0,UNIT(16) /* adding 64/128 to dest */
+ bne a0,a3,L(loop16w)
+ PTR_ADDIU a1,a1,UNIT(16) /* adding 64/128 to src */
move a2,t8
-# Here we have src and dest word-aligned but less than 64-bytes to go
-
-.Lchk8w:
- pref 0, 0x0(a1)
- andi t8,a2,0x1f # is there a 32-byte chunk?
- # the t8 is the reminder count past 32-bytes
- beq a2,t8,.Lchk1w # when a2=t8, no 32-byte chunk
- nop
-
- lw t0,0(a1)
- lw t1,4(a1)
- lw t2,8(a1)
- lw t3,12(a1)
- lw t4,16(a1)
- lw t5,20(a1)
- lw t6,24(a1)
- lw t7,28(a1)
- addiu a1,a1,32
-
- sw t0,0(a0)
- sw t1,4(a0)
- sw t2,8(a0)
- sw t3,12(a0)
- sw t4,16(a0)
- sw t5,20(a0)
- sw t6,24(a0)
- sw t7,28(a0)
- addiu a0,a0,32
-
-.Lchk1w:
- andi a2,t8,0x3 # now a2 is the reminder past 1w chunks
- beq a2,t8,.Llast8
- subu a3,t8,a2 # a3 is count of bytes in 1w chunks
- addu a3,a0,a3 # now a3 is the dst address past the 1w chunks
-
-# copying in words (4-byte chunks)
-.LwordCopy_loop:
- lw t3,0(a1) # the first t3 may be equal t0 ... optimize?
- addiu a1,a1,4
- addiu a0,a0,4
- bne a0,a3,.LwordCopy_loop
- sw t3,-4(a0)
-
-# For the last (<8) bytes
-.Llast8:
- blez a2,.Lleave
- addu a3,a0,a2 # a3 is the last dst address
-.Llast8loop:
- lb v1,0(a1)
- addiu a1,a1,1
- addiu a0,a0,1
- bne a0,a3,.Llast8loop
- sb v1,-1(a0)
+/* Here we have src and dest word-aligned but less than 64-bytes or
+ * 128 bytes to go. Check for a 32(64) byte chunk and copy if if there
+ * is one. Otherwise jump down to L(chk1w) to handle the tail end of
+ * the copy.
+ */
+
+L(chkw):
+ PREFETCH_FOR_LOAD (0, a1)
+ andi t8,a2,NSIZEMASK /* Is there a 32-byte/64-byte chunk. */
+ /* The t8 is the reminder count past 32-bytes */
+ beq a2,t8,L(chk1w) /* When a2=t8, no 32-byte chunk */
+ nop
+ C_LD t0,UNIT(0)(a1)
+ C_LD t1,UNIT(1)(a1)
+ C_LD REG2,UNIT(2)(a1)
+ C_LD REG3,UNIT(3)(a1)
+ C_LD REG4,UNIT(4)(a1)
+ C_LD REG5,UNIT(5)(a1)
+ C_LD REG6,UNIT(6)(a1)
+ C_LD REG7,UNIT(7)(a1)
+ PTR_ADDIU a1,a1,UNIT(8)
+ C_ST t0,UNIT(0)(a0)
+ C_ST t1,UNIT(1)(a0)
+ C_ST REG2,UNIT(2)(a0)
+ C_ST REG3,UNIT(3)(a0)
+ C_ST REG4,UNIT(4)(a0)
+ C_ST REG5,UNIT(5)(a0)
+ C_ST REG6,UNIT(6)(a0)
+ C_ST REG7,UNIT(7)(a0)
+ PTR_ADDIU a0,a0,UNIT(8)
-.Lleave:
+/*
+ * Here we have less than 32(64) bytes to copy. Set up for a loop to
+ * copy one word (or double word) at a time. Set a2 to count how many
+ * bytes we have to copy after all the word (or double word) chunks are
+ * copied and a3 to the dst pointer after all the (d)word chunks have
+ * been copied. We will loop, incrementing a0 and a1 until a0 equals a3.
+ */
+L(chk1w):
+ andi a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */
+ beq a2,t8,L(lastb)
+ PTR_SUBU a3,t8,a2 /* a3 is count of bytes in one (d)word chunks */
+ PTR_ADDU a3,a0,a3 /* a3 is the dst address after loop */
+
+/* copying in words (4-byte or 8-byte chunks) */
+L(wordCopy_loop):
+ C_LD REG3,UNIT(0)(a1)
+ PTR_ADDIU a0,a0,UNIT(1)
+ PTR_ADDIU a1,a1,UNIT(1)
+ bne a0,a3,L(wordCopy_loop)
+ C_ST REG3,UNIT(-1)(a0)
+
+/* Copy the last 8 (or 16) bytes */
+L(lastb):
+ blez a2,L(leave)
+ PTR_ADDU a3,a0,a2 /* a3 is the last dst address */
+L(lastbloop):
+ lb v1,0(a1)
+ PTR_ADDIU a0,a0,1
+ PTR_ADDIU a1,a1,1
+ bne a0,a3,L(lastbloop)
+ sb v1,-1(a0)
+L(leave):
j ra
- nop
-
-#
-# UNALIGNED case
-#
-
-.Lunaligned:
- # got here with a3="negu a0"
- andi a3,a3,0x3 # test if the a0 is word aligned
- beqz a3,.Lua_chk16w
- subu a2,a2,a3 # bytes left after initial a3 bytes
-
- LWHI v1,0(a1)
- LWLO v1,3(a1)
- addu a1,a1,a3 # a3 may be here 1, 2 or 3
- SWHI v1,0(a0)
- addu a0,a0,a3 # below the dst will be word aligned (NOTE1)
-
-.Lua_chk16w:
- andi t8,a2,0x3f # any whole 64-byte chunks?
- # t8 is the byte count after 64-byte chunks
- beq a2,t8,.Lua_chk8w # if a2==t8, no 64-byte chunks
- # There will be at most 1 32-byte chunk after it
- subu a3,a2,t8 # subtract from a2 the reminder
- # Here a3 counts bytes in 16w chunks
- addu a3,a0,a3 # Now a3 is the final dst after 64-byte chunks
-
- addu t0,a0,a2 # t0 is the "past the end" address
-
- subu t9,t0,160 # t9 is the "last safe pref 30,128(a0)" address
-
- pref 0,0(a1) # bring the first line of src, addr 0
- pref 0,32(a1) # bring the second line of src, addr 32
- pref 0,64(a1) # bring the third line of src, addr 64
- pref 30,32(a0) # safe, as we have at least 64 bytes ahead
-# In case the a0 > t9 don't use "pref 30" at all
- sgtu v1,a0,t9
- bgtz v1,.Lua_loop16w # skip "pref 30,64(a0)" for too short arrays
- nop
-# otherwise, start with using pref30
- pref 30,64(a0)
-.Lua_loop16w:
- pref 0,96(a1)
- LWHI t0,0(a1)
- LWLO t0,3(a1)
- LWHI t1,4(a1)
- bgtz v1,.Lua_skip_pref30_96
- LWLO t1,7(a1)
- pref 30,96(a0) # continue setting up the dest, addr 96
-.Lua_skip_pref30_96:
- LWHI t2,8(a1)
- LWLO t2,11(a1)
- LWHI t3,12(a1)
- LWLO t3,15(a1)
- LWHI t4,16(a1)
- LWLO t4,19(a1)
- LWHI t5,20(a1)
- LWLO t5,23(a1)
- LWHI t6,24(a1)
- LWLO t6,27(a1)
- LWHI t7,28(a1)
- LWLO t7,31(a1)
- pref 0,128(a1) # bring the next lines of src, addr 128
-
- sw t0,0(a0)
- sw t1,4(a0)
- sw t2,8(a0)
- sw t3,12(a0)
- sw t4,16(a0)
- sw t5,20(a0)
- sw t6,24(a0)
- sw t7,28(a0)
-
- LWHI t0,32(a1)
- LWLO t0,35(a1)
- LWHI t1,36(a1)
- bgtz v1,.Lua_skip_pref30_128
- LWLO t1,39(a1)
- pref 30,128(a0) # continue setting up the dest, addr 128
-.Lua_skip_pref30_128:
- LWHI t2,40(a1)
- LWLO t2,43(a1)
- LWHI t3,44(a1)
- LWLO t3,47(a1)
- LWHI t4,48(a1)
- LWLO t4,51(a1)
- LWHI t5,52(a1)
- LWLO t5,55(a1)
- LWHI t6,56(a1)
- LWLO t6,59(a1)
- LWHI t7,60(a1)
- LWLO t7,63(a1)
- pref 0, 160(a1) # bring the next lines of src, addr 160
-
- sw t0,32(a0)
- sw t1,36(a0)
- sw t2,40(a0)
- sw t3,44(a0)
- sw t4,48(a0)
- sw t5,52(a0)
- sw t6,56(a0)
- sw t7,60(a0)
-
- addiu a0,a0,64 # adding 64 to dest
- sgtu v1,a0,t9
- bne a0,a3,.Lua_loop16w
- addiu a1,a1,64 # adding 64 to src
+ nop
+
+#ifndef R6_CODE
+/*
+ * UNALIGNED case, got here with a3 = "negu a0"
+ * This code is nearly identical to the aligned code above
+ * but only the destination (not the source) gets aligned
+ * so we need to do partial loads of the source followed
+ * by normal stores to the destination (once we have aligned
+ * the destination).
+ */
+
+L(unaligned):
+ andi a3,a3,(NSIZE-1) /* copy a3 bytes to align a0/a1 */
+ beqz a3,L(ua_chk16w) /* if a3=0, it is already aligned */
+ PTR_SUBU a2,a2,a3 /* a2 is the remining bytes count */
+
+ C_LDHI v1,UNIT(0)(a1)
+ C_LDLO v1,UNITM1(1)(a1)
+ PTR_ADDU a1,a1,a3
+ C_STHI v1,UNIT(0)(a0)
+ PTR_ADDU a0,a0,a3
+
+/*
+ * Now the destination (but not the source) is aligned
+ * Set a2 to count how many bytes we have to copy after all the 64/128 byte
+ * chunks are copied and a3 to the dst pointer after all the 64/128 byte
+ * chunks have been copied. We will loop, incrementing a0 and a1 until a0
+ * equals a3.
+ */
+
+L(ua_chk16w):
+ andi t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */
+ beq a2,t8,L(ua_chkw) /* if a2==t8, no 64-byte/128-byte chunks */
+ PTR_SUBU a3,a2,t8 /* subtract from a2 the reminder */
+ PTR_ADDU a3,a0,a3 /* Now a3 is the final dst after loop */
+
+# if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+ PTR_ADDU t0,a0,a2 /* t0 is the "past the end" address */
+ PTR_SUBU t9,t0,PREFETCH_LIMIT /* t9 is the "last safe pref" address */
+# endif
+ PREFETCH_FOR_LOAD (0, a1)
+ PREFETCH_FOR_LOAD (1, a1)
+ PREFETCH_FOR_LOAD (2, a1)
+# if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
+ PREFETCH_FOR_STORE (1, a0)
+ PREFETCH_FOR_STORE (2, a0)
+ PREFETCH_FOR_STORE (3, a0)
+# endif
+# if defined(RETURN_FIRST_PREFETCH) && defined(USE_PREFETCH)
+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+ sltu v1,t9,a0
+ bgtz v1,L(ua_skip_set)
+ nop
+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*4)
+L(ua_skip_set):
+# else
+ PTR_ADDIU v0,a0,(PREFETCH_CHUNK*1)
+# endif
+# endif
+L(ua_loop16w):
+ PREFETCH_FOR_LOAD (3, a1)
+ C_LDHI t0,UNIT(0)(a1)
+ C_LDHI t1,UNIT(1)(a1)
+ C_LDHI REG2,UNIT(2)(a1)
+# if defined(USE_PREFETCH) && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+ sltu v1,t9,a0
+ bgtz v1,L(ua_skip_pref)
+# endif
+ C_LDHI REG3,UNIT(3)(a1)
+ PREFETCH_FOR_STORE (4, a0)
+ PREFETCH_FOR_STORE (5, a0)
+L(ua_skip_pref):
+ C_LDHI REG4,UNIT(4)(a1)
+ C_LDHI REG5,UNIT(5)(a1)
+ C_LDHI REG6,UNIT(6)(a1)
+ C_LDHI REG7,UNIT(7)(a1)
+ C_LDLO t0,UNITM1(1)(a1)
+ C_LDLO t1,UNITM1(2)(a1)
+ C_LDLO REG2,UNITM1(3)(a1)
+ C_LDLO REG3,UNITM1(4)(a1)
+ C_LDLO REG4,UNITM1(5)(a1)
+ C_LDLO REG5,UNITM1(6)(a1)
+ C_LDLO REG6,UNITM1(7)(a1)
+ C_LDLO REG7,UNITM1(8)(a1)
+ PREFETCH_FOR_LOAD (4, a1)
+ C_ST t0,UNIT(0)(a0)
+ C_ST t1,UNIT(1)(a0)
+ C_ST REG2,UNIT(2)(a0)
+ C_ST REG3,UNIT(3)(a0)
+ C_ST REG4,UNIT(4)(a0)
+ C_ST REG5,UNIT(5)(a0)
+ C_ST REG6,UNIT(6)(a0)
+ C_ST REG7,UNIT(7)(a0)
+ C_LDHI t0,UNIT(8)(a1)
+ C_LDHI t1,UNIT(9)(a1)
+ C_LDHI REG2,UNIT(10)(a1)
+ C_LDHI REG3,UNIT(11)(a1)
+ C_LDHI REG4,UNIT(12)(a1)
+ C_LDHI REG5,UNIT(13)(a1)
+ C_LDHI REG6,UNIT(14)(a1)
+ C_LDHI REG7,UNIT(15)(a1)
+ C_LDLO t0,UNITM1(9)(a1)
+ C_LDLO t1,UNITM1(10)(a1)
+ C_LDLO REG2,UNITM1(11)(a1)
+ C_LDLO REG3,UNITM1(12)(a1)
+ C_LDLO REG4,UNITM1(13)(a1)
+ C_LDLO REG5,UNITM1(14)(a1)
+ C_LDLO REG6,UNITM1(15)(a1)
+ C_LDLO REG7,UNITM1(16)(a1)
+ PREFETCH_FOR_LOAD (5, a1)
+ C_ST t0,UNIT(8)(a0)
+ C_ST t1,UNIT(9)(a0)
+ C_ST REG2,UNIT(10)(a0)
+ C_ST REG3,UNIT(11)(a0)
+ C_ST REG4,UNIT(12)(a0)
+ C_ST REG5,UNIT(13)(a0)
+ C_ST REG6,UNIT(14)(a0)
+ C_ST REG7,UNIT(15)(a0)
+ PTR_ADDIU a0,a0,UNIT(16) /* adding 64/128 to dest */
+ bne a0,a3,L(ua_loop16w)
+ PTR_ADDIU a1,a1,UNIT(16) /* adding 64/128 to src */
move a2,t8
-# Here we have src and dest word-aligned but less than 64-bytes to go
-
-.Lua_chk8w:
- pref 0, 0x0(a1)
- andi t8,a2,0x1f # is there a 32-byte chunk?
- # the t8 is the reminder count
- beq a2,t8,.Lua_chk1w # when a2=t8, no 32-byte chunk
- nop
-
- LWHI t0,0(a1)
- LWLO t0,3(a1)
- LWHI t1,4(a1)
- LWLO t1,7(a1)
- LWHI t2,8(a1)
- LWLO t2,11(a1)
- LWHI t3,12(a1)
- LWLO t3,15(a1)
- LWHI t4,16(a1)
- LWLO t4,19(a1)
- LWHI t5,20(a1)
- LWLO t5,23(a1)
- LWHI t6,24(a1)
- LWLO t6,27(a1)
- LWHI t7,28(a1)
- LWLO t7,31(a1)
- addiu a1,a1,32
-
- sw t0,0(a0)
- sw t1,4(a0)
- sw t2,8(a0)
- sw t3,12(a0)
- sw t4,16(a0)
- sw t5,20(a0)
- sw t6,24(a0)
- sw t7,28(a0)
- addiu a0,a0,32
-
-.Lua_chk1w:
- andi a2,t8,0x3 # now a2 is the reminder past 1w chunks
- beq a2,t8,.Lua_smallCopy
- subu a3,t8,a2 # a3 is count of bytes in 1w chunks
- addu a3,a0,a3 # now a3 is the dst address past the 1w chunks
-
-# copying in words (4-byte chunks)
-.Lua_wordCopy_loop:
- LWHI v1,0(a1)
- LWLO v1,3(a1)
- addiu a1,a1,4
- addiu a0,a0,4 # note: dst=a0 is word aligned here, see NOTE1
- bne a0,a3,.Lua_wordCopy_loop
- sw v1,-4(a0)
-
-# Now less than 4 bytes (value in a2) left to copy
-.Lua_smallCopy:
- beqz a2,.Lleave
- addu a3,a0,a2 # a3 is the last dst address
-.Lua_smallCopy_loop:
+/* Here we have src and dest word-aligned but less than 64-bytes or
+ * 128 bytes to go. Check for a 32(64) byte chunk and copy if if there
+ * is one. Otherwise jump down to L(ua_chk1w) to handle the tail end of
+ * the copy. */
+
+L(ua_chkw):
+ PREFETCH_FOR_LOAD (0, a1)
+ andi t8,a2,NSIZEMASK /* Is there a 32-byte/64-byte chunk. */
+ /* t8 is the reminder count past 32-bytes */
+ beq a2,t8,L(ua_chk1w) /* When a2=t8, no 32-byte chunk */
+ nop
+ C_LDHI t0,UNIT(0)(a1)
+ C_LDHI t1,UNIT(1)(a1)
+ C_LDHI REG2,UNIT(2)(a1)
+ C_LDHI REG3,UNIT(3)(a1)
+ C_LDHI REG4,UNIT(4)(a1)
+ C_LDHI REG5,UNIT(5)(a1)
+ C_LDHI REG6,UNIT(6)(a1)
+ C_LDHI REG7,UNIT(7)(a1)
+ C_LDLO t0,UNITM1(1)(a1)
+ C_LDLO t1,UNITM1(2)(a1)
+ C_LDLO REG2,UNITM1(3)(a1)
+ C_LDLO REG3,UNITM1(4)(a1)
+ C_LDLO REG4,UNITM1(5)(a1)
+ C_LDLO REG5,UNITM1(6)(a1)
+ C_LDLO REG6,UNITM1(7)(a1)
+ C_LDLO REG7,UNITM1(8)(a1)
+ PTR_ADDIU a1,a1,UNIT(8)
+ C_ST t0,UNIT(0)(a0)
+ C_ST t1,UNIT(1)(a0)
+ C_ST REG2,UNIT(2)(a0)
+ C_ST REG3,UNIT(3)(a0)
+ C_ST REG4,UNIT(4)(a0)
+ C_ST REG5,UNIT(5)(a0)
+ C_ST REG6,UNIT(6)(a0)
+ C_ST REG7,UNIT(7)(a0)
+ PTR_ADDIU a0,a0,UNIT(8)
+/*
+ * Here we have less than 32(64) bytes to copy. Set up for a loop to
+ * copy one word (or double word) at a time.
+ */
+L(ua_chk1w):
+ andi a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */
+ beq a2,t8,L(ua_smallCopy)
+ PTR_SUBU a3,t8,a2 /* a3 is count of bytes in one (d)word chunks */
+ PTR_ADDU a3,a0,a3 /* a3 is the dst address after loop */
+
+/* copying in words (4-byte or 8-byte chunks) */
+L(ua_wordCopy_loop):
+ C_LDHI v1,UNIT(0)(a1)
+ C_LDLO v1,UNITM1(1)(a1)
+ PTR_ADDIU a0,a0,UNIT(1)
+ PTR_ADDIU a1,a1,UNIT(1)
+ bne a0,a3,L(ua_wordCopy_loop)
+ C_ST v1,UNIT(-1)(a0)
+
+/* Copy the last 8 (or 16) bytes */
+L(ua_smallCopy):
+ beqz a2,L(leave)
+ PTR_ADDU a3,a0,a2 /* a3 is the last dst address */
+L(ua_smallCopy_loop):
lb v1,0(a1)
- addiu a1,a1,1
- addiu a0,a0,1
- bne a0,a3,.Lua_smallCopy_loop
- sb v1,-1(a0)
+ PTR_ADDIU a0,a0,1
+ PTR_ADDIU a1,a1,1
+ bne a0,a3,L(ua_smallCopy_loop)
+ sb v1,-1(a0)
j ra
- nop
+ nop
+
+#else /* R6_CODE */
+
+# if __MIPSEB
+# define SWAP_REGS(X,Y) X, Y
+# define ALIGN_OFFSET(N) (N)
+# else
+# define SWAP_REGS(X,Y) Y, X
+# define ALIGN_OFFSET(N) (NSIZE-N)
+# endif
+# define R6_UNALIGNED_WORD_COPY(BYTEOFFSET) \
+ andi REG7, a2, (NSIZE-1);/* REG7 is # of bytes to by bytes. */ \
+ beq REG7, a2, L(lastb); /* Check for bytes to copy by word */ \
+ PTR_SUBU a3, a2, REG7; /* a3 is number of bytes to be copied in */ \
+ /* (d)word chunks. */ \
+ move a2, REG7; /* a2 is # of bytes to copy byte by byte */ \
+ /* after word loop is finished. */ \
+ PTR_ADDU REG6, a0, a3; /* REG6 is the dst address after loop. */ \
+ PTR_SUBU REG2, a1, t8; /* REG2 is the aligned src address. */ \
+ PTR_ADDU a1, a1, a3; /* a1 is addr of source after word loop. */ \
+ C_LD t0, UNIT(0)(REG2); /* Load first part of source. */ \
+L(r6_ua_wordcopy##BYTEOFFSET): \
+ C_LD t1, UNIT(1)(REG2); /* Load second part of source. */ \
+ C_ALIGN REG3, SWAP_REGS(t1,t0), ALIGN_OFFSET(BYTEOFFSET); \
+ PTR_ADDIU a0, a0, UNIT(1); /* Increment destination pointer. */ \
+ PTR_ADDIU REG2, REG2, UNIT(1); /* Increment aligned source pointer.*/ \
+ move t0, t1; /* Move second part of source to first. */ \
+ bne a0, REG6,L(r6_ua_wordcopy##BYTEOFFSET); \
+ C_ST REG3, UNIT(-1)(a0); \
+ j L(lastb); \
+ nop
+
+ /* We are generating R6 code, the destination is 4 byte aligned and
+ the source is not 4 byte aligned. t8 is 1, 2, or 3 depending on the
+ alignment of the source. */
+
+L(r6_unaligned1):
+ R6_UNALIGNED_WORD_COPY(1)
+L(r6_unaligned2):
+ R6_UNALIGNED_WORD_COPY(2)
+L(r6_unaligned3):
+ R6_UNALIGNED_WORD_COPY(3)
+# ifdef USE_DOUBLE
+L(r6_unaligned4):
+ R6_UNALIGNED_WORD_COPY(4)
+L(r6_unaligned5):
+ R6_UNALIGNED_WORD_COPY(5)
+L(r6_unaligned6):
+ R6_UNALIGNED_WORD_COPY(6)
+L(r6_unaligned7):
+ R6_UNALIGNED_WORD_COPY(7)
+# endif
+#endif /* R6_CODE */
.set at
.set reorder
-
-END(memcpy)
-
-
-/************************************************************************
- * Implementation : Static functions
- ************************************************************************/
+END(MEMCPY_NAME)
+#ifndef __ANDROID__
+# ifdef _LIBC
+libc_hidden_builtin_def (MEMCPY_NAME)
+# endif
+#endif
diff --git a/libc/arch-mips/string/memcpy.c b/libc/arch-mips/string/memcpy.c
deleted file mode 100644
index 5551a6d..0000000
--- a/libc/arch-mips/string/memcpy.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/* $OpenBSD: memcpy.c,v 1.1 2014/11/30 19:43:56 deraadt Exp $ */
-/*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <syslog.h>
-
-/*
- * sizeof(word) MUST BE A POWER OF TWO
- * SO THAT wmask BELOW IS ALL ONES
- */
-typedef long word; /* "word" used for optimal copy speed */
-
-#define wsize sizeof(word)
-#define wmask (wsize - 1)
-
-/*
- * Copy a block of memory, not handling overlap.
- */
-void *
-memcpy(void *dst0, const void *src0, size_t length)
-{
- char *dst = dst0;
- const char *src = src0;
- size_t t;
-
- if (length == 0 || dst == src) /* nothing to do */
- goto done;
-
- /*
- * Macros: loop-t-times; and loop-t-times, t>0
- */
-#define TLOOP(s) if (t) TLOOP1(s)
-#define TLOOP1(s) do { s; } while (--t)
-
- /*
- * Copy forward.
- */
- t = (long)src; /* only need low bits */
- if ((t | (long)dst) & wmask) {
- /*
- * Try to align operands. This cannot be done
- * unless the low bits match.
- */
- if ((t ^ (long)dst) & wmask || length < wsize)
- t = length;
- else
- t = wsize - (t & wmask);
- length -= t;
- TLOOP1(*dst++ = *src++);
- }
- /*
- * Copy whole words, then mop up any trailing bytes.
- */
- t = length / wsize;
- TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
- t = length & wmask;
- TLOOP(*dst++ = *src++);
-done:
- return (dst0);
-}
diff --git a/libc/arch-mips/string/memset.S b/libc/arch-mips/string/memset.S
index 09b756b..65bb5b5 100644
--- a/libc/arch-mips/string/memset.S
+++ b/libc/arch-mips/string/memset.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009
+ * Copyright (c) 2013
* MIPS Technologies, Inc., California.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,216 +27,410 @@
* SUCH DAMAGE.
*/
-/************************************************************************
- *
- * memset.S, version "64h" with 1 cache line horizon for "pref 30" and 14 nops
- * Version: "043009"
- *
- ************************************************************************/
+#ifdef __ANDROID__
+# include <private/bionic_asm.h>
+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
+#elif _LIBC
+# include <sysdep.h>
+# include <regdef.h>
+# include <sys/asm.h>
+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
+#elif _COMPILING_NEWLIB
+# include "machine/asm.h"
+# include "machine/regdef.h"
+# define PREFETCH_STORE_HINT PREFETCH_HINT_PREPAREFORSTORE
+#else
+# include <regdef.h>
+# include <sys/asm.h>
+#endif
+/* Check to see if the MIPS architecture we are compiling for supports
+ prefetching. */
-/************************************************************************
- * Include files
- ************************************************************************/
+#if (__mips == 4) || (__mips == 5) || (__mips == 32) || (__mips == 64)
+# ifndef DISABLE_PREFETCH
+# define USE_PREFETCH
+# endif
+#endif
-#include <private/bionic_asm.h>
+#if defined(_MIPS_SIM) && ((_MIPS_SIM == _ABI64) || (_MIPS_SIM == _ABIN32))
+# ifndef DISABLE_DOUBLE
+# define USE_DOUBLE
+# endif
+#endif
-/*
- * This routine could be optimized for MIPS64. The current code only
- * uses MIPS32 instructions.
- */
+#ifndef USE_DOUBLE
+# ifndef DISABLE_DOUBLE_ALIGN
+# define DOUBLE_ALIGN
+# endif
+#endif
-#if defined(__MIPSEB__)
-# define SWHI swl /* high part is left in big-endian */
-# define SWLO swr /* low part is right in big-endian */
+/* Some asm.h files do not have the L macro definition. */
+#ifndef L
+# if _MIPS_SIM == _ABIO32
+# define L(label) $L ## label
+# else
+# define L(label) .L ## label
+# endif
#endif
-#if defined(__MIPSEL__)
-# define SWHI swr /* high part is right in little-endian */
-# define SWLO swl /* low part is left in little-endian */
+/* Some asm.h files do not have the PTR_ADDIU macro definition. */
+#ifndef PTR_ADDIU
+# if _MIPS_SIM == _ABIO32
+# define PTR_ADDIU addiu
+# else
+# define PTR_ADDIU daddiu
+# endif
#endif
-#if !(defined(XGPROF) || defined(XPROF))
-#undef SETUP_GP
-#define SETUP_GP
+/* New R6 instructions that may not be in asm.h. */
+#ifndef PTR_LSA
+# if _MIPS_SIM == _ABIO32
+# define PTR_LSA lsa
+# else
+# define PTR_LSA dlsa
+# endif
#endif
-#ifdef NDEBUG
-#define DBG #
-#else
-#define DBG
+/* Using PREFETCH_HINT_PREPAREFORSTORE instead of PREFETCH_STORE
+ or PREFETCH_STORE_STREAMED offers a large performance advantage
+ but PREPAREFORSTORE has some special restrictions to consider.
+
+ Prefetch with the 'prepare for store' hint does not copy a memory
+ location into the cache, it just allocates a cache line and zeros
+ it out. This means that if you do not write to the entire cache
+ line before writing it out to memory some data will get zero'ed out
+ when the cache line is written back to memory and data will be lost.
+
+ There are ifdef'ed sections of this memcpy to make sure that it does not
+ do prefetches on cache lines that are not going to be completely written.
+ This code is only needed and only used when PREFETCH_STORE_HINT is set to
+ PREFETCH_HINT_PREPAREFORSTORE. This code assumes that cache lines are
+ less than MAX_PREFETCH_SIZE bytes and if the cache line is larger it will
+ not work correctly. */
+
+#ifdef USE_PREFETCH
+# define PREFETCH_HINT_STORE 1
+# define PREFETCH_HINT_STORE_STREAMED 5
+# define PREFETCH_HINT_STORE_RETAINED 7
+# define PREFETCH_HINT_PREPAREFORSTORE 30
+
+/* If we have not picked out what hints to use at this point use the
+ standard load and store prefetch hints. */
+# ifndef PREFETCH_STORE_HINT
+# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE
+# endif
+
+/* We double everything when USE_DOUBLE is true so we do 2 prefetches to
+ get 64 bytes in that case. The assumption is that each individual
+ prefetch brings in 32 bytes. */
+# ifdef USE_DOUBLE
+# define PREFETCH_CHUNK 64
+# define PREFETCH_FOR_STORE(chunk, reg) \
+ pref PREFETCH_STORE_HINT, (chunk)*64(reg); \
+ pref PREFETCH_STORE_HINT, ((chunk)*64)+32(reg)
+# else
+# define PREFETCH_CHUNK 32
+# define PREFETCH_FOR_STORE(chunk, reg) \
+ pref PREFETCH_STORE_HINT, (chunk)*32(reg)
+# endif
+
+/* MAX_PREFETCH_SIZE is the maximum size of a prefetch, it must not be less
+ than PREFETCH_CHUNK, the assumed size of each prefetch. If the real size
+ of a prefetch is greater than MAX_PREFETCH_SIZE and the PREPAREFORSTORE
+ hint is used, the code will not work correctly. If PREPAREFORSTORE is not
+ used than MAX_PREFETCH_SIZE does not matter. */
+# define MAX_PREFETCH_SIZE 128
+/* PREFETCH_LIMIT is set based on the fact that we never use an offset greater
+ than 5 on a STORE prefetch and that a single prefetch can never be larger
+ than MAX_PREFETCH_SIZE. We add the extra 32 when USE_DOUBLE is set because
+ we actually do two prefetches in that case, one 32 bytes after the other. */
+# ifdef USE_DOUBLE
+# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + 32 + MAX_PREFETCH_SIZE
+# else
+# define PREFETCH_LIMIT (5 * PREFETCH_CHUNK) + MAX_PREFETCH_SIZE
+# endif
+
+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE) \
+ && ((PREFETCH_CHUNK * 4) < MAX_PREFETCH_SIZE)
+/* We cannot handle this because the initial prefetches may fetch bytes that
+ are before the buffer being copied. We start copies with an offset
+ of 4 so avoid this situation when using PREPAREFORSTORE. */
+# error "PREFETCH_CHUNK is too large and/or MAX_PREFETCH_SIZE is too small."
+# endif
+#else /* USE_PREFETCH not defined */
+# define PREFETCH_FOR_STORE(offset, reg)
#endif
-LEAF(memset,0)
+#if __mips_isa_rev > 5
+# if (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+# undef PREFETCH_STORE_HINT
+# define PREFETCH_STORE_HINT PREFETCH_HINT_STORE_STREAMED
+# endif
+# define R6_CODE
+#endif
- .set noreorder
- .set noat
+/* Allow the routine to be named something else if desired. */
+#ifndef MEMSET_NAME
+# define MEMSET_NAME memset
+#endif
+
+/* We load/store 64 bits at a time when USE_DOUBLE is true.
+ The C_ prefix stands for CHUNK and is used to avoid macro name
+ conflicts with system header files. */
- addu t0,a0,a2 # t0 is the "past the end" address
- slti AT,a2,4 # is a2 less than 4?
- bne AT,zero,.Llast4 # if yes, go to last4
- move v0,a0 # memset returns the dst pointer
+#ifdef USE_DOUBLE
+# define C_ST sd
+# if __MIPSEB
+# define C_STHI sdl /* high part is left in big-endian */
+# else
+# define C_STHI sdr /* high part is right in little-endian */
+# endif
+#else
+# define C_ST sw
+# if __MIPSEB
+# define C_STHI swl /* high part is left in big-endian */
+# else
+# define C_STHI swr /* high part is right in little-endian */
+# endif
+#endif
- beq a1,zero,.Lset0
- subu v1,zero,a0
+/* Bookkeeping values for 32 vs. 64 bit mode. */
+#ifdef USE_DOUBLE
+# define NSIZE 8
+# define NSIZEMASK 0x3f
+# define NSIZEDMASK 0x7f
+#else
+# define NSIZE 4
+# define NSIZEMASK 0x1f
+# define NSIZEDMASK 0x3f
+#endif
+#define UNIT(unit) ((unit)*NSIZE)
+#define UNITM1(unit) (((unit)*NSIZE)-1)
- # smear byte into 32 bit word
-#if (__mips==32) && (__mips_isa_rev>=2)
- ins a1, a1, 8, 8 # Replicate fill byte into half-word.
- ins a1, a1, 16, 16 # Replicate fill byte into word.
+#ifdef __ANDROID__
+LEAF(MEMSET_NAME,0)
#else
- and a1,0xff
- sll AT,a1,8
- or a1,AT
- sll AT,a1,16
- or a1,AT
-#endif
-
-.Lset0:
- andi v1,v1,0x3 # word-unaligned address?
- beq v1,zero,.Laligned # v1 is the unalignment count
- subu a2,a2,v1
- SWHI a1,0(a0)
- addu a0,a0,v1
-
-# Here we have the "word-aligned" a0 (until the "last4")
-.Laligned:
- andi t8,a2,0x3f # any 64-byte chunks?
- # t8 is the byte count past 64-byte chunks
- beq a2,t8,.Lchk8w # when a2==t8, no 64-byte chunks
- # There will be at most 1 32-byte chunk then
- subu a3,a2,t8 # subtract from a2 the reminder
- # Here a3 counts bytes in 16w chunks
- addu a3,a0,a3 # Now a3 is the final dst after 64-byte chunks
-
-# Find out, if there are any 64-byte chunks after which will be still at least
-# 96 bytes left. The value "96" is calculated as needed buffer for
-# "pref 30,64(a0)" prefetch, which can be used as "pref 30,0(a0)" after
-# incrementing "a0" by 64.
-# For "a2" below 160 there will be no such "pref 30 safe" 64-byte chunk.
-#
- sltiu v1,a2,160
- bgtz v1,.Lloop16w_nopref30 # skip "pref 30,0(a0)"
- subu t7,a2,96 # subtract "pref 30 unsafe" region
- # below we have at least 1 64-byte chunk which is "pref 30 safe"
- andi t6,t7,0x3f # t6 is past "64-byte safe chunks" reminder
- subu t5,t7,t6 # subtract from t7 the reminder
- # Here t5 counts bytes in 16w "safe" chunks
- addu t4,a0,t5 # Now t4 is the dst after 64-byte "safe" chunks
-
-# Don't use "pref 30,0(a0)" for a0 in a "middle" of a cache line
-# pref 30,0(a0)
-# Here we are in the region, where it is safe to use "pref 30,64(a0)"
-.Lloop16w:
- addiu a0,a0,64
- pref 30,-32(a0) # continue setting up the dest, addr 64-32
- sw a1,-64(a0)
- sw a1,-60(a0)
- sw a1,-56(a0)
- sw a1,-52(a0)
- sw a1,-48(a0)
- sw a1,-44(a0)
- sw a1,-40(a0)
- sw a1,-36(a0)
- nop
- nop # the extra nop instructions help to balance
- nop # cycles needed for "store" + "fill" + "evict"
- nop # For 64byte store there are needed 8 fill
- nop # and 8 evict cycles, i.e. at least 32 instr.
- nop
- nop
- pref 30,0(a0) # continue setting up the dest, addr 64-0
- sw a1,-32(a0)
- sw a1,-28(a0)
- sw a1,-24(a0)
- sw a1,-20(a0)
- sw a1,-16(a0)
- sw a1,-12(a0)
- sw a1,-8(a0)
- sw a1,-4(a0)
+LEAF(MEMSET_NAME)
+#endif
+
+ .set nomips16
+ .set noreorder
+/* If the size is less than 2*NSIZE (8 or 16), go to L(lastb). Regardless of
+ size, copy dst pointer to v0 for the return value. */
+ slti t2,a2,(2 * NSIZE)
+ bne t2,zero,L(lastb)
+ move v0,a0
+
+/* If memset value is not zero, we copy it to all the bytes in a 32 or 64
+ bit word. */
+ beq a1,zero,L(set0) /* If memset value is zero no smear */
+ PTR_SUBU a3,zero,a0
nop
+
+ /* smear byte into 32 or 64 bit word */
+#if ((__mips == 64) || (__mips == 32)) && (__mips_isa_rev >= 2)
+# ifdef USE_DOUBLE
+ dins a1, a1, 8, 8 /* Replicate fill byte into half-word. */
+ dins a1, a1, 16, 16 /* Replicate fill byte into word. */
+ dins a1, a1, 32, 32 /* Replicate fill byte into dbl word. */
+# else
+ ins a1, a1, 8, 8 /* Replicate fill byte into half-word. */
+ ins a1, a1, 16, 16 /* Replicate fill byte into word. */
+# endif
+#else
+# ifdef USE_DOUBLE
+ and a1,0xff
+ dsll t2,a1,8
+ or a1,t2
+ dsll t2,a1,16
+ or a1,t2
+ dsll t2,a1,32
+ or a1,t2
+# else
+ and a1,0xff
+ sll t2,a1,8
+ or a1,t2
+ sll t2,a1,16
+ or a1,t2
+# endif
+#endif
+
+/* If the destination address is not aligned do a partial store to get it
+ aligned. If it is already aligned just jump to L(aligned). */
+L(set0):
+#ifndef R6_CODE
+ andi t2,a3,(NSIZE-1) /* word-unaligned address? */
+ beq t2,zero,L(aligned) /* t2 is the unalignment count */
+ PTR_SUBU a2,a2,t2
+ C_STHI a1,0(a0)
+ PTR_ADDU a0,a0,t2
+#else /* R6_CODE */
+ andi t2,a0,(NSIZE-1)
+ lapc t9,L(atable)
+ PTR_LSA t9,t2,t9,2
+ jrc t9
+L(atable):
+ bc L(aligned)
+# ifdef USE_DOUBLE
+ bc L(lb7)
+ bc L(lb6)
+ bc L(lb5)
+ bc L(lb4)
+# endif
+ bc L(lb3)
+ bc L(lb2)
+ bc L(lb1)
+L(lb7):
+ sb a1,6(a0)
+L(lb6):
+ sb a1,5(a0)
+L(lb5):
+ sb a1,4(a0)
+L(lb4):
+ sb a1,3(a0)
+L(lb3):
+ sb a1,2(a0)
+L(lb2):
+ sb a1,1(a0)
+L(lb1):
+ sb a1,0(a0)
+
+ li t9,NSIZE
+ subu t2,t9,t2
+ PTR_SUBU a2,a2,t2
+ PTR_ADDU a0,a0,t2
+#endif /* R6_CODE */
+
+L(aligned):
+/* If USE_DOUBLE is not set we may still want to align the data on a 16
+ byte boundry instead of an 8 byte boundry to maximize the opportunity
+ of proAptiv chips to do memory bonding (combining two sequential 4
+ byte stores into one 8 byte store). We know there are at least 4 bytes
+ left to store or we would have jumped to L(lastb) earlier in the code. */
+#ifdef DOUBLE_ALIGN
+ andi t2,a3,4
+ beq t2,zero,L(double_aligned)
+ PTR_SUBU a2,a2,t2
+ sw a1,0(a0)
+ PTR_ADDU a0,a0,t2
+L(double_aligned):
+#endif
+
+/* Now the destination is aligned to (word or double word) aligned address
+ Set a2 to count how many bytes we have to copy after all the 64/128 byte
+ chunks are copied and a3 to the dest pointer after all the 64/128 byte
+ chunks have been copied. We will loop, incrementing a0 until it equals
+ a3. */
+ andi t8,a2,NSIZEDMASK /* any whole 64-byte/128-byte chunks? */
+ beq a2,t8,L(chkw) /* if a2==t8, no 64-byte/128-byte chunks */
+ PTR_SUBU a3,a2,t8 /* subtract from a2 the reminder */
+ PTR_ADDU a3,a0,a3 /* Now a3 is the final dst after loop */
+
+/* When in the loop we may prefetch with the 'prepare to store' hint,
+ in this case the a0+x should not be past the "t0-32" address. This
+ means: for x=128 the last "safe" a0 address is "t0-160". Alternatively,
+ for x=64 the last "safe" a0 address is "t0-96" In the current version we
+ will use "prefetch hint,128(a0)", so "t0-160" is the limit. */
+#if defined(USE_PREFETCH) \
+ && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+ PTR_ADDU t0,a0,a2 /* t0 is the "past the end" address */
+ PTR_SUBU t9,t0,PREFETCH_LIMIT /* t9 is the "last safe pref" address */
+#endif
+#if defined(USE_PREFETCH) \
+ && (PREFETCH_STORE_HINT != PREFETCH_HINT_PREPAREFORSTORE)
+ PREFETCH_FOR_STORE (1, a0)
+ PREFETCH_FOR_STORE (2, a0)
+ PREFETCH_FOR_STORE (3, a0)
+#endif
+
+L(loop16w):
+#if defined(USE_PREFETCH) \
+ && (PREFETCH_STORE_HINT == PREFETCH_HINT_PREPAREFORSTORE)
+ sltu v1,t9,a0 /* If a0 > t9 don't use next prefetch */
+ bgtz v1,L(skip_pref)
nop
+#endif
+#ifndef R6_CODE
+ PREFETCH_FOR_STORE (4, a0)
+ PREFETCH_FOR_STORE (5, a0)
+#else
+ PREFETCH_FOR_STORE (2, a0)
+#endif
+L(skip_pref):
+ C_ST a1,UNIT(0)(a0)
+ C_ST a1,UNIT(1)(a0)
+ C_ST a1,UNIT(2)(a0)
+ C_ST a1,UNIT(3)(a0)
+ C_ST a1,UNIT(4)(a0)
+ C_ST a1,UNIT(5)(a0)
+ C_ST a1,UNIT(6)(a0)
+ C_ST a1,UNIT(7)(a0)
+ C_ST a1,UNIT(8)(a0)
+ C_ST a1,UNIT(9)(a0)
+ C_ST a1,UNIT(10)(a0)
+ C_ST a1,UNIT(11)(a0)
+ C_ST a1,UNIT(12)(a0)
+ C_ST a1,UNIT(13)(a0)
+ C_ST a1,UNIT(14)(a0)
+ C_ST a1,UNIT(15)(a0)
+ PTR_ADDIU a0,a0,UNIT(16) /* adding 64/128 to dest */
+ bne a0,a3,L(loop16w)
nop
- nop # NOTE: adding 14 nop-s instead of 12 nop-s
- nop # gives better results for "fast" memory
+ move a2,t8
+
+/* Here we have dest word-aligned but less than 64-bytes or 128 bytes to go.
+ Check for a 32(64) byte chunk and copy if if there is one. Otherwise
+ jump down to L(chk1w) to handle the tail end of the copy. */
+L(chkw):
+ andi t8,a2,NSIZEMASK /* is there a 32-byte/64-byte chunk. */
+ /* the t8 is the reminder count past 32-bytes */
+ beq a2,t8,L(chk1w)/* when a2==t8, no 32-byte chunk */
nop
- bne a0,t4,.Lloop16w
- nop
-
- beq a0,a3,.Lchk8w # maybe no more 64-byte chunks?
- nop # this "delayed slot" is useless ...
-
-.Lloop16w_nopref30: # there could be up to 3 "64-byte nopref30" chunks
- addiu a0,a0,64
- sw a1,-64(a0)
- sw a1,-60(a0)
- sw a1,-56(a0)
- sw a1,-52(a0)
- sw a1,-48(a0)
- sw a1,-44(a0)
- sw a1,-40(a0)
- sw a1,-36(a0)
- sw a1,-32(a0)
- sw a1,-28(a0)
- sw a1,-24(a0)
- sw a1,-20(a0)
- sw a1,-16(a0)
- sw a1,-12(a0)
- sw a1,-8(a0)
- bne a0,a3,.Lloop16w_nopref30
- sw a1,-4(a0)
-
-.Lchk8w: # t8 here is the byte count past 64-byte chunks
-
- andi t7,t8,0x1f # is there a 32-byte chunk?
- # the t7 is the reminder count past 32-bytes
- beq t8,t7,.Lchk1w # when t8==t7, no 32-byte chunk
- move a2,t7
+ C_ST a1,UNIT(0)(a0)
+ C_ST a1,UNIT(1)(a0)
+ C_ST a1,UNIT(2)(a0)
+ C_ST a1,UNIT(3)(a0)
+ C_ST a1,UNIT(4)(a0)
+ C_ST a1,UNIT(5)(a0)
+ C_ST a1,UNIT(6)(a0)
+ C_ST a1,UNIT(7)(a0)
+ PTR_ADDIU a0,a0,UNIT(8)
- sw a1,0(a0)
- sw a1,4(a0)
- sw a1,8(a0)
- sw a1,12(a0)
- sw a1,16(a0)
- sw a1,20(a0)
- sw a1,24(a0)
- sw a1,28(a0)
- addiu a0,a0,32
-
-.Lchk1w:
- andi t8,a2,0x3 # now t8 is the reminder past 1w chunks
- beq a2,t8,.Llast4aligned
- subu a3,a2,t8 # a3 is the count of bytes in 1w chunks
- addu a3,a0,a3 # now a3 is the dst address past the 1w chunks
-
-# copying in words (4-byte chunks)
-.LwordCopy_loop:
- addiu a0,a0,4
- bne a0,a3,.LwordCopy_loop
- sw a1,-4(a0)
-
-# store last 0-3 bytes
-# this will repeat the last store if the memset finishes on a word boundary
-.Llast4aligned:
- j ra
- SWLO a1,-1(t0)
-
-.Llast4:
- beq a0,t0,.Llast4e
-.Llast4l:
- addiu a0,a0,1
- bne a0,t0,.Llast4l
- sb a1,-1(a0)
-.Llast4e:
+/* Here we have less than 32(64) bytes to set. Set up for a loop to
+ copy one word (or double word) at a time. Set a2 to count how many
+ bytes we have to copy after all the word (or double word) chunks are
+ copied and a3 to the dest pointer after all the (d)word chunks have
+ been copied. We will loop, incrementing a0 until a0 equals a3. */
+L(chk1w):
+ andi a2,t8,(NSIZE-1) /* a2 is the reminder past one (d)word chunks */
+ beq a2,t8,L(lastb)
+ PTR_SUBU a3,t8,a2 /* a3 is count of bytes in one (d)word chunks */
+ PTR_ADDU a3,a0,a3 /* a3 is the dst address after loop */
+
+/* copying in words (4-byte or 8 byte chunks) */
+L(wordCopy_loop):
+ PTR_ADDIU a0,a0,UNIT(1)
+ bne a0,a3,L(wordCopy_loop)
+ C_ST a1,UNIT(-1)(a0)
+
+/* Copy the last 8 (or 16) bytes */
+L(lastb):
+ blez a2,L(leave)
+ PTR_ADDU a3,a0,a2 /* a3 is the last dst address */
+L(lastbloop):
+ PTR_ADDIU a0,a0,1
+ bne a0,a3,L(lastbloop)
+ sb a1,-1(a0)
+L(leave):
j ra
- nop
+ nop
.set at
.set reorder
-
-END(memset)
-
-
-/************************************************************************
- * Implementation : Static functions
- ************************************************************************/
+END(MEMSET_NAME)
+#ifndef __ANDROID__
+# ifdef _LIBC
+libc_hidden_builtin_def (MEMSET_NAME)
+# endif
+#endif
diff --git a/libc/arch-mips/string/strcmp.S b/libc/arch-mips/string/strcmp.S
new file mode 100644
index 0000000..2b67f5a
--- /dev/null
+++ b/libc/arch-mips/string/strcmp.S
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2014
+ * Imagination Technologies Limited.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY IMAGINATION TECHNOLOGIES LIMITED ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL IMAGINATION TECHNOLOGIES LIMITED BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef __ANDROID__
+# include <private/bionic_asm.h>
+#elif _LIBC
+# include <sysdep.h>
+# include <regdef.h>
+# include <sys/asm.h>
+#elif _COMPILING_NEWLIB
+# include "machine/asm.h"
+# include "machine/regdef.h"
+#else
+# include <regdef.h>
+# include <sys/asm.h>
+#endif
+
+/* Technically strcmp should not read past the end of the strings being
+ compared. We will read a full word that may contain excess bits beyond
+ the NULL string terminator but unless ENABLE_READAHEAD is set, we will not
+ read the next word after the end of string. Setting ENABLE_READAHEAD will
+ improve performance but is technically illegal based on the definition of
+ strcmp. */
+#ifdef ENABLE_READAHEAD
+# define DELAY_READ
+#else
+# define DELAY_READ nop
+#endif
+
+/* Testing on a little endian machine showed using CLZ was a
+ performance loss, so we are not turning it on by default. */
+#if defined(ENABLE_CLZ) && (__mips_isa_rev > 1)
+# define USE_CLZ
+#endif
+
+/* Some asm.h files do not have the L macro definition. */
+#ifndef L
+# if _MIPS_SIM == _ABIO32
+# define L(label) $L ## label
+# else
+# define L(label) .L ## label
+# endif
+#endif
+
+/* Some asm.h files do not have the PTR_ADDIU macro definition. */
+#ifndef PTR_ADDIU
+# if _MIPS_SIM == _ABIO32
+# define PTR_ADDIU addiu
+# else
+# define PTR_ADDIU daddiu
+# endif
+#endif
+
+/* Allow the routine to be named something else if desired. */
+#ifndef STRCMP_NAME
+# define STRCMP_NAME strcmp
+#endif
+
+#ifdef __ANDROID__
+LEAF(STRCMP_NAME, 0)
+#else
+LEAF(STRCMP_NAME)
+#endif
+ .set nomips16
+ .set noreorder
+
+ or t0, a0, a1
+ andi t0,0x3
+ bne t0, zero, L(byteloop)
+
+/* Both strings are 4 byte aligned at this point. */
+
+ lui t8, 0x0101
+ ori t8, t8, 0x0101
+ lui t9, 0x7f7f
+ ori t9, 0x7f7f
+
+#define STRCMP32(OFFSET) \
+ lw v0, OFFSET(a0); \
+ lw v1, OFFSET(a1); \
+ subu t0, v0, t8; \
+ bne v0, v1, L(worddiff); \
+ nor t1, v0, t9; \
+ and t0, t0, t1; \
+ bne t0, zero, L(returnzero)
+
+L(wordloop):
+ STRCMP32(0)
+ DELAY_READ
+ STRCMP32(4)
+ DELAY_READ
+ STRCMP32(8)
+ DELAY_READ
+ STRCMP32(12)
+ DELAY_READ
+ STRCMP32(16)
+ DELAY_READ
+ STRCMP32(20)
+ DELAY_READ
+ STRCMP32(24)
+ DELAY_READ
+ STRCMP32(28)
+ PTR_ADDIU a0, a0, 32
+ b L(wordloop)
+ PTR_ADDIU a1, a1, 32
+
+L(returnzero):
+ j ra
+ move v0, zero
+
+L(worddiff):
+#ifdef USE_CLZ
+ subu t0, v0, t8
+ nor t1, v0, t9
+ and t1, t0, t1
+ xor t0, v0, v1
+ or t0, t0, t1
+# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ wsbh t0, t0
+ rotr t0, t0, 16
+# endif
+ clz t1, t0
+ and t1, 0xf8
+# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ neg t1
+ addu t1, 24
+# endif
+ rotrv v0, v0, t1
+ rotrv v1, v1, t1
+ and v0, v0, 0xff
+ and v1, v1, 0xff
+ j ra
+ subu v0, v0, v1
+#else /* USE_CLZ */
+# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ andi t0, v0, 0xff
+ beq t0, zero, L(wexit01)
+ andi t1, v1, 0xff
+ bne t0, t1, L(wexit01)
+
+ srl t8, v0, 8
+ srl t9, v1, 8
+ andi t8, t8, 0xff
+ beq t8, zero, L(wexit89)
+ andi t9, t9, 0xff
+ bne t8, t9, L(wexit89)
+
+ srl t0, v0, 16
+ srl t1, v1, 16
+ andi t0, t0, 0xff
+ beq t0, zero, L(wexit01)
+ andi t1, t1, 0xff
+ bne t0, t1, L(wexit01)
+
+ srl t8, v0, 24
+ srl t9, v1, 24
+# else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
+ srl t0, v0, 24
+ beq t0, zero, L(wexit01)
+ srl t1, v1, 24
+ bne t0, t1, L(wexit01)
+
+ srl t8, v0, 16
+ srl t9, v1, 16
+ andi t8, t8, 0xff
+ beq t8, zero, L(wexit89)
+ andi t9, t9, 0xff
+ bne t8, t9, L(wexit89)
+
+ srl t0, v0, 8
+ srl t1, v1, 8
+ andi t0, t0, 0xff
+ beq t0, zero, L(wexit01)
+ andi t1, t1, 0xff
+ bne t0, t1, L(wexit01)
+
+ andi t8, v0, 0xff
+ andi t9, v1, 0xff
+# endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
+
+L(wexit89):
+ j ra
+ subu v0, t8, t9
+L(wexit01):
+ j ra
+ subu v0, t0, t1
+#endif /* USE_CLZ */
+
+/* It might seem better to do the 'beq' instruction between the two 'lbu'
+ instructions so that the nop is not needed but testing showed that this
+ code is actually faster (based on glibc strcmp test). */
+#define BYTECMP01(OFFSET) \
+ lbu v0, OFFSET(a0); \
+ lbu v1, OFFSET(a1); \
+ beq v0, zero, L(bexit01); \
+ nop; \
+ bne v0, v1, L(bexit01)
+
+#define BYTECMP89(OFFSET) \
+ lbu t8, OFFSET(a0); \
+ lbu t9, OFFSET(a1); \
+ beq t8, zero, L(bexit89); \
+ nop; \
+ bne t8, t9, L(bexit89)
+
+L(byteloop):
+ BYTECMP01(0)
+ BYTECMP89(1)
+ BYTECMP01(2)
+ BYTECMP89(3)
+ BYTECMP01(4)
+ BYTECMP89(5)
+ BYTECMP01(6)
+ BYTECMP89(7)
+ PTR_ADDIU a0, a0, 8
+ b L(byteloop)
+ PTR_ADDIU a1, a1, 8
+
+L(bexit01):
+ j ra
+ subu v0, v0, v1
+L(bexit89):
+ j ra
+ subu v0, t8, t9
+
+ .set at
+ .set reorder
+
+END(STRCMP_NAME)
+#ifndef __ANDROID__
+# ifdef _LIBC
+libc_hidden_builtin_def (STRCMP_NAME)
+# endif
+#endif
diff --git a/libc/arch-mips/syscalls/__clock_nanosleep.S b/libc/arch-mips/syscalls/___clock_nanosleep.S
index 97bfa27..4879489 100644
--- a/libc/arch-mips/syscalls/__clock_nanosleep.S
+++ b/libc/arch-mips/syscalls/___clock_nanosleep.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__clock_nanosleep)
+ENTRY(___clock_nanosleep)
.set noreorder
.cpload t9
li v0, __NR_clock_nanosleep
@@ -16,4 +16,5 @@ ENTRY(__clock_nanosleep)
j t9
nop
.set reorder
-END(__clock_nanosleep)
+END(___clock_nanosleep)
+.hidden ___clock_nanosleep
diff --git a/libc/arch-mips/syscalls/fgetxattr.S b/libc/arch-mips/syscalls/___fgetxattr.S
index 6516feb..50ab69c 100644
--- a/libc/arch-mips/syscalls/fgetxattr.S
+++ b/libc/arch-mips/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
.set noreorder
.cpload t9
li v0, __NR_fgetxattr
@@ -16,4 +16,5 @@ ENTRY(fgetxattr)
j t9
nop
.set reorder
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-mips/syscalls/fsetxattr.S b/libc/arch-mips/syscalls/___fsetxattr.S
index 663c0df..0312921 100644
--- a/libc/arch-mips/syscalls/fsetxattr.S
+++ b/libc/arch-mips/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
.set noreorder
.cpload t9
li v0, __NR_fsetxattr
@@ -16,4 +16,5 @@ ENTRY(fsetxattr)
j t9
nop
.set reorder
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-mips/syscalls/__rt_sigqueueinfo.S b/libc/arch-mips/syscalls/___rt_sigqueueinfo.S
index a978bc4..95af36f 100644
--- a/libc/arch-mips/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-mips/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
.set noreorder
.cpload t9
li v0, __NR_rt_sigqueueinfo
@@ -16,4 +16,5 @@ ENTRY(__rt_sigqueueinfo)
j t9
nop
.set reorder
-END(__rt_sigqueueinfo)
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-mips/syscalls/ftruncate.S b/libc/arch-mips/syscalls/process_vm_readv.S
index 0589c81..22b74f0 100644
--- a/libc/arch-mips/syscalls/ftruncate.S
+++ b/libc/arch-mips/syscalls/process_vm_readv.S
@@ -2,10 +2,10 @@
#include <private/bionic_asm.h>
-ENTRY(ftruncate)
+ENTRY(process_vm_readv)
.set noreorder
.cpload t9
- li v0, __NR_ftruncate
+ li v0, __NR_process_vm_readv
syscall
bnez a3, 1f
move a0, v0
@@ -16,4 +16,4 @@ ENTRY(ftruncate)
j t9
nop
.set reorder
-END(ftruncate)
+END(process_vm_readv)
diff --git a/libc/arch-mips/syscalls/process_vm_writev.S b/libc/arch-mips/syscalls/process_vm_writev.S
new file mode 100644
index 0000000..dd1dc4b
--- /dev/null
+++ b/libc/arch-mips/syscalls/process_vm_writev.S
@@ -0,0 +1,19 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_writev)
+ .set noreorder
+ .cpload t9
+ li v0, __NR_process_vm_writev
+ syscall
+ bnez a3, 1f
+ move a0, v0
+ j ra
+ nop
+1:
+ la t9,__set_errno_internal
+ j t9
+ nop
+ .set reorder
+END(process_vm_writev)
diff --git a/libc/arch-mips64/bionic/stat.cpp b/libc/arch-mips64/bionic/stat.cpp
index 2767fbd..29a50ed 100644
--- a/libc/arch-mips64/bionic/stat.cpp
+++ b/libc/arch-mips64/bionic/stat.cpp
@@ -32,29 +32,28 @@
#include <unistd.h>
struct kernel_stat {
- unsigned int st_dev;
- unsigned int st_pad0[3];
- unsigned long st_ino;
- mode_t st_mode;
- __u32 st_nlink;
- uid_t st_uid;
- gid_t st_gid;
- unsigned int st_rdev;
- unsigned int st_pad1[3];
- __kernel_off_t st_size;
- unsigned int _st_atime;
- unsigned int st_atime_nsec;
- unsigned int _st_mtime;
- unsigned int st_mtime_nsec;
- unsigned int _st_ctime;
- unsigned int st_ctime_nsec;
- unsigned int st_blksize;
- unsigned int st_pad2;
- unsigned long st_blocks;
+ unsigned int st_dev;
+ unsigned int st_pad0[3];
+ unsigned long st_ino;
+ mode_t st_mode;
+ __u32 st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ unsigned int st_rdev;
+ unsigned int st_pad1[3];
+ __kernel_off_t st_size;
+ unsigned int _st_atime;
+ unsigned int st_atime_nsec;
+ unsigned int _st_mtime;
+ unsigned int st_mtime_nsec;
+ unsigned int _st_ctime;
+ unsigned int st_ctime_nsec;
+ unsigned int st_blksize;
+ unsigned int st_pad2;
+ unsigned long st_blocks;
};
-void copy_stat(struct stat *st, struct kernel_stat *s)
-{
+static void copy_stat(struct stat* st, struct kernel_stat* s) {
st->st_dev = static_cast<dev_t>(s->st_dev);
st->st_ino = static_cast<ino_t>(s->st_ino);
st->st_mode = static_cast<mode_t>(s->st_mode);
@@ -73,30 +72,17 @@ void copy_stat(struct stat *st, struct kernel_stat *s)
st->st_ctim.tv_nsec = static_cast<long>(s->st_ctime_nsec);
}
-int fstat(int fp, struct stat *st)
-{
+int fstat(int fp, struct stat* st) {
kernel_stat s;
- int ret;
- ret = syscall (__NR_fstat, fp, &s);
- copy_stat (st, &s);
+ int ret = syscall(__NR_fstat, fp, &s);
+ copy_stat(st, &s);
return ret;
}
__strong_alias(fstat64, fstat);
-int newfstatat(int dirfd, const char *pathname, struct stat *buf, int flags)
-{
+int fstatat(int dirfd, const char* pathname, struct stat* buf, int flags) {
kernel_stat s;
- int ret;
- ret = syscall(__NR_newfstatat, dirfd, pathname, &s, flags);
- copy_stat(buf, &s);
- return ret;
-}
-
-int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags)
-{
- kernel_stat s;
- int ret;
- ret = syscall(__NR_newfstatat, dirfd, pathname, &s, flags);
+ int ret = syscall(__NR_newfstatat, dirfd, pathname, &s, flags);
copy_stat(buf, &s);
return ret;
}
diff --git a/libc/arch-mips64/mips64.mk b/libc/arch-mips64/mips64.mk
index 2b81e63..7757385 100644
--- a/libc/arch-mips64/mips64.mk
+++ b/libc/arch-mips64/mips64.mk
@@ -5,6 +5,11 @@
#
libc_bionic_src_files_mips64 += \
+ arch-mips/string/memcmp.c \
+ arch-mips/string/memcpy.S \
+ arch-mips/string/memset.S \
+ arch-mips/string/strcmp.S \
+ arch-mips/string/strlen.c \
bionic/__memcpy_chk.cpp \
bionic/__memset_chk.cpp \
bionic/__strcpy_chk.cpp \
@@ -12,10 +17,6 @@ libc_bionic_src_files_mips64 += \
bionic/strchr.cpp \
bionic/strnlen.c \
bionic/strrchr.cpp \
- arch-mips/string/memcmp.c \
- arch-mips/string/memcpy.c \
- arch-mips/string/memset.c \
- arch-mips/string/strlen.c \
libc_freebsd_src_files_mips64 += \
upstream-freebsd/lib/libc/string/wcscat.c \
@@ -34,7 +35,6 @@ libc_openbsd_src_files_mips64 += \
upstream-openbsd/lib/libc/string/stpcpy.c \
upstream-openbsd/lib/libc/string/stpncpy.c \
upstream-openbsd/lib/libc/string/strcat.c \
- upstream-openbsd/lib/libc/string/strcmp.c \
upstream-openbsd/lib/libc/string/strcpy.c \
upstream-openbsd/lib/libc/string/strlcat.c \
upstream-openbsd/lib/libc/string/strlcpy.c \
diff --git a/libc/arch-mips64/string/memcpy.S b/libc/arch-mips64/string/memcpy.S
deleted file mode 100644
index dc91096..0000000
--- a/libc/arch-mips64/string/memcpy.S
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * Copyright (c) 2009
- * MIPS Technologies, Inc., California.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/************************************************************************
- *
- * memcpy.S
- * Version: "043009"
- *
- ************************************************************************/
-
-
-/************************************************************************
- * Include files
- ************************************************************************/
-
-#include <private/bionic_asm.h>
-
-
-/*
- * This routine could be optimized for MIPS64. The current code only
- * uses MIPS32 instructions.
- */
-#if defined(__MIPSEB__)
-# define LWHI lwl /* high part is left in big-endian */
-# define SWHI swl /* high part is left in big-endian */
-# define LWLO lwr /* low part is right in big-endian */
-# define SWLO swr /* low part is right in big-endian */
-#endif
-
-#if defined(__MIPSEL__)
-# define LWHI lwr /* high part is right in little-endian */
-# define SWHI swr /* high part is right in little-endian */
-# define LWLO lwl /* low part is left in big-endian */
-# define SWLO swl /* low part is left in big-endian */
-#endif
-
-LEAF(memcpy,0)
-
- .set noreorder
- .set noat
-/*
- * Below we handle the case where memcpy is called with overlapping src and dst.
- * Although memcpy is not required to handle this case, some parts of Android like Skia
- * rely on such usage. We call memmove to handle such cases.
- */
- subu t0,a0,a1
- sra AT,t0,31
- xor t1,t0,AT
- subu t0,t1,AT
- sltu AT,t0,a2
- beq AT,zero,.Lmemcpy
- la t9,memmove
- jr t9
- nop
-.Lmemcpy:
- slti AT,a2,8
- bne AT,zero,.Llast8
- move v0,a0 # memcpy returns the dst pointer
-
-# Test if the src and dst are word-aligned, or can be made word-aligned
- xor t8,a1,a0
- andi t8,t8,0x3 # t8 is a0/a1 word-displacement
-
- bne t8,zero,.Lunaligned
- negu a3,a0
-
- andi a3,a3,0x3 # we need to copy a3 bytes to make a0/a1 aligned
- beq a3,zero,.Lchk16w # when a3=0 then the dst (a0) is word-aligned
- subu a2,a2,a3 # now a2 is the remining bytes count
-
- LWHI t8,0(a1)
- addu a1,a1,a3
- SWHI t8,0(a0)
- addu a0,a0,a3
-
-# Now the dst/src are mutually word-aligned with word-aligned addresses
-.Lchk16w:
- andi t8,a2,0x3f # any whole 64-byte chunks?
- # t8 is the byte count after 64-byte chunks
-
- beq a2,t8,.Lchk8w # if a2==t8, no 64-byte chunks
- # There will be at most 1 32-byte chunk after it
- subu a3,a2,t8 # subtract from a2 the reminder
- # Here a3 counts bytes in 16w chunks
- addu a3,a0,a3 # Now a3 is the final dst after 64-byte chunks
-
- addu t0,a0,a2 # t0 is the "past the end" address
-
-# When in the loop we exercise "pref 30,x(a0)", the a0+x should not be past
-# the "t0-32" address
-# This means: for x=128 the last "safe" a0 address is "t0-160"
-# Alternatively, for x=64 the last "safe" a0 address is "t0-96"
-# In the current version we will use "pref 30,128(a0)", so "t0-160" is the limit
- subu t9,t0,160 # t9 is the "last safe pref 30,128(a0)" address
-
- pref 0,0(a1) # bring the first line of src, addr 0
- pref 0,32(a1) # bring the second line of src, addr 32
- pref 0,64(a1) # bring the third line of src, addr 64
- pref 30,32(a0) # safe, as we have at least 64 bytes ahead
-# In case the a0 > t9 don't use "pref 30" at all
- sgtu v1,a0,t9
- bgtz v1,.Lloop16w # skip "pref 30,64(a0)" for too short arrays
- nop
-# otherwise, start with using pref30
- pref 30,64(a0)
-.Lloop16w:
- pref 0,96(a1)
- lw t0,0(a1)
- bgtz v1,.Lskip_pref30_96 # skip "pref 30,96(a0)"
- lw t1,4(a1)
- pref 30,96(a0) # continue setting up the dest, addr 96
-.Lskip_pref30_96:
- lw t2,8(a1)
- lw t3,12(a1)
- lw t4,16(a1)
- lw t5,20(a1)
- lw t6,24(a1)
- lw t7,28(a1)
- pref 0,128(a1) # bring the next lines of src, addr 128
-
- sw t0,0(a0)
- sw t1,4(a0)
- sw t2,8(a0)
- sw t3,12(a0)
- sw t4,16(a0)
- sw t5,20(a0)
- sw t6,24(a0)
- sw t7,28(a0)
-
- lw t0,32(a1)
- bgtz v1,.Lskip_pref30_128 # skip "pref 30,128(a0)"
- lw t1,36(a1)
- pref 30,128(a0) # continue setting up the dest, addr 128
-.Lskip_pref30_128:
- lw t2,40(a1)
- lw t3,44(a1)
- lw t4,48(a1)
- lw t5,52(a1)
- lw t6,56(a1)
- lw t7,60(a1)
- pref 0, 160(a1) # bring the next lines of src, addr 160
-
- sw t0,32(a0)
- sw t1,36(a0)
- sw t2,40(a0)
- sw t3,44(a0)
- sw t4,48(a0)
- sw t5,52(a0)
- sw t6,56(a0)
- sw t7,60(a0)
-
- addiu a0,a0,64 # adding 64 to dest
- sgtu v1,a0,t9
- bne a0,a3,.Lloop16w
- addiu a1,a1,64 # adding 64 to src
- move a2,t8
-
-# Here we have src and dest word-aligned but less than 64-bytes to go
-
-.Lchk8w:
- pref 0, 0x0(a1)
- andi t8,a2,0x1f # is there a 32-byte chunk?
- # the t8 is the reminder count past 32-bytes
- beq a2,t8,.Lchk1w # when a2=t8, no 32-byte chunk
- nop
-
- lw t0,0(a1)
- lw t1,4(a1)
- lw t2,8(a1)
- lw t3,12(a1)
- lw t4,16(a1)
- lw t5,20(a1)
- lw t6,24(a1)
- lw t7,28(a1)
- addiu a1,a1,32
-
- sw t0,0(a0)
- sw t1,4(a0)
- sw t2,8(a0)
- sw t3,12(a0)
- sw t4,16(a0)
- sw t5,20(a0)
- sw t6,24(a0)
- sw t7,28(a0)
- addiu a0,a0,32
-
-.Lchk1w:
- andi a2,t8,0x3 # now a2 is the reminder past 1w chunks
- beq a2,t8,.Llast8
- subu a3,t8,a2 # a3 is count of bytes in 1w chunks
- addu a3,a0,a3 # now a3 is the dst address past the 1w chunks
-
-# copying in words (4-byte chunks)
-.LwordCopy_loop:
- lw t3,0(a1) # the first t3 may be equal t0 ... optimize?
- addiu a1,a1,4
- addiu a0,a0,4
- bne a0,a3,.LwordCopy_loop
- sw t3,-4(a0)
-
-# For the last (<8) bytes
-.Llast8:
- blez a2,.Lleave
- addu a3,a0,a2 # a3 is the last dst address
-.Llast8loop:
- lb v1,0(a1)
- addiu a1,a1,1
- addiu a0,a0,1
- bne a0,a3,.Llast8loop
- sb v1,-1(a0)
-
-.Lleave:
- j ra
- nop
-
-#
-# UNALIGNED case
-#
-
-.Lunaligned:
- # got here with a3="negu a0"
- andi a3,a3,0x3 # test if the a0 is word aligned
- beqz a3,.Lua_chk16w
- subu a2,a2,a3 # bytes left after initial a3 bytes
-
- LWHI v1,0(a1)
- LWLO v1,3(a1)
- addu a1,a1,a3 # a3 may be here 1, 2 or 3
- SWHI v1,0(a0)
- addu a0,a0,a3 # below the dst will be word aligned (NOTE1)
-
-.Lua_chk16w:
- andi t8,a2,0x3f # any whole 64-byte chunks?
- # t8 is the byte count after 64-byte chunks
- beq a2,t8,.Lua_chk8w # if a2==t8, no 64-byte chunks
- # There will be at most 1 32-byte chunk after it
- subu a3,a2,t8 # subtract from a2 the reminder
- # Here a3 counts bytes in 16w chunks
- addu a3,a0,a3 # Now a3 is the final dst after 64-byte chunks
-
- addu t0,a0,a2 # t0 is the "past the end" address
-
- subu t9,t0,160 # t9 is the "last safe pref 30,128(a0)" address
-
- pref 0,0(a1) # bring the first line of src, addr 0
- pref 0,32(a1) # bring the second line of src, addr 32
- pref 0,64(a1) # bring the third line of src, addr 64
- pref 30,32(a0) # safe, as we have at least 64 bytes ahead
-# In case the a0 > t9 don't use "pref 30" at all
- sgtu v1,a0,t9
- bgtz v1,.Lua_loop16w # skip "pref 30,64(a0)" for too short arrays
- nop
-# otherwise, start with using pref30
- pref 30,64(a0)
-.Lua_loop16w:
- pref 0,96(a1)
- LWHI t0,0(a1)
- LWLO t0,3(a1)
- LWHI t1,4(a1)
- bgtz v1,.Lua_skip_pref30_96
- LWLO t1,7(a1)
- pref 30,96(a0) # continue setting up the dest, addr 96
-.Lua_skip_pref30_96:
- LWHI t2,8(a1)
- LWLO t2,11(a1)
- LWHI t3,12(a1)
- LWLO t3,15(a1)
- LWHI t4,16(a1)
- LWLO t4,19(a1)
- LWHI t5,20(a1)
- LWLO t5,23(a1)
- LWHI t6,24(a1)
- LWLO t6,27(a1)
- LWHI t7,28(a1)
- LWLO t7,31(a1)
- pref 0,128(a1) # bring the next lines of src, addr 128
-
- sw t0,0(a0)
- sw t1,4(a0)
- sw t2,8(a0)
- sw t3,12(a0)
- sw t4,16(a0)
- sw t5,20(a0)
- sw t6,24(a0)
- sw t7,28(a0)
-
- LWHI t0,32(a1)
- LWLO t0,35(a1)
- LWHI t1,36(a1)
- bgtz v1,.Lua_skip_pref30_128
- LWLO t1,39(a1)
- pref 30,128(a0) # continue setting up the dest, addr 128
-.Lua_skip_pref30_128:
- LWHI t2,40(a1)
- LWLO t2,43(a1)
- LWHI t3,44(a1)
- LWLO t3,47(a1)
- LWHI t4,48(a1)
- LWLO t4,51(a1)
- LWHI t5,52(a1)
- LWLO t5,55(a1)
- LWHI t6,56(a1)
- LWLO t6,59(a1)
- LWHI t7,60(a1)
- LWLO t7,63(a1)
- pref 0, 160(a1) # bring the next lines of src, addr 160
-
- sw t0,32(a0)
- sw t1,36(a0)
- sw t2,40(a0)
- sw t3,44(a0)
- sw t4,48(a0)
- sw t5,52(a0)
- sw t6,56(a0)
- sw t7,60(a0)
-
- addiu a0,a0,64 # adding 64 to dest
- sgtu v1,a0,t9
- bne a0,a3,.Lua_loop16w
- addiu a1,a1,64 # adding 64 to src
- move a2,t8
-
-# Here we have src and dest word-aligned but less than 64-bytes to go
-
-.Lua_chk8w:
- pref 0, 0x0(a1)
- andi t8,a2,0x1f # is there a 32-byte chunk?
- # the t8 is the reminder count
- beq a2,t8,.Lua_chk1w # when a2=t8, no 32-byte chunk
- nop
-
- LWHI t0,0(a1)
- LWLO t0,3(a1)
- LWHI t1,4(a1)
- LWLO t1,7(a1)
- LWHI t2,8(a1)
- LWLO t2,11(a1)
- LWHI t3,12(a1)
- LWLO t3,15(a1)
- LWHI t4,16(a1)
- LWLO t4,19(a1)
- LWHI t5,20(a1)
- LWLO t5,23(a1)
- LWHI t6,24(a1)
- LWLO t6,27(a1)
- LWHI t7,28(a1)
- LWLO t7,31(a1)
- addiu a1,a1,32
-
- sw t0,0(a0)
- sw t1,4(a0)
- sw t2,8(a0)
- sw t3,12(a0)
- sw t4,16(a0)
- sw t5,20(a0)
- sw t6,24(a0)
- sw t7,28(a0)
- addiu a0,a0,32
-
-.Lua_chk1w:
- andi a2,t8,0x3 # now a2 is the reminder past 1w chunks
- beq a2,t8,.Lua_smallCopy
- subu a3,t8,a2 # a3 is count of bytes in 1w chunks
- addu a3,a0,a3 # now a3 is the dst address past the 1w chunks
-
-# copying in words (4-byte chunks)
-.Lua_wordCopy_loop:
- LWHI v1,0(a1)
- LWLO v1,3(a1)
- addiu a1,a1,4
- addiu a0,a0,4 # note: dst=a0 is word aligned here, see NOTE1
- bne a0,a3,.Lua_wordCopy_loop
- sw v1,-4(a0)
-
-# Now less than 4 bytes (value in a2) left to copy
-.Lua_smallCopy:
- beqz a2,.Lleave
- addu a3,a0,a2 # a3 is the last dst address
-.Lua_smallCopy_loop:
- lb v1,0(a1)
- addiu a1,a1,1
- addiu a0,a0,1
- bne a0,a3,.Lua_smallCopy_loop
- sb v1,-1(a0)
-
- j ra
- nop
-
- .set at
- .set reorder
-
-END(memcpy)
-
-
-/************************************************************************
- * Implementation : Static functions
- ************************************************************************/
diff --git a/libc/arch-mips64/string/memset.S b/libc/arch-mips64/string/memset.S
deleted file mode 100644
index 09b756b..0000000
--- a/libc/arch-mips64/string/memset.S
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (c) 2009
- * MIPS Technologies, Inc., California.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/************************************************************************
- *
- * memset.S, version "64h" with 1 cache line horizon for "pref 30" and 14 nops
- * Version: "043009"
- *
- ************************************************************************/
-
-
-/************************************************************************
- * Include files
- ************************************************************************/
-
-#include <private/bionic_asm.h>
-
-/*
- * This routine could be optimized for MIPS64. The current code only
- * uses MIPS32 instructions.
- */
-
-#if defined(__MIPSEB__)
-# define SWHI swl /* high part is left in big-endian */
-# define SWLO swr /* low part is right in big-endian */
-#endif
-
-#if defined(__MIPSEL__)
-# define SWHI swr /* high part is right in little-endian */
-# define SWLO swl /* low part is left in little-endian */
-#endif
-
-#if !(defined(XGPROF) || defined(XPROF))
-#undef SETUP_GP
-#define SETUP_GP
-#endif
-
-#ifdef NDEBUG
-#define DBG #
-#else
-#define DBG
-#endif
-
-LEAF(memset,0)
-
- .set noreorder
- .set noat
-
- addu t0,a0,a2 # t0 is the "past the end" address
- slti AT,a2,4 # is a2 less than 4?
- bne AT,zero,.Llast4 # if yes, go to last4
- move v0,a0 # memset returns the dst pointer
-
- beq a1,zero,.Lset0
- subu v1,zero,a0
-
- # smear byte into 32 bit word
-#if (__mips==32) && (__mips_isa_rev>=2)
- ins a1, a1, 8, 8 # Replicate fill byte into half-word.
- ins a1, a1, 16, 16 # Replicate fill byte into word.
-#else
- and a1,0xff
- sll AT,a1,8
- or a1,AT
- sll AT,a1,16
- or a1,AT
-#endif
-
-.Lset0:
- andi v1,v1,0x3 # word-unaligned address?
- beq v1,zero,.Laligned # v1 is the unalignment count
- subu a2,a2,v1
- SWHI a1,0(a0)
- addu a0,a0,v1
-
-# Here we have the "word-aligned" a0 (until the "last4")
-.Laligned:
- andi t8,a2,0x3f # any 64-byte chunks?
- # t8 is the byte count past 64-byte chunks
- beq a2,t8,.Lchk8w # when a2==t8, no 64-byte chunks
- # There will be at most 1 32-byte chunk then
- subu a3,a2,t8 # subtract from a2 the reminder
- # Here a3 counts bytes in 16w chunks
- addu a3,a0,a3 # Now a3 is the final dst after 64-byte chunks
-
-# Find out, if there are any 64-byte chunks after which will be still at least
-# 96 bytes left. The value "96" is calculated as needed buffer for
-# "pref 30,64(a0)" prefetch, which can be used as "pref 30,0(a0)" after
-# incrementing "a0" by 64.
-# For "a2" below 160 there will be no such "pref 30 safe" 64-byte chunk.
-#
- sltiu v1,a2,160
- bgtz v1,.Lloop16w_nopref30 # skip "pref 30,0(a0)"
- subu t7,a2,96 # subtract "pref 30 unsafe" region
- # below we have at least 1 64-byte chunk which is "pref 30 safe"
- andi t6,t7,0x3f # t6 is past "64-byte safe chunks" reminder
- subu t5,t7,t6 # subtract from t7 the reminder
- # Here t5 counts bytes in 16w "safe" chunks
- addu t4,a0,t5 # Now t4 is the dst after 64-byte "safe" chunks
-
-# Don't use "pref 30,0(a0)" for a0 in a "middle" of a cache line
-# pref 30,0(a0)
-# Here we are in the region, where it is safe to use "pref 30,64(a0)"
-.Lloop16w:
- addiu a0,a0,64
- pref 30,-32(a0) # continue setting up the dest, addr 64-32
- sw a1,-64(a0)
- sw a1,-60(a0)
- sw a1,-56(a0)
- sw a1,-52(a0)
- sw a1,-48(a0)
- sw a1,-44(a0)
- sw a1,-40(a0)
- sw a1,-36(a0)
- nop
- nop # the extra nop instructions help to balance
- nop # cycles needed for "store" + "fill" + "evict"
- nop # For 64byte store there are needed 8 fill
- nop # and 8 evict cycles, i.e. at least 32 instr.
- nop
- nop
- pref 30,0(a0) # continue setting up the dest, addr 64-0
- sw a1,-32(a0)
- sw a1,-28(a0)
- sw a1,-24(a0)
- sw a1,-20(a0)
- sw a1,-16(a0)
- sw a1,-12(a0)
- sw a1,-8(a0)
- sw a1,-4(a0)
- nop
- nop
- nop
- nop # NOTE: adding 14 nop-s instead of 12 nop-s
- nop # gives better results for "fast" memory
- nop
- bne a0,t4,.Lloop16w
- nop
-
- beq a0,a3,.Lchk8w # maybe no more 64-byte chunks?
- nop # this "delayed slot" is useless ...
-
-.Lloop16w_nopref30: # there could be up to 3 "64-byte nopref30" chunks
- addiu a0,a0,64
- sw a1,-64(a0)
- sw a1,-60(a0)
- sw a1,-56(a0)
- sw a1,-52(a0)
- sw a1,-48(a0)
- sw a1,-44(a0)
- sw a1,-40(a0)
- sw a1,-36(a0)
- sw a1,-32(a0)
- sw a1,-28(a0)
- sw a1,-24(a0)
- sw a1,-20(a0)
- sw a1,-16(a0)
- sw a1,-12(a0)
- sw a1,-8(a0)
- bne a0,a3,.Lloop16w_nopref30
- sw a1,-4(a0)
-
-.Lchk8w: # t8 here is the byte count past 64-byte chunks
-
- andi t7,t8,0x1f # is there a 32-byte chunk?
- # the t7 is the reminder count past 32-bytes
- beq t8,t7,.Lchk1w # when t8==t7, no 32-byte chunk
- move a2,t7
-
- sw a1,0(a0)
- sw a1,4(a0)
- sw a1,8(a0)
- sw a1,12(a0)
- sw a1,16(a0)
- sw a1,20(a0)
- sw a1,24(a0)
- sw a1,28(a0)
- addiu a0,a0,32
-
-.Lchk1w:
- andi t8,a2,0x3 # now t8 is the reminder past 1w chunks
- beq a2,t8,.Llast4aligned
- subu a3,a2,t8 # a3 is the count of bytes in 1w chunks
- addu a3,a0,a3 # now a3 is the dst address past the 1w chunks
-
-# copying in words (4-byte chunks)
-.LwordCopy_loop:
- addiu a0,a0,4
- bne a0,a3,.LwordCopy_loop
- sw a1,-4(a0)
-
-# store last 0-3 bytes
-# this will repeat the last store if the memset finishes on a word boundary
-.Llast4aligned:
- j ra
- SWLO a1,-1(t0)
-
-.Llast4:
- beq a0,t0,.Llast4e
-.Llast4l:
- addiu a0,a0,1
- bne a0,t0,.Llast4l
- sb a1,-1(a0)
-.Llast4e:
- j ra
- nop
-
- .set at
- .set reorder
-
-END(memset)
-
-
-/************************************************************************
- * Implementation : Static functions
- ************************************************************************/
diff --git a/libc/arch-mips64/string/mips-string-ops.h b/libc/arch-mips64/string/mips-string-ops.h
deleted file mode 100644
index e635ba1..0000000
--- a/libc/arch-mips64/string/mips-string-ops.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (c) 2010 MIPS Technologies, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with
- * the distribution.
- * * Neither the name of MIPS Technologies Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __MIPS_STRING_OPS_H
-#define __MIPS_STRING_OPS_H
- /* This definition of the byte bitfields uses the
- assumption that the layout of the bitfields is
- equivalent to the layout in memory. Generally,
- for the MIPS ABIs, this is true. If you compile
- the strcmp.c file with -DSMOKE_TEST_NEW_STRCMP,
- this assumption will be tested.
-
- Also, regardless of char signedness, ANSI C dictates that
- strcmp() treats each character as unsigned char. For
- strlen and the like, signedness doesn't matter.
-
- Also, this code assumes that there are 8-bits per 'char'. */
-
-#if __mips64
-typedef struct bits
-{
- unsigned long B0:8, B1:8, B2:8, B3:8, B4:8, B5:8, B6:8, B7:8;
-} bits_t;
-#else
-typedef struct bits
-{
- unsigned long B0:8, B1:8, B2:8, B3:8;
-} bits_t;
-#endif
-
-#ifndef _ULW
- /* for MIPS GCC, there is no unaligned builtins - so this code forces
- the compiler to treat the pointer access as unaligned. */
-struct ulw
-{
- unsigned long b;
-} __attribute__ ((packed));
-
-#define _ULW(__x) ((struct ulw *) ((char *)(&__x)))->b;
-#endif
-
-/* This union assumes that small structures can be in registers. If
- not, then memory accesses will be done - not optimal, but ok. */
-typedef union
-{
- unsigned long v;
- bits_t b;
-} bitfields_t;
-
-#ifndef detect_zero
-/* __mips_dsp, __mips_dspr2, and __mips64 are predefined by
- the compiler, based on command line options. */
-#if (__mips_dsp || __mips_dspr2) && !__mips64
-#define __mips_using_dsp 1
-
-/* DSP 4-lane (8 unsigned bits per line) subtract and saturate
- * Intrinsic operation. How this works:
- * Given a 4-byte string of "ABC\0", subtract this as
- * an unsigned integer from 0x01010101:
- * 0x01010101
- * - 0x41424300
- * -----------
- ( 0xbfbebe01 <-- answer without saturation
- * 0x00000001 <-- answer with saturation
- * When this 4-lane vector is treated as an unsigned int value,
- * a non-zero answer indicates the presence of a zero in the
- * original 4-byte argument. */
-
-typedef signed char v4i8 __attribute__ ((vector_size (4)));
-
-#define detect_zero(__x,__y,__01s,__80s)\
- ((unsigned) __builtin_mips_subu_s_qb((v4i8) __01s,(v4i8) __x))
-
- /* sets all 4 lanes to requested byte. */
-#define set_byte_lanes(__x) ((unsigned) __builtin_mips_repl_qb(__x))
-
- /* sets all 4 lanes to 0x01. */
-#define def_and_set_01(__x) unsigned long __x = (unsigned) __builtin_mips_repl_qb(0x01)
-
- /* sets all 4 lanes to 0x80. Not needed when subu_s.qb used. */
-#define def_and_set_80(__x) /* do nothing */
-
-#else
- /* this version, originally published in the 80's, uses
- a reverse-carry-set like determination of the zero byte.
- The steps are, for __x = 0x31ff0001:
- __x - _01s = 0x30fdff00
- ~__x = 0xce00fffe
- ((__x - _01s) & ~__x) = 0x0000ff00
- x & _80s = 0x00008000 <- byte 3 was zero
- Some implementaions naively assume that characters are
- always 7-bit unsigned ASCII. With that assumption, the
- "& ~x" is usually discarded. Since character strings
- are 8-bit, the and is needed to catch the case of
- a false positive when the byte is 0x80. */
-
-#define detect_zero(__x,__y,_01s,_80s)\
- ((unsigned) (((__x) - _01s) & ~(__x)) & _80s)
-
-#if __mips64
-#define def_and_set_80(__x) unsigned long __x = 0x8080808080808080ul
-#define def_and_set_01(__x) unsigned long __x = 0x0101010101010101ul
-#else
-#define def_and_set_80(__x) unsigned long __x = 0x80808080ul
-#define def_and_set_01(__x) unsigned long __x = 0x01010101ul
-#endif
-
-#endif
-#endif
-
-/* dealing with 'void *' conversions without using extra variables. */
-#define get_byte(__x,__idx) (((unsigned char *) (__x))[__idx])
-#define set_byte(__x,__idx,__fill) ((unsigned char *) (__x))[__idx] = (__fill)
-#define get_word(__x,__idx) (((unsigned long *) (__x))[__idx])
-#define set_word(__x,__idx,__fill) ((unsigned long *) (__x))[__idx] = (__fill)
-#define inc_ptr_as(__type,__x,__inc) __x = (void *) (((__type) __x) + (__inc))
-#define cvt_ptr_to(__type,__x) ((__type) (__x))
-
-#endif
diff --git a/libc/arch-mips64/string/mips_strlen.c b/libc/arch-mips64/string/mips_strlen.c
deleted file mode 100644
index 37e5865..0000000
--- a/libc/arch-mips64/string/mips_strlen.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (c) 2010 MIPS Technologies, Inc.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with
- * the distribution.
- * * Neither the name of MIPS Technologies Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-#include "mips-string-ops.h"
-
-#define do_strlen_word(__av) {\
- if (detect_zero(x,x,_01s,_80s)) break;\
- x = __av;\
- cnt += sizeof (unsigned);\
- }
-
-#define do_strlen_byte(__x) {\
- if ((bx.b.B##__x) == 0) break;\
- ++cnt;\
- }
-
-#if SMOKE_TEST_MIPS_STRLEN
-#define strlen my_strlen
-#endif
-
-size_t
-strlen (const char *_a)
-{
- int cnt = 0;
- unsigned long x;
-
- /* align the string to word boundary so we can do word at a time. */
- if ((cvt_ptr_to (unsigned long, _a) & (sizeof (unsigned long) - 1)) != 0)
- {
- if ((cvt_ptr_to (unsigned long, _a) & 1) != 0)
- {
- if (get_byte (_a, 0) == 0)
- return cnt;
- /* set bit 1 so 2-bytes are checked and incremented. */
- inc_ptr_as (char *, _a, 1);
- ++cnt;
- }
- if ((cvt_ptr_to (unsigned long, _a) & 2) != 0)
- {
- if (get_byte (_a, 0) == 0)
- return cnt + 0;
- if (get_byte (_a, 1) == 0)
- return cnt + 1;
- inc_ptr_as (char *, _a, 2);
- cnt += 2;
- }
- }
-
-#if __mips64
-#error strlen: mips64 check for 4-byte alignment not implemented.
-#endif
-
- if (1)
- {
- def_and_set_01 (_01s);
- def_and_set_80 (_80s);
-
- /* as advantagous as it is to performance, this code cannot pre-load
- the following word, nor can it prefetch the next line at the start
- of the loop since the string can be at the end of a page with the
- following page unmapped. There are tests in the suite to catch
- any attempt to go beyond the current word. */
- x = get_word (_a, 0);
- while (1)
- {
- /* doing 8 words should cover most strings. */
- do_strlen_word (get_word (_a, 1));
- do_strlen_word (get_word (_a, 2));
- do_strlen_word (get_word (_a, 3));
- do_strlen_word (get_word (_a, 4));
- do_strlen_word (get_word (_a, 5));
- do_strlen_word (get_word (_a, 6));
- do_strlen_word (get_word (_a, 7));
- do_strlen_word (get_word (_a, 8));
- inc_ptr_as (unsigned long*, _a, 8);
- }
- }
- while (1)
- {
- /* pull apart the last word processed and find the zero. */
- bitfields_t bx;
- bx.v = x;
-#if __mips64
- do_strlen_byte (0);
- do_strlen_byte (1);
- do_strlen_byte (2);
- do_strlen_byte (3);
- do_strlen_byte (4);
- do_strlen_byte (5);
- do_strlen_byte (6);
-#else
- do_strlen_byte (0);
- do_strlen_byte (1);
- do_strlen_byte (2);
-#endif
- /* last byte is zero */
- break;
- }
- return cnt;
-}
-
-#undef do_strlen_byte
-#undef do_strlen_word
-
-#if SMOKE_TEST_MIPS_STRLEN
-#include <stdio.h>
-char str1[] = "DHRYSTONE PROGRAM, 1'ST STRING";
-char str2[] = "DHRYSTONE PROGRAM, 2'ST STRING";
-
-char str3[] = "another string";
-char str4[] = "another";
-
-char str5[] = "somes tring";
-char str6[] = "somes_tring";
-
-char str7[16], str8[16];
-
-static char *
-chk (unsigned long mine, unsigned long libs, int *errors)
-{
- static char answer[1024];
- char *result = mine == libs ? "PASS" : "FAIL";
- sprintf (answer, "new_strlen=%d: lib_strlen=%d: %s!", mine, libs, result);
- if (mine != libs)
- (*errors)++;
- return answer;
-}
-
-int
-main (int argc, char **argv)
-{
- int errors = 0;
- /* set -1 in one position */
- str6[5] = 0xff;
- /* set zero in same position with junk in following 3 */
- str7[0] = str8[0] = 0;
- str7[1] = 0xff;
- str7[2] = 'a';
- str7[3] = 2;
- str8[1] = 's';
- str8[2] = -2;
- str8[3] = 0;
-
- fprintf (stderr, "========== mips_strlen%s test...\n",
- argv[0] ? argv[0] : "unknown strlen");
-#define P(__x,__y) {\
- int a = my_strlen(__x + __y);\
- int b = (strlen)(__x + __y) /* library version */;\
- fprintf(stderr,"%s+%d: %s\n",#__x,__y,chk(a,b,&errors));\
- }
-
- P (str1, 0);
- P (str1, 1);
- P (str1, 2);
- P (str1, 3);
-
- P (str2, 0);
- P (str2, 1);
- P (str2, 2);
- P (str2, 3);
-
- P (str3, 0);
- P (str3, 1);
- P (str3, 2);
- P (str3, 3);
-
- P (str4, 0);
- P (str4, 1);
- P (str4, 2);
- P (str4, 3);
-
- P (str5, 0);
- P (str5, 1);
- P (str5, 2);
- P (str5, 3);
-
- P (str6, 0);
- P (str6, 1);
- P (str6, 2);
- P (str6, 3);
-
- P (str7, 0);
- P (str7, 1);
- P (str7, 2);
- P (str7, 3);
-
- P (str8, 0);
- P (str8, 1);
- P (str8, 2);
- P (str8, 3);
-
- return errors;
-}
-#endif
diff --git a/libc/arch-mips64/syscalls/__clock_nanosleep.S b/libc/arch-mips64/syscalls/___clock_nanosleep.S
index 204675f..e9fb316 100644
--- a/libc/arch-mips64/syscalls/__clock_nanosleep.S
+++ b/libc/arch-mips64/syscalls/___clock_nanosleep.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__clock_nanosleep)
+ENTRY(___clock_nanosleep)
.set push
.set noreorder
li v0, __NR_clock_nanosleep
@@ -22,5 +22,5 @@ ENTRY(__clock_nanosleep)
j t9
move ra, t0
.set pop
-END(__clock_nanosleep)
-.hidden __clock_nanosleep
+END(___clock_nanosleep)
+.hidden ___clock_nanosleep
diff --git a/libc/arch-mips64/syscalls/fgetxattr.S b/libc/arch-mips64/syscalls/___fgetxattr.S
index 44c248a..935b080 100644
--- a/libc/arch-mips64/syscalls/fgetxattr.S
+++ b/libc/arch-mips64/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
.set push
.set noreorder
li v0, __NR_fgetxattr
@@ -22,4 +22,5 @@ ENTRY(fgetxattr)
j t9
move ra, t0
.set pop
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-mips64/syscalls/fsetxattr.S b/libc/arch-mips64/syscalls/___fsetxattr.S
index 0ad1f90..c02f406 100644
--- a/libc/arch-mips64/syscalls/fsetxattr.S
+++ b/libc/arch-mips64/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
.set push
.set noreorder
li v0, __NR_fsetxattr
@@ -22,4 +22,5 @@ ENTRY(fsetxattr)
j t9
move ra, t0
.set pop
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-mips64/syscalls/__rt_sigqueueinfo.S b/libc/arch-mips64/syscalls/___rt_sigqueueinfo.S
index e97aeba..1503f51 100644
--- a/libc/arch-mips64/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-mips64/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
.set push
.set noreorder
li v0, __NR_rt_sigqueueinfo
@@ -22,5 +22,5 @@ ENTRY(__rt_sigqueueinfo)
j t9
move ra, t0
.set pop
-END(__rt_sigqueueinfo)
-.hidden __rt_sigqueueinfo
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-mips64/syscalls/process_vm_readv.S b/libc/arch-mips64/syscalls/process_vm_readv.S
new file mode 100644
index 0000000..f3c7372
--- /dev/null
+++ b/libc/arch-mips64/syscalls/process_vm_readv.S
@@ -0,0 +1,25 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_readv)
+ .set push
+ .set noreorder
+ li v0, __NR_process_vm_readv
+ syscall
+ bnez a3, 1f
+ move a0, v0
+ j ra
+ nop
+1:
+ move t0, ra
+ bal 2f
+ nop
+2:
+ .cpsetup ra, t1, 2b
+ LA t9,__set_errno_internal
+ .cpreturn
+ j t9
+ move ra, t0
+ .set pop
+END(process_vm_readv)
diff --git a/libc/arch-mips64/syscalls/process_vm_writev.S b/libc/arch-mips64/syscalls/process_vm_writev.S
new file mode 100644
index 0000000..0e8140b
--- /dev/null
+++ b/libc/arch-mips64/syscalls/process_vm_writev.S
@@ -0,0 +1,25 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_writev)
+ .set push
+ .set noreorder
+ li v0, __NR_process_vm_writev
+ syscall
+ bnez a3, 1f
+ move a0, v0
+ j ra
+ nop
+1:
+ move t0, ra
+ bal 2f
+ nop
+2:
+ .cpsetup ra, t1, 2b
+ LA t9,__set_errno_internal
+ .cpreturn
+ j t9
+ move ra, t0
+ .set pop
+END(process_vm_writev)
diff --git a/libc/arch-x86/syscalls/__clock_nanosleep.S b/libc/arch-x86/syscalls/___clock_nanosleep.S
index 75a54d1..088a92e 100644
--- a/libc/arch-x86/syscalls/__clock_nanosleep.S
+++ b/libc/arch-x86/syscalls/___clock_nanosleep.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__clock_nanosleep)
+ENTRY(___clock_nanosleep)
pushl %ebx
.cfi_def_cfa_offset 8
.cfi_rel_offset ebx, 0
@@ -33,4 +33,5 @@ ENTRY(__clock_nanosleep)
popl %ecx
popl %ebx
ret
-END(__clock_nanosleep)
+END(___clock_nanosleep)
+.hidden ___clock_nanosleep
diff --git a/libc/arch-x86/syscalls/fgetxattr.S b/libc/arch-x86/syscalls/___fgetxattr.S
index 1eff931..2891511 100644
--- a/libc/arch-x86/syscalls/fgetxattr.S
+++ b/libc/arch-x86/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
pushl %ebx
.cfi_def_cfa_offset 8
.cfi_rel_offset ebx, 0
@@ -33,4 +33,5 @@ ENTRY(fgetxattr)
popl %ecx
popl %ebx
ret
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-x86/syscalls/fsetxattr.S b/libc/arch-x86/syscalls/___fsetxattr.S
index 7af0ef0..287dafc 100644
--- a/libc/arch-x86/syscalls/fsetxattr.S
+++ b/libc/arch-x86/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
pushl %ebx
.cfi_def_cfa_offset 8
.cfi_rel_offset ebx, 0
@@ -38,4 +38,5 @@ ENTRY(fsetxattr)
popl %ecx
popl %ebx
ret
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-x86/syscalls/__rt_sigqueueinfo.S b/libc/arch-x86/syscalls/___rt_sigqueueinfo.S
index 4152100..97d167f 100644
--- a/libc/arch-x86/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-x86/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
pushl %ebx
.cfi_def_cfa_offset 8
.cfi_rel_offset ebx, 0
@@ -28,4 +28,5 @@ ENTRY(__rt_sigqueueinfo)
popl %ecx
popl %ebx
ret
-END(__rt_sigqueueinfo)
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-x86/syscalls/ftruncate.S b/libc/arch-x86/syscalls/ftruncate.S
deleted file mode 100644
index 78d1e18..0000000
--- a/libc/arch-x86/syscalls/ftruncate.S
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Generated by gensyscalls.py. Do not edit. */
-
-#include <private/bionic_asm.h>
-
-ENTRY(ftruncate)
- pushl %ebx
- .cfi_def_cfa_offset 8
- .cfi_rel_offset ebx, 0
- pushl %ecx
- .cfi_adjust_cfa_offset 4
- .cfi_rel_offset ecx, 0
- mov 12(%esp), %ebx
- mov 16(%esp), %ecx
- movl $__NR_ftruncate, %eax
- int $0x80
- cmpl $-MAX_ERRNO, %eax
- jb 1f
- negl %eax
- pushl %eax
- call __set_errno_internal
- addl $4, %esp
-1:
- popl %ecx
- popl %ebx
- ret
-END(ftruncate)
diff --git a/libc/arch-x86/syscalls/process_vm_readv.S b/libc/arch-x86/syscalls/process_vm_readv.S
new file mode 100644
index 0000000..64965f6
--- /dev/null
+++ b/libc/arch-x86/syscalls/process_vm_readv.S
@@ -0,0 +1,46 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_readv)
+ pushl %ebx
+ .cfi_def_cfa_offset 8
+ .cfi_rel_offset ebx, 0
+ pushl %ecx
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset ecx, 0
+ pushl %edx
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset edx, 0
+ pushl %esi
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset esi, 0
+ pushl %edi
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset edi, 0
+ pushl %ebp
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset ebp, 0
+ mov 28(%esp), %ebx
+ mov 32(%esp), %ecx
+ mov 36(%esp), %edx
+ mov 40(%esp), %esi
+ mov 44(%esp), %edi
+ mov 48(%esp), %ebp
+ movl $__NR_process_vm_readv, %eax
+ int $0x80
+ cmpl $-MAX_ERRNO, %eax
+ jb 1f
+ negl %eax
+ pushl %eax
+ call __set_errno_internal
+ addl $4, %esp
+1:
+ popl %ebp
+ popl %edi
+ popl %esi
+ popl %edx
+ popl %ecx
+ popl %ebx
+ ret
+END(process_vm_readv)
diff --git a/libc/arch-x86/syscalls/process_vm_writev.S b/libc/arch-x86/syscalls/process_vm_writev.S
new file mode 100644
index 0000000..555c822
--- /dev/null
+++ b/libc/arch-x86/syscalls/process_vm_writev.S
@@ -0,0 +1,46 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_writev)
+ pushl %ebx
+ .cfi_def_cfa_offset 8
+ .cfi_rel_offset ebx, 0
+ pushl %ecx
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset ecx, 0
+ pushl %edx
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset edx, 0
+ pushl %esi
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset esi, 0
+ pushl %edi
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset edi, 0
+ pushl %ebp
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset ebp, 0
+ mov 28(%esp), %ebx
+ mov 32(%esp), %ecx
+ mov 36(%esp), %edx
+ mov 40(%esp), %esi
+ mov 44(%esp), %edi
+ mov 48(%esp), %ebp
+ movl $__NR_process_vm_writev, %eax
+ int $0x80
+ cmpl $-MAX_ERRNO, %eax
+ jb 1f
+ negl %eax
+ pushl %eax
+ call __set_errno_internal
+ addl $4, %esp
+1:
+ popl %ebp
+ popl %edi
+ popl %esi
+ popl %edx
+ popl %ecx
+ popl %ebx
+ ret
+END(process_vm_writev)
diff --git a/libc/arch-x86_64/string/ssse3-strcmp-slm.S b/libc/arch-x86_64/string/ssse3-strcmp-slm.S
index 0dd8c27..e8acd5b 100644
--- a/libc/arch-x86_64/string/ssse3-strcmp-slm.S
+++ b/libc/arch-x86_64/string/ssse3-strcmp-slm.S
@@ -1897,8 +1897,8 @@ L(strcmp_exitz):
.p2align 4
L(Byte0):
- movzx (%rsi), %ecx
- movzx (%rdi), %eax
+ movzbl (%rsi), %ecx
+ movzbl (%rdi), %eax
sub %ecx, %eax
ret
diff --git a/libc/arch-x86_64/syscalls/__clock_nanosleep.S b/libc/arch-x86_64/syscalls/___clock_nanosleep.S
index 37726c0..3286eb2 100644
--- a/libc/arch-x86_64/syscalls/__clock_nanosleep.S
+++ b/libc/arch-x86_64/syscalls/___clock_nanosleep.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__clock_nanosleep)
+ENTRY(___clock_nanosleep)
movq %rcx, %r10
movl $__NR_clock_nanosleep, %eax
syscall
@@ -13,5 +13,5 @@ ENTRY(__clock_nanosleep)
call __set_errno_internal
1:
ret
-END(__clock_nanosleep)
-.hidden __clock_nanosleep
+END(___clock_nanosleep)
+.hidden ___clock_nanosleep
diff --git a/libc/arch-x86_64/syscalls/fgetxattr.S b/libc/arch-x86_64/syscalls/___fgetxattr.S
index 7762474..302fd77 100644
--- a/libc/arch-x86_64/syscalls/fgetxattr.S
+++ b/libc/arch-x86_64/syscalls/___fgetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fgetxattr)
+ENTRY(___fgetxattr)
movq %rcx, %r10
movl $__NR_fgetxattr, %eax
syscall
@@ -13,4 +13,5 @@ ENTRY(fgetxattr)
call __set_errno_internal
1:
ret
-END(fgetxattr)
+END(___fgetxattr)
+.hidden ___fgetxattr
diff --git a/libc/arch-x86_64/syscalls/fsetxattr.S b/libc/arch-x86_64/syscalls/___fsetxattr.S
index 97822c4..125ef20 100644
--- a/libc/arch-x86_64/syscalls/fsetxattr.S
+++ b/libc/arch-x86_64/syscalls/___fsetxattr.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(fsetxattr)
+ENTRY(___fsetxattr)
movq %rcx, %r10
movl $__NR_fsetxattr, %eax
syscall
@@ -13,4 +13,5 @@ ENTRY(fsetxattr)
call __set_errno_internal
1:
ret
-END(fsetxattr)
+END(___fsetxattr)
+.hidden ___fsetxattr
diff --git a/libc/arch-x86_64/syscalls/__rt_sigqueueinfo.S b/libc/arch-x86_64/syscalls/___rt_sigqueueinfo.S
index 52b6863..8c6b30b 100644
--- a/libc/arch-x86_64/syscalls/__rt_sigqueueinfo.S
+++ b/libc/arch-x86_64/syscalls/___rt_sigqueueinfo.S
@@ -2,7 +2,7 @@
#include <private/bionic_asm.h>
-ENTRY(__rt_sigqueueinfo)
+ENTRY(___rt_sigqueueinfo)
movl $__NR_rt_sigqueueinfo, %eax
syscall
cmpq $-MAX_ERRNO, %rax
@@ -12,5 +12,5 @@ ENTRY(__rt_sigqueueinfo)
call __set_errno_internal
1:
ret
-END(__rt_sigqueueinfo)
-.hidden __rt_sigqueueinfo
+END(___rt_sigqueueinfo)
+.hidden ___rt_sigqueueinfo
diff --git a/libc/arch-x86_64/syscalls/process_vm_readv.S b/libc/arch-x86_64/syscalls/process_vm_readv.S
new file mode 100644
index 0000000..597649e
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/process_vm_readv.S
@@ -0,0 +1,16 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_readv)
+ movq %rcx, %r10
+ movl $__NR_process_vm_readv, %eax
+ syscall
+ cmpq $-MAX_ERRNO, %rax
+ jb 1f
+ negl %eax
+ movl %eax, %edi
+ call __set_errno_internal
+1:
+ ret
+END(process_vm_readv)
diff --git a/libc/arch-x86_64/syscalls/process_vm_writev.S b/libc/arch-x86_64/syscalls/process_vm_writev.S
new file mode 100644
index 0000000..397c007
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/process_vm_writev.S
@@ -0,0 +1,16 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(process_vm_writev)
+ movq %rcx, %r10
+ movl $__NR_process_vm_writev, %eax
+ syscall
+ cmpq $-MAX_ERRNO, %rax
+ jb 1f
+ negl %eax
+ movl %eax, %edi
+ call __set_errno_internal
+1:
+ ret
+END(process_vm_writev)
diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp
index 10521cf..103aa8f 100644
--- a/libc/bionic/bionic_systrace.cpp
+++ b/libc/bionic/bionic_systrace.cpp
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
+#include "private/bionic_lock.h"
#include "private/bionic_systrace.h"
#include "private/libc_logging.h"
@@ -29,12 +30,17 @@
#define WRITE_OFFSET 32
-static const prop_info* g_pinfo = NULL;
+constexpr char SYSTRACE_PROPERTY_NAME[] = "debug.atrace.tags.enableflags";
+
+static Lock g_lock;
+static const prop_info* g_pinfo;
static uint32_t g_serial = -1;
-static uint64_t g_tags = 0;
+static uint64_t g_tags;
static int g_trace_marker_fd = -1;
static bool should_trace() {
+ bool result = false;
+ g_lock.lock();
// If g_pinfo is null, this means that systrace hasn't been run and it's safe to
// assume that no trace writing will need to take place. However, to avoid running
// this costly find check each time, we set it to a non-tracing value so that next
@@ -42,32 +48,39 @@ static bool should_trace() {
// this function also deals with the bootup case, during which the call to property
// set will fail if the property server hasn't yet started.
if (g_pinfo == NULL) {
- g_pinfo = __system_property_find("debug.atrace.tags.enableflags");
+ g_pinfo = __system_property_find(SYSTRACE_PROPERTY_NAME);
if (g_pinfo == NULL) {
- __system_property_set("debug.atrace.tags.enableflags", "0");
- g_pinfo = __system_property_find("debug.atrace.tags.enableflags");
- if (g_pinfo == NULL) {
- return false;
- }
+ __system_property_set(SYSTRACE_PROPERTY_NAME, "0");
+ g_pinfo = __system_property_find(SYSTRACE_PROPERTY_NAME);
}
}
-
- // Find out which tags have been enabled on the command line and set
- // the value of tags accordingly. If the value of the property changes,
- // the serial will also change, so the costly system_property_read function
- // can be avoided by calling the much cheaper system_property_serial
- // first. The values within pinfo may change, but its location is guaranteed
- // not to move.
- const uint32_t cur_serial = __system_property_serial(g_pinfo);
- if (cur_serial != g_serial) {
- g_serial = cur_serial;
- char value[PROP_VALUE_MAX];
- __system_property_read(g_pinfo, 0, value);
- g_tags = strtoull(value, NULL, 0);
+ if (g_pinfo != NULL) {
+ // Find out which tags have been enabled on the command line and set
+ // the value of tags accordingly. If the value of the property changes,
+ // the serial will also change, so the costly system_property_read function
+ // can be avoided by calling the much cheaper system_property_serial
+ // first. The values within pinfo may change, but its location is guaranteed
+ // not to move.
+ uint32_t cur_serial = __system_property_serial(g_pinfo);
+ if (cur_serial != g_serial) {
+ g_serial = cur_serial;
+ char value[PROP_VALUE_MAX];
+ __system_property_read(g_pinfo, 0, value);
+ g_tags = strtoull(value, NULL, 0);
+ }
+ result = ((g_tags & ATRACE_TAG_BIONIC) != 0);
}
+ g_lock.unlock();
+ return result;
+}
- // Finally, verify that this tag value enables bionic tracing.
- return ((g_tags & ATRACE_TAG_BIONIC) != 0);
+static int get_trace_marker_fd() {
+ g_lock.lock();
+ if (g_trace_marker_fd == -1) {
+ g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY);
+ }
+ g_lock.unlock();
+ return g_trace_marker_fd;
}
ScopedTrace::ScopedTrace(const char* message) {
@@ -75,11 +88,9 @@ ScopedTrace::ScopedTrace(const char* message) {
return;
}
- if (g_trace_marker_fd == -1) {
- g_trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_CLOEXEC | O_WRONLY);
- if (g_trace_marker_fd == -1) {
- __libc_fatal("Could not open kernel trace file: %s\n", strerror(errno));
- }
+ int trace_marker_fd = get_trace_marker_fd();
+ if (trace_marker_fd == -1) {
+ return;
}
// If bionic tracing has been enabled, then write the message to the
@@ -87,12 +98,10 @@ ScopedTrace::ScopedTrace(const char* message) {
int length = strlen(message);
char buf[length + WRITE_OFFSET];
size_t len = snprintf(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message);
- ssize_t wbytes = TEMP_FAILURE_RETRY(write(g_trace_marker_fd, buf, len));
- // Error while writing
- if (static_cast<size_t>(wbytes) != len) {
- __libc_fatal("Could not write to kernel trace file: %s\n", strerror(errno));
- }
+ // Tracing may stop just after checking property and before writing the message.
+ // So the write is acceptable to fail. See b/20666100.
+ TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len));
}
ScopedTrace::~ScopedTrace() {
@@ -100,10 +109,10 @@ ScopedTrace::~ScopedTrace() {
return;
}
- ssize_t wbytes = TEMP_FAILURE_RETRY(write(g_trace_marker_fd, "E", 1));
-
- // Error while writing
- if (static_cast<size_t>(wbytes) != 1) {
- __libc_fatal("Could not write to kernel trace file: %s\n", strerror(errno));
+ int trace_marker_fd = get_trace_marker_fd();
+ if (trace_marker_fd == -1) {
+ return;
}
+
+ TEMP_FAILURE_RETRY(write(trace_marker_fd, "E", 1));
}
diff --git a/libc/bionic/clock_nanosleep.cpp b/libc/bionic/clock_nanosleep.cpp
index 15b8fe7..8e2146f 100644
--- a/libc/bionic/clock_nanosleep.cpp
+++ b/libc/bionic/clock_nanosleep.cpp
@@ -30,9 +30,9 @@
#include "private/ErrnoRestorer.h"
-extern "C" int __clock_nanosleep(clockid_t, int, const timespec*, timespec*);
+extern "C" int ___clock_nanosleep(clockid_t, int, const timespec*, timespec*);
int clock_nanosleep(clockid_t clock_id, int flags, const timespec* in, timespec* out) {
ErrnoRestorer errno_restorer;
- return (__clock_nanosleep(clock_id, flags, in, out) == 0) ? 0 : errno;
+ return (___clock_nanosleep(clock_id, flags, in, out) == 0) ? 0 : errno;
}
diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp
index 698ab6b..de72cb2 100644
--- a/libc/bionic/debug_mapinfo.cpp
+++ b/libc/bionic/debug_mapinfo.cpp
@@ -27,6 +27,7 @@
*/
#include <ctype.h>
+#include <elf.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
@@ -35,14 +36,22 @@
#include "debug_mapinfo.h"
#include "malloc_debug_disable.h"
+#if defined(__LP64__)
+#define Elf_W(x) Elf64_##x
+#else
+#define Elf_W(x) Elf32_##x
+#endif
+
// Format of /proc/<PID>/maps:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
static mapinfo_t* parse_maps_line(char* line) {
uintptr_t start;
uintptr_t end;
+ uintptr_t offset;
+ char permissions[4];
int name_pos;
- if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d%n", &start,
- &end, &name_pos) < 2) {
+ if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %4s %" PRIxPTR " %*x:%*x %*d%n", &start,
+ &end, permissions, &offset, &name_pos) < 2) {
return NULL;
}
@@ -59,6 +68,14 @@ static mapinfo_t* parse_maps_line(char* line) {
if (mi) {
mi->start = start;
mi->end = end;
+ mi->offset = offset;
+ if (permissions[0] != 'r') {
+ // Any unreadable map will just get a zero load base.
+ mi->load_base = 0;
+ mi->load_base_read = true;
+ } else {
+ mi->load_base_read = false;
+ }
memcpy(mi->name, name, name_len);
mi->name[name_len] = '\0';
}
@@ -95,11 +112,58 @@ __LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi) {
}
}
+template<typename T>
+static inline bool get_val(mapinfo_t* mi, uintptr_t addr, T* store) {
+ if (addr < mi->start || addr + sizeof(T) > mi->end) {
+ return false;
+ }
+ // Make sure the address is aligned properly.
+ if (addr & (sizeof(T)-1)) {
+ return false;
+ }
+ *store = *reinterpret_cast<T*>(addr);
+ return true;
+}
+
+__LIBC_HIDDEN__ void mapinfo_read_loadbase(mapinfo_t* mi) {
+ mi->load_base = 0;
+ mi->load_base_read = true;
+ uintptr_t addr = mi->start;
+ Elf_W(Ehdr) ehdr;
+ if (!get_val<Elf_W(Half)>(mi, addr + offsetof(Elf_W(Ehdr), e_phnum), &ehdr.e_phnum)) {
+ return;
+ }
+ if (!get_val<Elf_W(Off)>(mi, addr + offsetof(Elf_W(Ehdr), e_phoff), &ehdr.e_phoff)) {
+ return;
+ }
+ addr += ehdr.e_phoff;
+ for (size_t i = 0; i < ehdr.e_phnum; i++) {
+ Elf_W(Phdr) phdr;
+ if (!get_val<Elf_W(Word)>(mi, addr + offsetof(Elf_W(Phdr), p_type), &phdr.p_type)) {
+ return;
+ }
+ if (!get_val<Elf_W(Off)>(mi, addr + offsetof(Elf_W(Phdr), p_offset), &phdr.p_offset)) {
+ return;
+ }
+ if (phdr.p_type == PT_LOAD && phdr.p_offset == mi->offset) {
+ if (!get_val<Elf_W(Addr)>(mi, addr + offsetof(Elf_W(Phdr), p_vaddr), &phdr.p_vaddr)) {
+ return;
+ }
+ mi->load_base = phdr.p_vaddr;
+ return;
+ }
+ addr += sizeof(phdr);
+ }
+}
+
// Find the containing map info for the PC.
__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, uintptr_t pc, uintptr_t* rel_pc) {
for (; mi != NULL; mi = mi->next) {
if ((pc >= mi->start) && (pc < mi->end)) {
- *rel_pc = pc - mi->start;
+ if (!mi->load_base_read) {
+ mapinfo_read_loadbase(mi);
+ }
+ *rel_pc = pc - mi->start + mi->load_base;
return mi;
}
}
diff --git a/libc/bionic/debug_mapinfo.h b/libc/bionic/debug_mapinfo.h
index 926b377..af7d05d 100644
--- a/libc/bionic/debug_mapinfo.h
+++ b/libc/bionic/debug_mapinfo.h
@@ -35,6 +35,9 @@ struct mapinfo_t {
struct mapinfo_t* next;
uintptr_t start;
uintptr_t end;
+ uintptr_t offset;
+ uintptr_t load_base;
+ bool load_base_read;
char name[];
};
diff --git a/libc/bionic/dirent.cpp b/libc/bionic/dirent.cpp
index fb45398..6fd3842 100644
--- a/libc/bionic/dirent.cpp
+++ b/libc/bionic/dirent.cpp
@@ -41,13 +41,19 @@
extern "C" int __getdents64(unsigned int, dirent*, unsigned int);
+// Apportable decided to copy the data structure from this file
+// and use it in their own code, but they also call into readdir.
+// In order to avoid a lockup, the structure must be maintained in
+// the exact same order as in L and below. New structure members
+// need to be added to the end of this structure.
+// See b/21037208 for more details.
struct DIR {
int fd_;
size_t available_bytes_;
dirent* next_;
- long current_pos_;
pthread_mutex_t mutex_;
dirent buff_[15];
+ long current_pos_;
};
static DIR* __allocate_DIR(int fd) {
diff --git a/libc/bionic/dlmalloc.h b/libc/bionic/dlmalloc.h
index 2f53c1b..054bd4f 100644
--- a/libc/bionic/dlmalloc.h
+++ b/libc/bionic/dlmalloc.h
@@ -44,11 +44,13 @@
#define dlmalloc dlmalloc_real
#endif
-/* Export two symbols used by the VM. */
-__BEGIN_DECLS
-int dlmalloc_trim(size_t) __LIBC_ABI_PUBLIC__;
-void dlmalloc_inspect_all(void (*handler)(void*, void*, size_t, void*), void*) __LIBC_ABI_PUBLIC__;
-__END_DECLS
+/* These two symbols are exported on devices that use dlmalloc.
+ * In order to be consistent across all devices, they will
+ * be exported everywhere. Move the real symbols out of the way
+ * so that ndk_cruft.cpp can export these symbols.
+ */
+#define dlmalloc_inspect_all dlmalloc_inspect_all_real
+#define dlmalloc_trim dlmalloc_trim_real
/* Include the proper definitions. */
#include "../upstream-dlmalloc/malloc.h"
diff --git a/linker/linker_environ.h b/libc/bionic/fgetxattr.cpp
index 0f6ac08..6d999bf 100644
--- a/linker/linker_environ.h
+++ b/libc/bionic/fgetxattr.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,19 +26,34 @@
* SUCH DAMAGE.
*/
-#ifndef LINKER_ENVIRON_H
-#define LINKER_ENVIRON_H
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
-class KernelArgumentBlock;
+extern "C" ssize_t ___fgetxattr(int, const char*, void*, size_t);
-// Call this function before any of the other functions in this header file.
-extern void linker_env_init(KernelArgumentBlock& args);
+ssize_t fgetxattr(int fd, const char *name, void *value, size_t size) {
+ int saved_errno = errno;
+ ssize_t result = ___fgetxattr(fd, name, value, size);
-// Returns the value of environment variable 'name' if defined and not
-// empty, or null otherwise.
-extern const char* linker_env_get(const char* name);
+ if ((result != -1) || (errno != EBADF)) {
+ return result;
+ }
-// Returns the value of this program's AT_SECURE variable.
-extern bool get_AT_SECURE();
+ // fd could be an O_PATH file descriptor, and the kernel
+ // may not directly support fgetxattr() on such a file descriptor.
+ // Use /proc/self/fd instead to emulate this support.
+ int fd_flag = fcntl(fd, F_GETFL);
+ if ((fd_flag == -1) || ((fd_flag & O_PATH) == 0)) {
+ errno = EBADF;
+ return -1;
+ }
-#endif // LINKER_ENVIRON_H
+ char buf[40];
+ snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
+ errno = saved_errno;
+ return getxattr(buf, name, value, size);
+}
diff --git a/libc/bionic/fsetxattr.cpp b/libc/bionic/fsetxattr.cpp
new file mode 100644
index 0000000..6d2e868
--- /dev/null
+++ b/libc/bionic/fsetxattr.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+extern "C" int ___fsetxattr(int, const char*, const void*, size_t, int);
+
+int fsetxattr(int fd, const char* name, const void* value, size_t size, int flags) {
+ int saved_errno = errno;
+ int result = ___fsetxattr(fd, name, value, size, flags);
+
+ if ((result == 0) || (errno != EBADF)) {
+ return result;
+ }
+
+ // fd could be an O_PATH file descriptor, and the kernel
+ // may not directly support fsetxattr() on such a file descriptor.
+ // Use /proc/self/fd instead to emulate this support.
+ int fd_flag = fcntl(fd, F_GETFL);
+ if ((fd_flag == -1) || ((fd_flag & O_PATH) == 0)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ char buf[40];
+ snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
+ errno = saved_errno;
+ return setxattr(buf, name, value, size, flags);
+}
diff --git a/libc/bionic/ftruncate.cpp b/libc/bionic/ftruncate.cpp
new file mode 100644
index 0000000..9936df0
--- /dev/null
+++ b/libc/bionic/ftruncate.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <unistd.h>
+
+#if !defined(__LP64__)
+static_assert(sizeof(off_t) == 4,
+ "libc can't be built with _FILE_OFFSET_BITS=64.");
+
+// The kernel's implementation of ftruncate uses an unsigned long for the length
+// parameter, so it will not catch negative values. On the other hand
+// ftruncate64 does check for this, so just forward the call.
+int ftruncate(int filedes, off_t length) {
+ return ftruncate64(filedes, length);
+}
+#endif // !defined(__LP64__)
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 36dc085..bd71628 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -30,11 +30,14 @@
#include <elf.h>
#include <errno.h>
+#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/auxv.h>
+#include <sys/personality.h>
#include <sys/time.h>
#include <unistd.h>
@@ -42,6 +45,7 @@
#include "private/bionic_ssp.h"
#include "private/bionic_tls.h"
#include "private/KernelArgumentBlock.h"
+#include "private/libc_logging.h"
#include "pthread_internal.h"
extern "C" abort_msg_t** __abort_message_ptr;
@@ -120,6 +124,213 @@ void __libc_init_common(KernelArgumentBlock& args) {
__libc_init_vdso();
}
+__noreturn static void __early_abort(int line) {
+ // We can't write to stdout or stderr because we're aborting before we've checked that
+ // it's safe for us to use those file descriptors. We probably can't strace either, so
+ // we rely on the fact that if we dereference a low address, either debuggerd or the
+ // kernel's crash dump will show the fault address.
+ *reinterpret_cast<int*>(line) = 0;
+ _exit(EXIT_FAILURE);
+}
+
+// Force any of the closed stdin, stdout and stderr to be associated with /dev/null.
+static void __nullify_closed_stdio() {
+ int dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
+ if (dev_null == -1) {
+ // init won't have /dev/null available, but SELinux provides an equivalent.
+ dev_null = TEMP_FAILURE_RETRY(open("/sys/fs/selinux/null", O_RDWR));
+ }
+ if (dev_null == -1) {
+ __early_abort(__LINE__);
+ }
+
+ // If any of the stdio file descriptors is valid and not associated
+ // with /dev/null, dup /dev/null to it.
+ for (int i = 0; i < 3; i++) {
+ // If it is /dev/null already, we are done.
+ if (i == dev_null) {
+ continue;
+ }
+
+ // Is this fd already open?
+ int status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL));
+ if (status != -1) {
+ continue;
+ }
+
+ // The only error we allow is that the file descriptor does not
+ // exist, in which case we dup /dev/null to it.
+ if (errno == EBADF) {
+ // Try dupping /dev/null to this stdio file descriptor and
+ // repeat if there is a signal. Note that any errors in closing
+ // the stdio descriptor are lost.
+ status = TEMP_FAILURE_RETRY(dup2(dev_null, i));
+ if (status == -1) {
+ __early_abort(__LINE__);
+ }
+ } else {
+ __early_abort(__LINE__);
+ }
+ }
+
+ // If /dev/null is not one of the stdio file descriptors, close it.
+ if (dev_null > 2) {
+ if (close(dev_null) == -1) {
+ __early_abort(__LINE__);
+ }
+ }
+}
+
+// Check if the environment variable definition at 'envstr'
+// starts with '<name>=', and if so return the address of the
+// first character after the equal sign. Otherwise return null.
+static const char* env_match(const char* envstr, const char* name) {
+ size_t i = 0;
+
+ while (envstr[i] == name[i] && name[i] != '\0') {
+ ++i;
+ }
+
+ if (name[i] == '\0' && envstr[i] == '=') {
+ return envstr + i + 1;
+ }
+
+ return nullptr;
+}
+
+static bool __is_valid_environment_variable(const char* name) {
+ // According to the kernel source, by default the kernel uses 32*PAGE_SIZE
+ // as the maximum size for an environment variable definition.
+ const int MAX_ENV_LEN = 32*4096;
+
+ if (name == nullptr) {
+ return false;
+ }
+
+ // Parse the string, looking for the first '=' there, and its size.
+ int pos = 0;
+ int first_equal_pos = -1;
+ while (pos < MAX_ENV_LEN) {
+ if (name[pos] == '\0') {
+ break;
+ }
+ if (name[pos] == '=' && first_equal_pos < 0) {
+ first_equal_pos = pos;
+ }
+ pos++;
+ }
+
+ // Check that it's smaller than MAX_ENV_LEN (to detect non-zero terminated strings).
+ if (pos >= MAX_ENV_LEN) {
+ return false;
+ }
+
+ // Check that it contains at least one equal sign that is not the first character
+ if (first_equal_pos < 1) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool __is_unsafe_environment_variable(const char* name) {
+ // None of these should be allowed in setuid programs.
+ static const char* const UNSAFE_VARIABLE_NAMES[] = {
+ "GCONV_PATH",
+ "GETCONF_DIR",
+ "HOSTALIASES",
+ "JE_MALLOC_CONF",
+ "LD_AOUT_LIBRARY_PATH",
+ "LD_AOUT_PRELOAD",
+ "LD_AUDIT",
+ "LD_DEBUG",
+ "LD_DEBUG_OUTPUT",
+ "LD_DYNAMIC_WEAK",
+ "LD_LIBRARY_PATH",
+ "LD_ORIGIN_PATH",
+ "LD_PRELOAD",
+ "LD_PROFILE",
+ "LD_SHOW_AUXV",
+ "LD_USE_LOAD_BIAS",
+ "LOCALDOMAIN",
+ "LOCPATH",
+ "MALLOC_CHECK_",
+ "MALLOC_CONF",
+ "MALLOC_TRACE",
+ "NIS_PATH",
+ "NLSPATH",
+ "RESOLV_HOST_CONF",
+ "RES_OPTIONS",
+ "TMPDIR",
+ "TZDIR",
+ nullptr
+ };
+ for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != nullptr; ++i) {
+ if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != nullptr) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void __sanitize_environment_variables(char** env) {
+ bool is_AT_SECURE = getauxval(AT_SECURE);
+ char** src = env;
+ char** dst = env;
+ for (; src[0] != nullptr; ++src) {
+ if (!__is_valid_environment_variable(src[0])) {
+ continue;
+ }
+ // Remove various unsafe environment variables if we're loading a setuid program.
+ if (is_AT_SECURE && __is_unsafe_environment_variable(src[0])) {
+ continue;
+ }
+ dst[0] = src[0];
+ ++dst;
+ }
+ dst[0] = nullptr;
+}
+
+static void __initialize_personality() {
+#if !defined(__LP64__)
+ int old_value = personality(0xffffffff);
+ if (old_value == -1) {
+ __libc_fatal("error getting old personality value: %s", strerror(errno));
+ }
+
+ if (personality((static_cast<unsigned int>(old_value) & ~PER_MASK) | PER_LINUX32) == -1) {
+ __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
+ }
+#endif
+}
+
+void __libc_init_AT_SECURE(KernelArgumentBlock& args) {
+ __libc_auxv = args.auxv;
+
+ // Check that the kernel provided a value for AT_SECURE.
+ bool found_AT_SECURE = false;
+ for (ElfW(auxv_t)* v = __libc_auxv; v->a_type != AT_NULL; ++v) {
+ if (v->a_type == AT_SECURE) {
+ found_AT_SECURE = true;
+ break;
+ }
+ }
+ if (!found_AT_SECURE) __early_abort(__LINE__);
+
+ if (getauxval(AT_SECURE)) {
+ // If this is a setuid/setgid program, close the security hole described in
+ // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
+ __nullify_closed_stdio();
+
+ __sanitize_environment_variables(args.envp);
+ }
+
+ // Now the environment has been sanitized, make it available.
+ environ = args.envp;
+
+ __initialize_personality();
+}
+
/* This function will be called during normal program termination
* to run the destructors that are listed in the .fini_array section
* of the executable, if any.
diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h
index 3032f99..673ad5b 100644
--- a/libc/bionic/libc_init_common.h
+++ b/libc/bionic/libc_init_common.h
@@ -49,8 +49,12 @@ __LIBC_HIDDEN__ void __libc_fini(void* finit_array);
__END_DECLS
#if defined(__cplusplus)
+
class KernelArgumentBlock;
__LIBC_HIDDEN__ void __libc_init_common(KernelArgumentBlock& args);
+
+__LIBC_HIDDEN__ void __libc_init_AT_SECURE(KernelArgumentBlock& args);
+
#endif
#endif
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index bc11f3d..7794fbe 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -91,6 +91,7 @@ __noreturn void __libc_init(void* raw_args,
structors_array_t const * const structors) {
KernelArgumentBlock args(raw_args);
__libc_init_tls(args);
+ __libc_init_AT_SECURE(args);
__libc_init_common(args);
apply_gnu_relro();
diff --git a/libc/bionic/libc_logging.cpp b/libc/bionic/libc_logging.cpp
index 7ad21c4..cb0b334 100644
--- a/libc/bionic/libc_logging.cpp
+++ b/libc/bionic/libc_logging.cpp
@@ -56,6 +56,7 @@ enum AndroidEventLogType {
EVENT_TYPE_LONG = 1,
EVENT_TYPE_STRING = 2,
EVENT_TYPE_LIST = 3,
+ EVENT_TYPE_FLOAT = 4,
};
struct BufferOutputStream {
diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp
index 64f2112..6a46667 100644
--- a/libc/bionic/malloc_debug_leak.cpp
+++ b/libc/bionic/malloc_debug_leak.cpp
@@ -133,8 +133,9 @@ static HashEntry* record_backtrace(uintptr_t* backtrace, size_t numEntries, size
size |= SIZE_FLAG_ZYGOTE_CHILD;
}
+ // Keep the lock held for as little time as possible to prevent deadlocks.
+ ScopedPthreadMutexLocker locker(&g_hash_table->lock);
HashEntry* entry = find_entry(g_hash_table, slot, backtrace, numEntries, size);
-
if (entry != NULL) {
entry->allocations++;
} else {
@@ -302,8 +303,6 @@ extern "C" void* leak_malloc(size_t bytes) {
void* base = g_malloc_dispatch->malloc(size);
if (base != NULL) {
- ScopedPthreadMutexLocker locker(&g_hash_table->lock);
-
uintptr_t backtrace[BACKTRACE_SIZE];
size_t numEntries = GET_BACKTRACE(backtrace, BACKTRACE_SIZE);
@@ -328,8 +327,6 @@ extern "C" void leak_free(void* mem) {
return;
}
- ScopedPthreadMutexLocker locker(&g_hash_table->lock);
-
// check the guard to make sure it is valid
AllocationEntry* header = to_header(mem);
@@ -342,6 +339,7 @@ extern "C" void leak_free(void* mem) {
}
}
+ ScopedPthreadMutexLocker locker(&g_hash_table->lock);
if (header->guard == GUARD || is_valid_entry(header->entry)) {
// decrement the allocations
HashEntry* entry = header->entry;
diff --git a/libc/bionic/ndk_cruft.cpp b/libc/bionic/ndk_cruft.cpp
index 8b34495..b299684 100644
--- a/libc/bionic/ndk_cruft.cpp
+++ b/libc/bionic/ndk_cruft.cpp
@@ -340,7 +340,7 @@ extern "C" pid_t __pthread_gettid(pthread_t t) {
return pthread_gettid_np(t);
}
-// Older versions of appportable used dlmalloc directly instead of malloc,
+// Older versions of apportable used dlmalloc directly instead of malloc,
// so export this compatibility shim that simply calls malloc.
extern "C" void* dlmalloc(size_t size) {
return malloc(size);
@@ -369,3 +369,26 @@ extern "C" void endusershell() { }
// This is never implemented in bionic, only needed for ABI compatibility with the NDK.
extern "C" void endpwent() { }
+
+// Since dlmalloc_inspect_all and dlmalloc_trim are exported for systems
+// that use dlmalloc, be consistent and export them everywhere.
+#if defined(USE_JEMALLOC)
+extern "C" void dlmalloc_inspect_all(void (*)(void*, void*, size_t, void*), void*) {
+}
+#else
+extern "C" void dlmalloc_inspect_all_real(void (*)(void*, void*, size_t, void*), void*);
+extern "C" void dlmalloc_inspect_all(void (*handler)(void*, void*, size_t, void*), void* arg) {
+ dlmalloc_inspect_all_real(handler, arg);
+}
+#endif
+
+#if defined(USE_JEMALLOC)
+extern "C" int dlmalloc_trim(size_t) {
+ return 0;
+}
+#else
+extern "C" int dlmalloc_trim_real(size_t);
+extern "C" int dlmalloc_trim(size_t pad) {
+ return dlmalloc_trim_real(pad);
+}
+#endif
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index 4fec753..851fc3d 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -501,6 +501,12 @@ static int __pthread_mutex_lock_with_timeout(pthread_mutex_internal_t* mutex,
}
int pthread_mutex_lock(pthread_mutex_t* mutex_interface) {
+#if !defined(__LP64__)
+ if (mutex_interface == NULL) {
+ return EINVAL;
+ }
+#endif
+
pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
@@ -516,6 +522,12 @@ int pthread_mutex_lock(pthread_mutex_t* mutex_interface) {
}
int pthread_mutex_unlock(pthread_mutex_t* mutex_interface) {
+#if !defined(__LP64__)
+ if (mutex_interface == NULL) {
+ return EINVAL;
+ }
+#endif
+
pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
diff --git a/libc/bionic/sigqueue.cpp b/libc/bionic/sigqueue.cpp
index 39c8798..8741460 100644
--- a/libc/bionic/sigqueue.cpp
+++ b/libc/bionic/sigqueue.cpp
@@ -31,7 +31,7 @@
#include <sys/types.h>
#include <unistd.h>
-extern "C" int __rt_sigqueueinfo(pid_t, int, siginfo_t*);
+extern "C" int ___rt_sigqueueinfo(pid_t, int, siginfo_t*);
int sigqueue(pid_t pid, int signo, const sigval value) {
siginfo_t info;
@@ -42,5 +42,5 @@ int sigqueue(pid_t pid, int signo, const sigval value) {
info.si_uid = getuid();
info.si_value = value;
- return __rt_sigqueueinfo(pid, signo, &info);
+ return ___rt_sigqueueinfo(pid, signo, &info);
}
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index aae99b1..c436a16 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -598,6 +598,16 @@ int __system_property_area_init()
return map_prop_area_rw();
}
+unsigned int __system_property_area_serial()
+{
+ prop_area *pa = __system_property_area__;
+ if (!pa) {
+ return -1;
+ }
+ // Make sure this read fulfilled before __system_property_serial
+ return atomic_load_explicit(&(pa->serial), memory_order_acquire);
+}
+
const prop_info *__system_property_find(const char *name)
{
if (__predict_false(compat_mode)) {
diff --git a/libc/dns/include/resolv_netid.h b/libc/dns/include/resolv_netid.h
index 1d0f869..d364645 100644
--- a/libc/dns/include/resolv_netid.h
+++ b/libc/dns/include/resolv_netid.h
@@ -53,10 +53,37 @@ struct addrinfo;
#define __used_in_netd __attribute__((visibility ("default")))
+/*
+ * A struct to capture context relevant to network operations.
+ *
+ * Application and DNS netids/marks can differ from one another under certain
+ * circumstances, notably when a VPN applies to the given uid's traffic but the
+ * VPN network does not have its own DNS servers explicitly provisioned.
+ *
+ * The introduction of per-UID routing means the uid is also an essential part
+ * of the evaluation context. Its proper uninitialized value is
+ * NET_CONTEXT_INVALID_UID.
+ */
+struct android_net_context {
+ unsigned app_netid;
+ unsigned app_mark;
+ unsigned dns_netid;
+ unsigned dns_mark;
+ uid_t uid;
+} __attribute__((packed));
+
+#define NET_CONTEXT_INVALID_UID ((uid_t)-1)
+
struct hostent *android_gethostbyaddrfornet(const void *, socklen_t, int, unsigned, unsigned) __used_in_netd;
struct hostent *android_gethostbynamefornet(const char *, int, unsigned, unsigned) __used_in_netd;
int android_getaddrinfofornet(const char *, const char *, const struct addrinfo *, unsigned,
- unsigned, struct addrinfo **) __used_in_netd;
+ unsigned, struct addrinfo **) __used_in_netd;
+/*
+ * TODO: consider refactoring android_getaddrinfo_proxy() to serve as an
+ * explore_fqdn() dispatch table method, with the below function only making DNS calls.
+ */
+int android_getaddrinfofornetcontext(const char *, const char *, const struct addrinfo *,
+ const struct android_net_context *, struct addrinfo **) __used_in_netd;
/* set name servers for a network */
extern void _resolv_set_nameservers_for_net(unsigned netid,
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
index c73c085..829b679 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -218,7 +218,7 @@ struct res_target {
static int str2number(const char *);
static int explore_fqdn(const struct addrinfo *, const char *,
- const char *, struct addrinfo **, unsigned netid, unsigned mark);
+ const char *, struct addrinfo **, const struct android_net_context *);
static int explore_null(const struct addrinfo *,
const char *, struct addrinfo **);
static int explore_numeric(const struct addrinfo *, const char *,
@@ -244,6 +244,7 @@ static void _endhtent(FILE **);
static struct addrinfo *_gethtent(FILE **, const char *,
const struct addrinfo *);
static int _files_getaddrinfo(void *, void *, va_list);
+static int _find_src_addr(const struct sockaddr *, struct sockaddr *, unsigned , uid_t);
static int res_queryN(const char *, struct res_target *, res_state);
static int res_searchN(const char *, struct res_target *, res_state);
@@ -360,29 +361,6 @@ str2number(const char *p)
}
/*
- * Connect a UDP socket to a given unicast address. This will cause no network
- * traffic, but will fail fast if the system has no or limited reachability to
- * the destination (e.g., no IPv4 address, no IPv6 default route, ...).
- */
-static int
-_test_connect(int pf, struct sockaddr *addr, size_t addrlen, unsigned mark) {
- int s = socket(pf, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
- if (s < 0)
- return 0;
- if (mark != MARK_UNSET && setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
- return 0;
- int ret;
- do {
- ret = __connect(s, addr, addrlen);
- } while (ret < 0 && errno == EINTR);
- int success = (ret == 0);
- do {
- ret = close(s);
- } while (ret < 0 && errno == EINTR);
- return success;
-}
-
-/*
* The following functions determine whether IPv4 or IPv6 connectivity is
* available in order to implement AI_ADDRCONFIG.
*
@@ -392,24 +370,24 @@ _test_connect(int pf, struct sockaddr *addr, size_t addrlen, unsigned mark) {
* so checking for connectivity is the next best thing.
*/
static int
-_have_ipv6(unsigned mark) {
+_have_ipv6(unsigned mark, uid_t uid) {
static const struct sockaddr_in6 sin6_test = {
.sin6_family = AF_INET6,
.sin6_addr.s6_addr = { // 2000::
0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
sockaddr_union addr = { .in6 = sin6_test };
- return _test_connect(PF_INET6, &addr.generic, sizeof(addr.in6), mark);
+ return _find_src_addr(&addr.generic, NULL, mark, uid) == 1;
}
static int
-_have_ipv4(unsigned mark) {
+_have_ipv4(unsigned mark, uid_t uid) {
static const struct sockaddr_in sin_test = {
.sin_family = AF_INET,
.sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8
};
sockaddr_union addr = { .in = sin_test };
- return _test_connect(PF_INET, &addr.generic, sizeof(addr.in), mark);
+ return _find_src_addr(&addr.generic, NULL, mark, uid) == 1;
}
bool readBE32(FILE* fp, int32_t* result) {
@@ -474,7 +452,7 @@ android_getaddrinfo_proxy(
int result_code = (int)strtol(buf, NULL, 10);
// verify the code itself
- if (result_code != DnsProxyQueryResult ) {
+ if (result_code != DnsProxyQueryResult) {
fread(buf, 1, sizeof(buf), proxy);
goto exit;
}
@@ -589,6 +567,21 @@ int
android_getaddrinfofornet(const char *hostname, const char *servname,
const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res)
{
+ struct android_net_context netcontext = {
+ .app_netid = netid,
+ .app_mark = mark,
+ .dns_netid = netid,
+ .dns_mark = mark,
+ .uid = NET_CONTEXT_INVALID_UID,
+ };
+ return android_getaddrinfofornetcontext(hostname, servname, hints, &netcontext, res);
+}
+
+int
+android_getaddrinfofornetcontext(const char *hostname, const char *servname,
+ const struct addrinfo *hints, const struct android_net_context *netcontext,
+ struct addrinfo **res)
+{
struct addrinfo sentinel;
struct addrinfo *cur;
int error = 0;
@@ -601,6 +594,7 @@ android_getaddrinfofornet(const char *hostname, const char *servname,
/* servname is allowed to be NULL */
/* hints is allowed to be NULL */
assert(res != NULL);
+ assert(netcontext != NULL);
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
pai = &ai;
@@ -731,7 +725,8 @@ android_getaddrinfofornet(const char *hostname, const char *servname,
ERR(EAI_NONAME);
#if defined(__ANDROID__)
- int gai_error = android_getaddrinfo_proxy(hostname, servname, hints, res, netid);
+ int gai_error = android_getaddrinfo_proxy(
+ hostname, servname, hints, res, netcontext->app_netid);
if (gai_error != EAI_SYSTEM) {
return gai_error;
}
@@ -763,8 +758,8 @@ android_getaddrinfofornet(const char *hostname, const char *servname,
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
pai->ai_protocol = ex->e_protocol;
- error = explore_fqdn(pai, hostname, servname,
- &cur->ai_next, netid, mark);
+ error = explore_fqdn(
+ pai, hostname, servname, &cur->ai_next, netcontext);
while (cur && cur->ai_next)
cur = cur->ai_next;
@@ -797,7 +792,8 @@ android_getaddrinfofornet(const char *hostname, const char *servname,
*/
static int
explore_fqdn(const struct addrinfo *pai, const char *hostname,
- const char *servname, struct addrinfo **res, unsigned netid, unsigned mark)
+ const char *servname, struct addrinfo **res,
+ const struct android_net_context *netcontext)
{
struct addrinfo *result;
struct addrinfo *cur;
@@ -823,7 +819,7 @@ explore_fqdn(const struct addrinfo *pai, const char *hostname,
return 0;
switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
- default_dns_files, hostname, pai, netid, mark)) {
+ default_dns_files, hostname, pai, netcontext)) {
case NS_TRYAGAIN:
error = EAI_AGAIN;
goto free;
@@ -1763,13 +1759,13 @@ _rfc6724_compare(const void *ptr1, const void* ptr2)
* address. src_addr must be large enough to hold a struct sockaddr_in6.
*
* Returns 1 if a source address was found, 0 if the address is unreachable,
- * and -1 if a fatal error occurred. If 0 or 1, the contents of src_addr are
+ * and -1 if a fatal error occurred. If 0 or -1, the contents of src_addr are
* undefined.
*/
/*ARGSUSED*/
static int
-_find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned mark)
+_find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned mark, uid_t uid)
{
int sock;
int ret;
@@ -1797,6 +1793,8 @@ _find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned
}
if (mark != MARK_UNSET && setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
return 0;
+ if (uid > 0 && uid != NET_CONTEXT_INVALID_UID && fchown(sock, uid, (gid_t)-1) < 0)
+ return 0;
do {
ret = __connect(sock, addr, len);
} while (ret == -1 && errno == EINTR);
@@ -1806,7 +1804,7 @@ _find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned
return 0;
}
- if (getsockname(sock, src_addr, &len) == -1) {
+ if (src_addr && getsockname(sock, src_addr, &len) == -1) {
close(sock);
return -1;
}
@@ -1821,7 +1819,7 @@ _find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned
/*ARGSUSED*/
static void
-_rfc6724_sort(struct addrinfo *list_sentinel, unsigned mark)
+_rfc6724_sort(struct addrinfo *list_sentinel, unsigned mark, uid_t uid)
{
struct addrinfo *cur;
int nelem = 0, i;
@@ -1848,7 +1846,7 @@ _rfc6724_sort(struct addrinfo *list_sentinel, unsigned mark)
elems[i].ai = cur;
elems[i].original_order = i;
- has_src_addr = _find_src_addr(cur->ai_addr, &elems[i].src_addr.generic, mark);
+ has_src_addr = _find_src_addr(cur->ai_addr, &elems[i].src_addr.generic, mark, uid);
if (has_src_addr == -1) {
goto error;
}
@@ -1879,12 +1877,11 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
struct addrinfo sentinel, *cur;
struct res_target q, q2;
res_state res;
- unsigned netid, mark;
+ const struct android_net_context *netcontext;
name = va_arg(ap, char *);
pai = va_arg(ap, const struct addrinfo *);
- netid = va_arg(ap, unsigned);
- mark = va_arg(ap, unsigned);
+ netcontext = va_arg(ap, const struct android_net_context *);
//fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name);
memset(&q, 0, sizeof(q));
@@ -1913,8 +1910,8 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
q.anslen = sizeof(buf->buf);
int query_ipv6 = 1, query_ipv4 = 1;
if (pai->ai_flags & AI_ADDRCONFIG) {
- query_ipv6 = _have_ipv6(mark);
- query_ipv4 = _have_ipv4(mark);
+ query_ipv6 = _have_ipv6(netcontext->app_mark, netcontext->uid);
+ query_ipv4 = _have_ipv4(netcontext->app_mark, netcontext->uid);
}
if (query_ipv6) {
q.qtype = T_AAAA;
@@ -1966,8 +1963,8 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
* fully populate the thread private data here, but if we get down there
* and have a cache hit that would be wasted, so we do the rest there on miss
*/
- res_setnetid(res, netid);
- res_setmark(res, mark);
+ res_setnetid(res, netcontext->dns_netid);
+ res_setmark(res, netcontext->dns_mark);
if (res_searchN(name, &q, res) < 0) {
__res_put_state(res);
free(buf);
@@ -1999,7 +1996,7 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
}
}
- _rfc6724_sort(&sentinel, netid);
+ _rfc6724_sort(&sentinel, netcontext->app_mark, netcontext->uid);
__res_put_state(res);
diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
index 8f5800a..42f0d0a 100644
--- a/libc/dns/net/gethnamaddr.c
+++ b/libc/dns/net/gethnamaddr.c
@@ -640,6 +640,9 @@ android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen
ptr += size;
}
+ // Fix alignment after variable-length data.
+ ptr = (char*)ALIGN(ptr);
+
int aliases_len = ((int)(aliases - aliases_ptrs) + 1) * sizeof(*hp->h_aliases);
if (ptr + aliases_len > hbuf_end) {
goto nospc;
@@ -674,6 +677,9 @@ android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen
ptr += size;
}
+ // Fix alignment after variable-length data.
+ ptr = (char*)ALIGN(ptr);
+
int addrs_len = ((int)(addr_p - addr_ptrs) + 1) * sizeof(*hp->h_addr_list);
if (ptr + addrs_len > hbuf_end) {
goto nospc;
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index f10a8a2..40f610f 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -73,6 +73,13 @@ enum {
*/
ANDROID_DLEXT_FORCE_LOAD = 0x40,
+ /* When set, if the minimum p_vaddr of the ELF file's PT_LOAD segments is non-zero,
+ * the dynamic linker will load it at that address.
+ *
+ * This flag is for ART internal use only.
+ */
+ ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80,
+
/* Mask of valid bits */
ANDROID_DLEXT_VALID_FLAG_BITS = ANDROID_DLEXT_RESERVED_ADDRESS |
ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
@@ -80,7 +87,8 @@ enum {
ANDROID_DLEXT_USE_RELRO |
ANDROID_DLEXT_USE_LIBRARY_FD |
ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
- ANDROID_DLEXT_FORCE_LOAD,
+ ANDROID_DLEXT_FORCE_LOAD |
+ ANDROID_DLEXT_FORCE_FIXED_VADDR,
};
typedef struct {
diff --git a/libc/include/elf.h b/libc/include/elf.h
index df768ba..eaad1d3 100644
--- a/libc/include/elf.h
+++ b/libc/include/elf.h
@@ -34,6 +34,11 @@
#include <machine/elf_machdep.h>
+#define ELF32_R_INFO(sym, type) ((((Elf32_Word)sym) << 8) | ((type) & 0xff))
+#define ELF64_R_INFO(sym, type) ((((Elf64_Xword)sym) << 32) | ((type) & 0xffffffff))
+
+typedef __s64 Elf32_Sxword;
+
typedef struct {
__u32 a_type;
union {
@@ -187,6 +192,11 @@ typedef struct {
#define STT_LOPROC 13
#define STT_HIPROC 15
+#define STV_DEFAULT 0
+#define STV_INTERNAL 1
+#define STV_HIDDEN 2
+#define STV_PROTECTED 3
+
/* The kernel uses NT_PRFPREG but glibc also offers NT_FPREGSET */
#define NT_FPREGSET NT_PRFPREG
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index cf09445..260ae5b 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -46,9 +46,6 @@ typedef struct {
typedef long pthread_mutexattr_t;
-#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER
-#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
-
enum {
PTHREAD_MUTEX_NORMAL = 0,
PTHREAD_MUTEX_RECURSIVE = 1,
@@ -179,10 +176,18 @@ int pthread_mutexattr_settype(pthread_mutexattr_t*, int) __nonnull((1));
int pthread_mutex_destroy(pthread_mutex_t*) __nonnull((1));
int pthread_mutex_init(pthread_mutex_t*, const pthread_mutexattr_t*) __nonnull((1));
+#if !defined(__LP64__)
+int pthread_mutex_lock(pthread_mutex_t*) /* __nonnull((1)) */;
+#else
int pthread_mutex_lock(pthread_mutex_t*) __nonnull((1));
+#endif
int pthread_mutex_timedlock(pthread_mutex_t*, const struct timespec*) __nonnull((1, 2));
int pthread_mutex_trylock(pthread_mutex_t*) __nonnull((1));
+#if !defined(__LP4__)
+int pthread_mutex_unlock(pthread_mutex_t*) /* __nonnull((1)) */;
+#else
int pthread_mutex_unlock(pthread_mutex_t*) __nonnull((1));
+#endif
int pthread_once(pthread_once_t*, void (*)(void)) __nonnull((1, 2));
diff --git a/libc/include/sys/_system_properties.h b/libc/include/sys/_system_properties.h
index 7ff3ded..a0315b5 100644
--- a/libc/include/sys/_system_properties.h
+++ b/libc/include/sys/_system_properties.h
@@ -81,7 +81,6 @@ struct prop_msg
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_VENDOR_BUILD "/vendor/build.prop"
-#define PROP_PATH_BOOTIMAGE_BUILD "/build.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
#define PROP_PATH_FACTORY "/factory/factory.prop"
@@ -98,6 +97,30 @@ int __system_property_set_filename(const char *filename);
*/
int __system_property_area_init();
+/* Read the global serial number of the system properties
+**
+** Called to predict if a series of cached __system_property_find
+** objects will have seen __system_property_serial values change.
+** But also aids the converse, as changes in the global serial can
+** also be used to predict if a failed __system_property_find
+** could in-turn now find a new object; thus preventing the
+** cycles of effort to poll __system_property_find.
+**
+** Typically called at beginning of a cache cycle to signal if _any_ possible
+** changes have occurred since last. If there is, one may check each individual
+** __system_property_serial to confirm dirty, or __system_property_find
+** to check if the property now exists. If a call to __system_property_add
+** or __system_property_update has completed between two calls to
+** __system_property_area_serial then the second call will return a larger
+** value than the first call. Beware of race conditions as changes to the
+** properties are not atomic, the main value of this call is to determine
+** whether the expensive __system_property_find is worth retrying to see if
+** a property now exists.
+**
+** Returns the serial number on success, -1 on error.
+*/
+unsigned int __system_property_area_serial();
+
/* Add a new system property. Can only be done by a single
** process that has write access to the property area, and
** that process must handle sequencing to ensure the property
diff --git a/libc/include/sys/personality.h b/libc/include/sys/personality.h
index 8a023f9..7764468 100644
--- a/libc/include/sys/personality.h
+++ b/libc/include/sys/personality.h
@@ -34,7 +34,7 @@
__BEGIN_DECLS
-extern int personality (unsigned long persona);
+extern int personality (unsigned int persona);
__END_DECLS
diff --git a/libc/arch-mips/string/memset.c b/libc/include/sys/procfs.h
index 41dafb2..b5b1a46 100644
--- a/libc/arch-mips/string/memset.c
+++ b/libc/include/sys/procfs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,20 +25,26 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <string.h>
-#include <stdint.h>
-
-void* memset(void* dst, int c, size_t n)
-{
- char* q = dst;
- char* end = q + n;
-
- for (;;) {
- if (q >= end) break; *q++ = (char) c;
- if (q >= end) break; *q++ = (char) c;
- if (q >= end) break; *q++ = (char) c;
- if (q >= end) break; *q++ = (char) c;
- }
-
- return dst;
-}
+
+#ifndef _SYS_PROCFS_H_
+#define _SYS_PROCFS_H_
+
+#include <sys/cdefs.h>
+#include <sys/ucontext.h>
+
+__BEGIN_DECLS
+
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[NGREG];
+
+typedef fpregset_t elf_fpregset_t;
+
+typedef elf_gregset_t prgregset_t;
+typedef elf_fpregset_t prfpregset_t;
+
+typedef pid_t lwpid_t;
+typedef void* psaddr_t;
+
+__END_DECLS
+
+#endif /* _SYS_PROCFS_H_ */
diff --git a/libc/include/sys/ptrace.h b/libc/include/sys/ptrace.h
index 8bba9fe..4b881e7 100644
--- a/libc/include/sys/ptrace.h
+++ b/libc/include/sys/ptrace.h
@@ -34,11 +34,31 @@
__BEGIN_DECLS
-/* glibc uses different names from the kernel for these two... */
+/* glibc uses different PTRACE_ names from the kernel for these two... */
#define PTRACE_POKEUSER PTRACE_POKEUSR
#define PTRACE_PEEKUSER PTRACE_PEEKUSR
-extern long ptrace(int, ...);
+/* glibc exports a different set of PT_ names too... */
+#define PT_TRACE_ME PTRACE_TRACEME
+#define PT_READ_I PTRACE_PEEKTEXT
+#define PT_READ_D PTRACE_PEEKDATA
+#define PT_READ_U PTRACE_PEEKUSR
+#define PT_WRITE_I PTRACE_POKETEXT
+#define PT_WRITE_D PTRACE_POKEDATA
+#define PT_WRITE_U PTRACE_POKEUSR
+#define PT_CONT PTRACE_CONT
+#define PT_KILL PTRACE_KILL
+#define PT_STEP PTRACE_SINGLESTEP
+#define PT_GETFPREGS PTRACE_GETFPREGS
+#define PT_ATTACH PTRACE_ATTACH
+#define PT_DETACH PTRACE_DETACH
+#define PT_SYSCALL PTRACE_SYSCALL
+#define PT_SETOPTIONS PTRACE_SETOPTIONS
+#define PT_GETEVENTMSG PTRACE_GETEVENTMSG
+#define PT_GETSIGINFO PTRACE_GETSIGINFO
+#define PT_SETSIGINFO PTRACE_SETSIGINFO
+
+long ptrace(int, ...);
__END_DECLS
diff --git a/libc/include/sys/ucontext.h b/libc/include/sys/ucontext.h
index b68d704..399458e 100644
--- a/libc/include/sys/ucontext.h
+++ b/libc/include/sys/ucontext.h
@@ -59,6 +59,7 @@ enum {
typedef int greg_t;
typedef greg_t gregset_t[NGREG];
+typedef struct user_fpregs fpregset_t;
#include <asm/sigcontext.h>
typedef struct sigcontext mcontext_t;
@@ -82,6 +83,13 @@ typedef struct ucontext {
typedef unsigned long greg_t;
typedef greg_t gregset_t[NGREG];
+struct user_fpsimd_struct {
+ long double vregs[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+};
+typedef struct user_fpsimd_struct fpregset_t;
+
#include <asm/sigcontext.h>
typedef struct sigcontext mcontext_t;
diff --git a/libc/include/sys/uio.h b/libc/include/sys/uio.h
index 0251716..187ec22 100644
--- a/libc/include/sys/uio.h
+++ b/libc/include/sys/uio.h
@@ -34,8 +34,13 @@
__BEGIN_DECLS
-int readv(int, const struct iovec *, int);
-int writev(int, const struct iovec *, int);
+int readv(int, const struct iovec*, int);
+int writev(int, const struct iovec*, int);
+
+#if defined(__USE_GNU)
+ssize_t process_vm_readv(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long);
+ssize_t process_vm_writev(pid_t, const struct iovec*, unsigned long, const struct iovec*, unsigned long, unsigned long);
+#endif
__END_DECLS
diff --git a/libc/include/sys/wait.h b/libc/include/sys/wait.h
index 8d9a5f6..12b7308 100644
--- a/libc/include/sys/wait.h
+++ b/libc/include/sys/wait.h
@@ -45,6 +45,9 @@ __BEGIN_DECLS
#define WIFSTOPPED(s) (WTERMSIG(s) == 0x7f)
#define WIFSIGNALED(s) (WTERMSIG((s)+1) >= 2)
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | 0x7f)
+
extern pid_t wait(int *);
extern pid_t waitpid(pid_t, int *, int);
extern pid_t wait4(pid_t, int *, int, struct rusage *);
diff --git a/libc/libc.map b/libc/libc.map
new file mode 100644
index 0000000..47c52a4
--- /dev/null
+++ b/libc/libc.map
@@ -0,0 +1,1456 @@
+LIBC {
+ global:
+ __assert;
+ __assert2;
+ __atomic_cmpxchg; # arm
+ __atomic_dec; # arm
+ __atomic_inc; # arm
+ __atomic_swap; # arm
+ __b64_ntop;
+ __b64_pton;
+ __brk; # arm x86 mips
+ __cmpdf2; # arm
+ __cmsg_nxthdr;
+ __connect; # arm x86 mips
+ __ctype_get_mb_cur_max;
+ __cxa_atexit;
+ __cxa_finalize;
+ __cxa_thread_atexit_impl;
+ __divdf3; # arm
+ __divdi3; # arm x86 mips
+ __divsf3; # arm
+ __divsi3; # arm
+ __dn_comp;
+ __dn_count_labels;
+ __dn_skipname;
+ __epoll_pwait; # arm x86 mips
+ __eqdf2; # arm
+ __errno;
+ __exit; # arm x86 mips
+ __extendsfdf2; # arm
+ __fadvise64; # x86 mips
+ __fbufsize;
+ __fcntl64; # arm x86 mips
+ __FD_CLR_chk;
+ __FD_ISSET_chk;
+ __FD_SET_chk;
+ __fgets_chk;
+ __fixdfsi; # arm
+ __fixsfsi; # arm
+ __fixunssfsi; # arm
+ __flbf;
+ __floatdidf; # arm
+ __floatdisf; # arm
+ __floatsidf; # arm
+ __floatsisf; # arm
+ __floatundidf; # arm
+ __floatundisf; # arm
+ __floatunsidf; # arm
+ __floatunsisf; # arm
+ __fp_nquery;
+ __fp_query;
+ __fpclassify;
+ __fpclassifyd;
+ __fpclassifyf;
+ __fpclassifyl;
+ __fpending;
+ __fpurge;
+ __freadable;
+ __fsetlocking;
+ __fstatfs64; # arm x86 mips
+ __futex_wait; # arm x86 mips
+ __futex_wake; # arm x86 mips
+ __fwritable;
+ __gedf2; # arm
+ __get_h_errno;
+ __get_thread; # arm x86 mips
+ __get_tls; # arm x86 mips
+ __getcpu; # arm x86 mips
+ __getcwd; # arm x86 mips
+ __getdents64; # arm x86 mips
+ __getpid; # arm x86 mips
+ __getpriority; # arm x86 mips
+ __gnu_basename;
+ __gnu_ldivmod_helper; # arm
+ __gnu_strerror_r;
+ __gnu_uldivmod_helper; # arm
+ __gtdf2; # arm
+ __hostalias;
+ __ioctl; # arm x86 mips
+ __isfinite;
+ __isfinitef;
+ __isfinitel;
+ __isinf;
+ __isinff;
+ __isinfl;
+ __isnan;
+ __isnanf;
+ __isnanl;
+ __isnormal;
+ __isnormalf;
+ __isnormall;
+ __isthreaded;
+ __ledf2; # arm
+ __libc_current_sigrtmax;
+ __libc_current_sigrtmin;
+ __libc_init;
+ __llseek; # arm x86 mips
+ __loc_aton;
+ __loc_ntoa;
+ __lshrdi3; # arm
+ __ltdf2; # arm
+ __memchr_chk;
+ __memcpy_chk;
+ __memmove_chk;
+ __memrchr_chk;
+ __memset_chk;
+ __mmap2; # arm x86 mips
+ __moddi3; # x86 mips
+ __muldf3; # arm
+ __muldi3; # arm
+ __mulsf3; # arm
+ __nedf2; # arm
+ __ns_format_ttl; # arm x86 mips
+ __ns_get16; # arm x86 mips
+ __ns_get32; # arm x86 mips
+ __ns_initparse; # arm x86 mips
+ __ns_makecanon; # arm x86 mips
+ __ns_msg_getflag; # arm x86 mips
+ __ns_name_compress; # arm x86 mips
+ __ns_name_ntol; # arm x86 mips
+ __ns_name_ntop; # arm x86 mips
+ __ns_name_pack; # arm x86 mips
+ __ns_name_pton; # arm x86 mips
+ __ns_name_rollback; # arm x86 mips
+ __ns_name_skip; # arm x86 mips
+ __ns_name_uncompress; # arm x86 mips
+ __ns_name_unpack; # arm x86 mips
+ __ns_parserr; # arm x86 mips
+ __ns_put16; # arm x86 mips
+ __ns_put32; # arm x86 mips
+ __ns_samename; # arm x86 mips
+ __ns_skiprr; # arm x86 mips
+ __ns_sprintrr; # arm x86 mips
+ __ns_sprintrrf; # arm x86 mips
+ __open; # arm x86 mips
+ __open_2;
+ __openat; # arm x86 mips
+ __openat_2;
+ __p_cdname;
+ __p_cdnname;
+ __p_class;
+ __p_class_syms;
+ __p_fqname;
+ __p_fqnname;
+ __p_option;
+ __p_query;
+ __p_rcode;
+ __p_secstodate;
+ __p_time;
+ __p_type;
+ __p_type_syms;
+ __page_shift; # arm x86 mips
+ __page_size; # arm x86 mips
+ __poll_chk;
+ __popcount_tab; # arm
+ __popcountsi2; # arm x86 mips
+ __ppoll; # arm x86 mips
+ __ppoll_chk;
+ __pread64_chk;
+ __pread_chk;
+ __progname;
+ __pselect6; # arm x86 mips
+ __pthread_cleanup_pop;
+ __pthread_cleanup_push;
+ __pthread_gettid; # arm x86 mips
+ __ptrace; # arm x86 mips
+ __putlong;
+ __putshort;
+ __read_chk;
+ __readlink_chk;
+ __readlinkat_chk;
+ __reboot; # arm x86 mips
+ __recvfrom_chk;
+ __register_atfork;
+ __res_close;
+ __res_dnok;
+ __res_hnok;
+ __res_hostalias;
+ __res_isourserver;
+ __res_mailok;
+ __res_nameinquery;
+ __res_nclose;
+ __res_ninit;
+ __res_nmkquery;
+ __res_nquery;
+ __res_nquerydomain;
+ __res_nsearch;
+ __res_nsend;
+ __res_ownok;
+ __res_queriesmatch;
+ __res_querydomain;
+ __res_send;
+ __res_send_setqhook;
+ __res_send_setrhook;
+ __restore_core_regs; # arm
+ __rt_sigaction; # arm x86 mips
+ __rt_sigpending; # arm x86 mips
+ __rt_sigprocmask; # arm x86 mips
+ __rt_sigsuspend; # arm x86 mips
+ __rt_sigtimedwait; # arm x86 mips
+ __sched_cpualloc;
+ __sched_cpucount;
+ __sched_cpufree;
+ __sched_getaffinity; # arm x86 mips
+ __sclose; # arm x86 mips
+ __sdidinit; # arm x86 mips
+ __set_errno; # arm x86 mips
+ __set_thread_area; # x86
+ __set_tid_address; # arm x86 mips
+ __set_tls; # arm mips
+ __sF;
+ __sflags; # arm x86 mips
+ __sflush; # arm x86 mips
+ __sfp; # arm x86 mips
+ __sglue; # arm x86 mips
+ __sigaction; # arm x86 mips
+ __signalfd4; # arm x86 mips
+ __sinit; # arm x86 mips
+ __smakebuf; # arm x86 mips
+ __snprintf_chk;
+ __socket; # arm x86 mips
+ __sprintf_chk;
+ __sread; # arm x86 mips
+ __srefill; # arm x86 mips
+ __srget; # arm x86 mips
+ __sseek; # arm x86 mips
+ __stack_chk_fail;
+ __stack_chk_guard;
+ __statfs64; # arm x86 mips
+ __stpcpy_chk;
+ __stpncpy_chk;
+ __stpncpy_chk2;
+ __strcat_chk;
+ __strchr_chk;
+ __strcpy_chk;
+ __strlcat_chk;
+ __strlcpy_chk;
+ __strlen_chk;
+ __strncat_chk;
+ __strncpy_chk;
+ __strncpy_chk2;
+ __strrchr_chk;
+ __subdf3; # arm
+ __subsf3; # arm
+ __swbuf; # arm x86 mips
+ __swrite; # arm x86 mips
+ __swsetup; # arm x86 mips
+ __sym_ntop;
+ __sym_ntos;
+ __sym_ston;
+ __system_properties_init;
+ __system_property_add;
+ __system_property_area__;
+ __system_property_area_init;
+ __system_property_area_serial;
+ __system_property_find;
+ __system_property_find_nth;
+ __system_property_foreach;
+ __system_property_get;
+ __system_property_read;
+ __system_property_serial;
+ __system_property_set;
+ __system_property_set_filename;
+ __system_property_update;
+ __system_property_wait_any;
+ __timer_create; # arm x86 mips
+ __timer_delete; # arm x86 mips
+ __timer_getoverrun; # arm x86 mips
+ __timer_gettime; # arm x86 mips
+ __timer_settime; # arm x86 mips
+ __truncdfsf2; # arm
+ __udivdi3; # arm x86 mips
+ __udivsi3; # arm
+ __umask_chk;
+ __umoddi3; # x86 mips
+ __unorddf2; # arm
+ __unordsf2; # arm
+ __vsnprintf_chk;
+ __vsprintf_chk;
+ __wait4; # arm x86 mips
+ __waitid; # arm x86 mips
+ _ctype_;
+ _Exit;
+ _exit;
+ _flush_cache; # mips
+ _flushlbf;
+ _fwalk; # arm x86 mips
+ _getlong;
+ _getshort;
+ _longjmp;
+ _resolv_delete_cache_for_net;
+ _resolv_flush_cache_for_net;
+ _resolv_set_nameservers_for_net;
+ _setjmp;
+ _tolower;
+ _tolower_tab_; # arm x86 mips
+ _toupper;
+ _toupper_tab_; # arm x86 mips
+ abort;
+ abs;
+ accept;
+ accept4;
+ access;
+ acct;
+ alarm;
+ alphasort;
+ alphasort64;
+ android_getaddrinfofornet;
+ android_getaddrinfofornetcontext;
+ android_gethostbyaddrfornet;
+ android_gethostbynamefornet;
+ android_set_abort_message;
+ arc4random;
+ arc4random_addrandom; # arm x86 mips
+ arc4random_buf;
+ arc4random_stir; # arm x86 mips
+ arc4random_uniform;
+ asctime;
+ asctime64; # arm x86 mips
+ asctime64_r; # arm x86 mips
+ asctime_r;
+ asprintf;
+ at_quick_exit;
+ atof;
+ atoi;
+ atol;
+ atoll;
+ basename;
+ basename_r; # arm x86 mips
+ bcopy; # arm x86 mips
+ bind;
+ bindresvport;
+ brk;
+ bsd_signal; # arm x86 mips
+ bsearch;
+ btowc;
+ bzero; # arm x86 mips
+ c16rtomb;
+ c32rtomb;
+ cacheflush; # arm mips
+ calloc;
+ capget;
+ capset;
+ cfgetispeed;
+ cfgetospeed;
+ cfmakeraw;
+ cfsetispeed;
+ cfsetospeed;
+ cfsetspeed;
+ chdir;
+ chmod;
+ chown;
+ chroot;
+ clearenv;
+ clearerr;
+ clearerr_unlocked;
+ clock;
+ clock_getcpuclockid;
+ clock_getres;
+ clock_gettime;
+ clock_nanosleep;
+ clock_settime;
+ clone;
+ close;
+ closedir;
+ closelog;
+ connect;
+ creat;
+ creat64;
+ ctime;
+ ctime64; # arm x86 mips
+ ctime64_r; # arm x86 mips
+ ctime_r;
+ daemon;
+ daylight;
+ delete_module;
+ difftime;
+ dirfd;
+ dirname;
+ dirname_r; # arm x86 mips
+ div;
+ dn_expand;
+ dprintf;
+ drand48;
+ dup;
+ dup2;
+ dup3;
+ duplocale;
+ endmntent;
+ endpwent;
+ endservent;
+ endusershell;
+ endutent;
+ environ;
+ epoll_create;
+ epoll_create1;
+ epoll_ctl;
+ epoll_pwait;
+ epoll_wait;
+ erand48;
+ err;
+ error;
+ error_at_line;
+ error_message_count;
+ error_one_per_line;
+ error_print_progname;
+ errx;
+ ether_aton;
+ ether_aton_r;
+ ether_ntoa;
+ ether_ntoa_r;
+ eventfd;
+ eventfd_read;
+ eventfd_write;
+ execl;
+ execle;
+ execlp;
+ execv;
+ execve;
+ execvp;
+ execvpe;
+ exit;
+ faccessat;
+ fake_gmtime_r; # arm x86 mips
+ fake_localtime_r; # arm x86 mips
+ fallocate;
+ fallocate64;
+ fchdir;
+ fchmod;
+ fchmodat;
+ fchown;
+ fchownat;
+ fclose;
+ fcntl;
+ fdatasync;
+ fdopen;
+ fdopendir;
+ fdprintf; # arm x86 mips
+ feof;
+ feof_unlocked;
+ ferror;
+ ferror_unlocked;
+ fflush;
+ ffs;
+ fgetc;
+ fgetln;
+ fgetpos;
+ fgets;
+ fgetwc;
+ fgetws;
+ fgetxattr;
+ fileno;
+ flistxattr;
+ flock;
+ flockfile;
+ fmemopen;
+ fnmatch;
+ fopen;
+ fork;
+ forkpty;
+ fpathconf;
+ fprintf;
+ fpurge;
+ fputc;
+ fputs;
+ fputwc;
+ fputws;
+ fread;
+ free;
+ free_malloc_leak_info;
+ freeaddrinfo;
+ freelocale;
+ fremovexattr;
+ freopen;
+ fscanf;
+ fseek;
+ fseeko;
+ fsetpos;
+ fsetxattr;
+ fstat;
+ fstat64;
+ fstatat;
+ fstatat64;
+ fstatfs;
+ fstatfs64;
+ fstatvfs;
+ fstatvfs64;
+ fsync;
+ ftell;
+ ftello;
+ ftime; # arm x86 mips
+ ftok;
+ ftruncate;
+ ftruncate64;
+ ftrylockfile;
+ fts_children;
+ fts_close;
+ fts_open;
+ fts_read;
+ fts_set;
+ ftw;
+ ftw64;
+ funlockfile;
+ funopen;
+ futimens;
+ fwide;
+ fwprintf;
+ fwrite;
+ fwscanf;
+ gai_strerror;
+ get_avphys_pages;
+ get_malloc_leak_info;
+ get_nprocs;
+ get_nprocs_conf;
+ get_phys_pages;
+ getaddrinfo;
+ getauxval;
+ getc;
+ getc_unlocked;
+ getchar;
+ getchar_unlocked;
+ getcwd;
+ getdelim;
+ getdents; # arm x86 mips
+ getdtablesize; # arm x86 mips
+ getegid;
+ getenv;
+ geteuid;
+ getgid;
+ getgrgid;
+ getgrnam;
+ getgrouplist;
+ getgroups;
+ gethostbyaddr;
+ gethostbyaddr_r;
+ gethostbyname;
+ gethostbyname2;
+ gethostbyname2_r;
+ gethostbyname_r;
+ gethostent;
+ gethostname;
+ getitimer;
+ getline;
+ getlogin;
+ getmntent;
+ getmntent_r;
+ getnameinfo;
+ getnetbyaddr;
+ getnetbyname;
+ getopt;
+ getopt_long;
+ getopt_long_only;
+ getpagesize;
+ getpeername;
+ getpgid;
+ getpgrp;
+ getpid;
+ getppid;
+ getpriority;
+ getprogname;
+ getprotobyname;
+ getprotobynumber;
+ getpt;
+ getpwnam;
+ getpwnam_r;
+ getpwuid;
+ getpwuid_r;
+ getresgid;
+ getresuid;
+ getrlimit;
+ getrlimit64;
+ getrusage;
+ gets;
+ getservbyname;
+ getservbyport;
+ getservent;
+ getsid;
+ getsockname;
+ getsockopt;
+ gettid;
+ gettimeofday;
+ getuid;
+ getusershell;
+ getutent;
+ getwc;
+ getwchar;
+ getxattr;
+ gmtime;
+ gmtime64; # arm x86 mips
+ gmtime64_r; # arm x86 mips
+ gmtime_r;
+ grantpt;
+ herror;
+ hstrerror;
+ htonl;
+ htons;
+ if_indextoname;
+ if_nametoindex;
+ imaxabs;
+ imaxdiv;
+ index; # arm x86 mips
+ inet_addr;
+ inet_aton;
+ inet_lnaof;
+ inet_makeaddr;
+ inet_netof;
+ inet_network;
+ inet_nsap_addr;
+ inet_nsap_ntoa;
+ inet_ntoa;
+ inet_ntop;
+ inet_pton;
+ init_module;
+ initgroups;
+ initstate;
+ inotify_add_watch;
+ inotify_init;
+ inotify_init1;
+ inotify_rm_watch;
+ insque;
+ ioctl;
+ isalnum;
+ isalnum_l;
+ isalpha;
+ isalpha_l;
+ isascii;
+ isatty;
+ isblank;
+ isblank_l;
+ iscntrl;
+ iscntrl_l;
+ isdigit;
+ isdigit_l;
+ isfinite;
+ isfinitef;
+ isfinitel;
+ isgraph;
+ isgraph_l;
+ isinf;
+ isinff;
+ isinfl;
+ islower;
+ islower_l;
+ isnan;
+ isnanf;
+ isnanl;
+ isnormal;
+ isnormalf;
+ isnormall;
+ isprint;
+ isprint_l;
+ ispunct;
+ ispunct_l;
+ issetugid; # arm x86 mips
+ isspace;
+ isspace_l;
+ isupper;
+ isupper_l;
+ iswalnum;
+ iswalnum_l;
+ iswalpha;
+ iswalpha_l;
+ iswblank;
+ iswblank_l;
+ iswcntrl;
+ iswcntrl_l;
+ iswctype;
+ iswctype_l;
+ iswdigit;
+ iswdigit_l;
+ iswgraph;
+ iswgraph_l;
+ iswlower;
+ iswlower_l;
+ iswprint;
+ iswprint_l;
+ iswpunct;
+ iswpunct_l;
+ iswspace;
+ iswspace_l;
+ iswupper;
+ iswupper_l;
+ iswxdigit;
+ iswxdigit_l;
+ isxdigit;
+ isxdigit_l;
+ jrand48;
+ kill;
+ killpg;
+ klogctl;
+ labs;
+ lchown;
+ lcong48;
+ ldexp;
+ ldiv;
+ lfind;
+ lgetxattr;
+ link;
+ linkat;
+ listen;
+ listxattr;
+ llabs;
+ lldiv;
+ llistxattr;
+ localeconv;
+ localtime;
+ localtime64; # arm x86 mips
+ localtime64_r; # arm x86 mips
+ localtime_r;
+ login_tty;
+ longjmp;
+ lrand48;
+ lremovexattr;
+ lsearch;
+ lseek;
+ lseek64;
+ lsetxattr;
+ lstat;
+ lstat64;
+ madvise;
+ mallinfo;
+ malloc;
+ malloc_info;
+ malloc_usable_size;
+ mbrlen;
+ mbrtoc16;
+ mbrtoc32;
+ mbrtowc;
+ mbsinit;
+ mbsnrtowcs;
+ mbsrtowcs;
+ mbstowcs;
+ mbtowc;
+ memalign;
+ memccpy;
+ memchr;
+ memcmp;
+ memcpy;
+ memmem;
+ memmove;
+ mempcpy;
+ memrchr;
+ memset;
+ memswap; # arm x86 mips
+ mincore;
+ mkdir;
+ mkdirat;
+ mkdtemp;
+ mkfifo;
+ mkfifoat;
+ mknod;
+ mknodat;
+ mkostemp;
+ mkostemp64;
+ mkostemps;
+ mkostemps64;
+ mkstemp;
+ mkstemp64;
+ mkstemps;
+ mkstemps64;
+ mktemp;
+ mktime;
+ mktime64; # arm x86 mips
+ mktime_tz;
+ mlock;
+ mlockall;
+ mmap;
+ mmap64;
+ mount;
+ mprotect;
+ mrand48;
+ mremap;
+ msync;
+ munlock;
+ munlockall;
+ munmap;
+ nanosleep;
+ newlocale;
+ nftw;
+ nftw64;
+ nice;
+ nrand48;
+ ns_format_ttl; # arm64 x86_64 mips64
+ ns_get16; # arm64 x86_64 mips64
+ ns_get32; # arm64 x86_64 mips64
+ ns_initparse; # arm64 x86_64 mips64
+ ns_makecanon; # arm64 x86_64 mips64
+ ns_msg_getflag; # arm64 x86_64 mips64
+ ns_name_compress; # arm64 x86_64 mips64
+ ns_name_ntol; # arm64 x86_64 mips64
+ ns_name_ntop; # arm64 x86_64 mips64
+ ns_name_pack; # arm64 x86_64 mips64
+ ns_name_pton; # arm64 x86_64 mips64
+ ns_name_rollback; # arm64 x86_64 mips64
+ ns_name_skip; # arm64 x86_64 mips64
+ ns_name_uncompress; # arm64 x86_64 mips64
+ ns_name_unpack; # arm64 x86_64 mips64
+ ns_parserr; # arm64 x86_64 mips64
+ ns_put16; # arm64 x86_64 mips64
+ ns_put32; # arm64 x86_64 mips64
+ ns_samename; # arm64 x86_64 mips64
+ ns_skiprr; # arm64 x86_64 mips64
+ ns_sprintrr; # arm64 x86_64 mips64
+ ns_sprintrrf; # arm64 x86_64 mips64
+ nsdispatch;
+ ntohl;
+ ntohs;
+ open;
+ open64;
+ open_memstream;
+ open_wmemstream;
+ openat;
+ openat64;
+ opendir;
+ openlog;
+ openpty;
+ optarg;
+ opterr;
+ optind;
+ optopt;
+ optreset;
+ pathconf;
+ pause;
+ pclose;
+ perror;
+ personality;
+ pipe;
+ pipe2;
+ poll;
+ popen;
+ posix_fadvise;
+ posix_fadvise64;
+ posix_fallocate;
+ posix_fallocate64;
+ posix_madvise;
+ posix_memalign;
+ posix_openpt;
+ ppoll;
+ prctl;
+ pread;
+ pread64;
+ printf;
+ prlimit; # arm64 x86_64 mips64
+ prlimit64;
+ process_vm_readv;
+ process_vm_writev;
+ pselect;
+ psiginfo;
+ psignal;
+ pthread_atfork;
+ pthread_attr_destroy;
+ pthread_attr_getdetachstate;
+ pthread_attr_getguardsize;
+ pthread_attr_getschedparam;
+ pthread_attr_getschedpolicy;
+ pthread_attr_getscope;
+ pthread_attr_getstack;
+ pthread_attr_getstackaddr; # arm x86 mips
+ pthread_attr_getstacksize;
+ pthread_attr_init;
+ pthread_attr_setdetachstate;
+ pthread_attr_setguardsize;
+ pthread_attr_setschedparam;
+ pthread_attr_setschedpolicy;
+ pthread_attr_setscope;
+ pthread_attr_setstack;
+ pthread_attr_setstackaddr; # arm x86 mips
+ pthread_attr_setstacksize;
+ pthread_cond_broadcast;
+ pthread_cond_destroy;
+ pthread_cond_init;
+ pthread_cond_signal;
+ pthread_cond_timedwait;
+ pthread_cond_timedwait_monotonic; # arm x86 mips
+ pthread_cond_timedwait_monotonic_np; # arm x86 mips
+ pthread_cond_timedwait_relative_np; # arm x86 mips
+ pthread_cond_timeout_np; # arm x86 mips
+ pthread_cond_wait;
+ pthread_condattr_destroy;
+ pthread_condattr_getclock;
+ pthread_condattr_getpshared;
+ pthread_condattr_init;
+ pthread_condattr_setclock;
+ pthread_condattr_setpshared;
+ pthread_create;
+ pthread_detach;
+ pthread_equal;
+ pthread_exit;
+ pthread_getattr_np;
+ pthread_getcpuclockid;
+ pthread_getschedparam;
+ pthread_getspecific;
+ pthread_gettid_np;
+ pthread_join;
+ pthread_key_create;
+ pthread_key_delete;
+ pthread_kill;
+ pthread_mutex_destroy;
+ pthread_mutex_init;
+ pthread_mutex_lock;
+ pthread_mutex_lock_timeout_np; # arm x86 mips
+ pthread_mutex_timedlock;
+ pthread_mutex_trylock;
+ pthread_mutex_unlock;
+ pthread_mutexattr_destroy;
+ pthread_mutexattr_getpshared;
+ pthread_mutexattr_gettype;
+ pthread_mutexattr_init;
+ pthread_mutexattr_setpshared;
+ pthread_mutexattr_settype;
+ pthread_once;
+ pthread_rwlock_destroy;
+ pthread_rwlock_init;
+ pthread_rwlock_rdlock;
+ pthread_rwlock_timedrdlock;
+ pthread_rwlock_timedwrlock;
+ pthread_rwlock_tryrdlock;
+ pthread_rwlock_trywrlock;
+ pthread_rwlock_unlock;
+ pthread_rwlock_wrlock;
+ pthread_rwlockattr_destroy;
+ pthread_rwlockattr_getkind_np;
+ pthread_rwlockattr_getpshared;
+ pthread_rwlockattr_init;
+ pthread_rwlockattr_setkind_np;
+ pthread_rwlockattr_setpshared;
+ pthread_self;
+ pthread_setname_np;
+ pthread_setschedparam;
+ pthread_setspecific;
+ pthread_sigmask;
+ ptrace;
+ ptsname;
+ ptsname_r;
+ putc;
+ putc_unlocked;
+ putchar;
+ putchar_unlocked;
+ putenv;
+ puts;
+ pututline;
+ putw; # arm x86 mips
+ putwc;
+ putwchar;
+ pvalloc; # arm x86 mips
+ pwrite;
+ pwrite64;
+ qsort;
+ quick_exit;
+ raise;
+ rand;
+ rand_r;
+ random;
+ read;
+ readahead;
+ readdir;
+ readdir64;
+ readdir64_r;
+ readdir_r;
+ readlink;
+ readlinkat;
+ readv;
+ realloc;
+ realpath;
+ reboot;
+ recv;
+ recvfrom;
+ recvmmsg;
+ recvmsg;
+ regcomp;
+ regerror;
+ regexec;
+ regfree;
+ remove;
+ removexattr;
+ remque;
+ rename;
+ renameat;
+ res_init;
+ res_mkquery;
+ res_query;
+ res_search;
+ restore_core_regs; # arm
+ rewind;
+ rewinddir;
+ rmdir;
+ sbrk;
+ scandir;
+ scandir64;
+ scanf;
+ sched_get_priority_max;
+ sched_get_priority_min;
+ sched_getaffinity;
+ sched_getcpu;
+ sched_getparam;
+ sched_getscheduler;
+ sched_rr_get_interval;
+ sched_setaffinity;
+ sched_setparam;
+ sched_setscheduler;
+ sched_yield;
+ seed48;
+ seekdir;
+ select;
+ sem_close;
+ sem_destroy;
+ sem_getvalue;
+ sem_init;
+ sem_open;
+ sem_post;
+ sem_timedwait;
+ sem_trywait;
+ sem_unlink;
+ sem_wait;
+ send;
+ sendfile;
+ sendfile64;
+ sendmmsg;
+ sendmsg;
+ sendto;
+ setbuf;
+ setbuffer;
+ setegid;
+ setenv;
+ seteuid;
+ setfsgid;
+ setfsuid;
+ setgid;
+ setgroups;
+ sethostname;
+ setitimer;
+ setjmp;
+ setlinebuf;
+ setlocale;
+ setlogmask;
+ setmntent;
+ setns;
+ setpgid;
+ setpgrp;
+ setpriority;
+ setprogname;
+ setregid;
+ setresgid;
+ setresuid;
+ setreuid;
+ setrlimit;
+ setrlimit64;
+ setservent;
+ setsid;
+ setsockopt;
+ setstate;
+ settimeofday;
+ setuid;
+ setusershell;
+ setutent;
+ setvbuf;
+ setxattr;
+ shutdown;
+ sigaction;
+ sigaddset;
+ sigaltstack;
+ sigblock;
+ sigdelset;
+ sigemptyset;
+ sigfillset;
+ siginterrupt;
+ sigismember;
+ siglongjmp;
+ signal;
+ signalfd;
+ sigpending;
+ sigprocmask;
+ sigqueue;
+ sigsetjmp;
+ sigsetmask;
+ sigsuspend;
+ sigtimedwait;
+ sigwait;
+ sigwaitinfo;
+ sleep;
+ snprintf;
+ socket;
+ socketpair;
+ splice;
+ sprintf;
+ srand;
+ srand48;
+ srandom;
+ sscanf;
+ stat;
+ stat64;
+ statfs;
+ statfs64;
+ statvfs;
+ statvfs64;
+ stderr;
+ stdin;
+ stdout;
+ stpcpy;
+ stpncpy;
+ strcasecmp;
+ strcasecmp_l;
+ strcasestr;
+ strcat;
+ strchr;
+ strcmp;
+ strcoll;
+ strcoll_l;
+ strcpy;
+ strcspn;
+ strdup;
+ strerror;
+ strerror_l;
+ strerror_r;
+ strftime;
+ strftime_l;
+ strlcat;
+ strlcpy;
+ strlen;
+ strncasecmp;
+ strncasecmp_l;
+ strncat;
+ strncmp;
+ strncpy;
+ strndup;
+ strnlen;
+ strntoimax; # arm x86 mips
+ strntoumax; # arm x86 mips
+ strpbrk;
+ strptime;
+ strrchr;
+ strsep;
+ strsignal;
+ strspn;
+ strstr;
+ strtod;
+ strtof;
+ strtoimax;
+ strtok;
+ strtok_r;
+ strtol;
+ strtold;
+ strtold_l;
+ strtoll;
+ strtoll_l;
+ strtoq;
+ strtotimeval; # arm x86 mips
+ strtoul;
+ strtoull;
+ strtoull_l;
+ strtoumax;
+ strtouq;
+ strxfrm;
+ strxfrm_l;
+ swapoff;
+ swapon;
+ swprintf;
+ swscanf;
+ symlink;
+ symlinkat;
+ sync;
+ sys_siglist;
+ sys_signame;
+ syscall;
+ sysconf;
+ sysinfo;
+ syslog;
+ system;
+ sysv_signal; # arm x86 mips
+ tcdrain;
+ tcflow;
+ tcflush;
+ tcgetattr;
+ tcgetpgrp;
+ tcgetsid;
+ tcsendbreak;
+ tcsetattr;
+ tcsetpgrp;
+ tdelete;
+ tdestroy;
+ tee;
+ telldir;
+ tempnam;
+ tfind;
+ tgkill;
+ time;
+ timegm;
+ timegm64; # arm x86 mips
+ timelocal;
+ timelocal64; # arm x86 mips
+ timer_create;
+ timer_delete;
+ timer_getoverrun;
+ timer_gettime;
+ timer_settime;
+ timerfd_create;
+ timerfd_gettime;
+ timerfd_settime;
+ times;
+ timezone;
+ tkill; # arm x86 mips
+ tmpfile;
+ tmpnam;
+ toascii;
+ tolower;
+ tolower_l;
+ toupper;
+ toupper_l;
+ towlower;
+ towlower_l;
+ towupper;
+ towupper_l;
+ truncate;
+ truncate64;
+ tsearch;
+ ttyname;
+ ttyname_r;
+ twalk;
+ tzname;
+ tzset;
+ umask;
+ umount;
+ umount2;
+ uname;
+ ungetc;
+ ungetwc;
+ unlink;
+ unlinkat;
+ unlockpt;
+ unsetenv;
+ unshare;
+ uselocale;
+ usleep;
+ utime;
+ utimensat;
+ utimes;
+ utmpname;
+ valloc; # arm x86 mips
+ vasprintf;
+ vdprintf;
+ verr;
+ verrx;
+ vfdprintf; # arm x86 mips
+ vfork;
+ vfprintf;
+ vfscanf;
+ vfwprintf;
+ vfwscanf;
+ vmsplice;
+ vprintf;
+ vscanf;
+ vsnprintf;
+ vsprintf;
+ vsscanf;
+ vswprintf;
+ vswscanf;
+ vsyslog;
+ vwarn;
+ vwarnx;
+ vwprintf;
+ vwscanf;
+ wait;
+ wait3; # arm x86 mips
+ wait4;
+ waitid;
+ waitpid;
+ warn;
+ warnx;
+ wcpcpy;
+ wcpncpy;
+ wcrtomb;
+ wcscasecmp;
+ wcscasecmp_l;
+ wcscat;
+ wcschr;
+ wcscmp;
+ wcscoll;
+ wcscoll_l;
+ wcscpy;
+ wcscspn;
+ wcsdup;
+ wcsftime;
+ wcslcat;
+ wcslcpy;
+ wcslen;
+ wcsncasecmp;
+ wcsncasecmp_l;
+ wcsncat;
+ wcsncmp;
+ wcsncpy;
+ wcsnlen;
+ wcsnrtombs;
+ wcspbrk;
+ wcsrchr;
+ wcsrtombs;
+ wcsspn;
+ wcsstr;
+ wcstod;
+ wcstof;
+ wcstoimax;
+ wcstok;
+ wcstol;
+ wcstold;
+ wcstold_l;
+ wcstoll;
+ wcstoll_l;
+ wcstombs;
+ wcstoul;
+ wcstoull;
+ wcstoull_l;
+ wcstoumax;
+ wcswcs; # arm x86 mips
+ wcswidth;
+ wcsxfrm;
+ wcsxfrm_l;
+ wctob;
+ wctomb;
+ wctype;
+ wctype_l;
+ wcwidth;
+ wmemchr;
+ wmemcmp;
+ wmemcpy;
+ wmemmove;
+ wmempcpy;
+ wmemset;
+ wprintf;
+ write;
+ writev;
+ wscanf;
+ local:
+ *;
+};
+
+LIBC_PRIVATE {
+ global:
+ ___Unwind_Backtrace; # arm
+ ___Unwind_ForcedUnwind; # arm
+ ___Unwind_RaiseException; # arm
+ ___Unwind_Resume; # arm
+ ___Unwind_Resume_or_Rethrow; # arm
+ __accept4; # arm x86 mips
+ __adddf3; # arm
+ __addsf3; # arm
+ __aeabi_atexit; # arm
+ __aeabi_cdcmpeq; # arm
+ __aeabi_cdcmple; # arm
+ __aeabi_cdrcmple; # arm
+ __aeabi_d2f; # arm
+ __aeabi_d2iz; # arm
+ __aeabi_dadd; # arm
+ __aeabi_dcmpeq; # arm
+ __aeabi_dcmpge; # arm
+ __aeabi_dcmpgt; # arm
+ __aeabi_dcmple; # arm
+ __aeabi_dcmplt; # arm
+ __aeabi_dcmpun; # arm
+ __aeabi_ddiv; # arm
+ __aeabi_dmul; # arm
+ __aeabi_drsub; # arm
+ __aeabi_dsub; # arm
+ __aeabi_f2d; # arm
+ __aeabi_f2iz; # arm
+ __aeabi_f2uiz; # arm
+ __aeabi_fadd; # arm
+ __aeabi_fcmpun; # arm
+ __aeabi_fdiv; # arm
+ __aeabi_fmul; # arm
+ __aeabi_frsub; # arm
+ __aeabi_fsub; # arm
+ __aeabi_i2d; # arm
+ __aeabi_i2f; # arm
+ __aeabi_idiv; # arm
+ __aeabi_idiv0; # arm
+ __aeabi_idivmod; # arm
+ __aeabi_l2d; # arm
+ __aeabi_l2f; # arm
+ __aeabi_lasr; # arm
+ __aeabi_ldiv0; # arm
+ __aeabi_ldivmod; # arm
+ __aeabi_llsl; # arm
+ __aeabi_llsr; # arm
+ __aeabi_lmul; # arm
+ __aeabi_memclr; # arm
+ __aeabi_memclr4; # arm
+ __aeabi_memclr8; # arm
+ __aeabi_memcpy; # arm
+ __aeabi_memcpy4; # arm
+ __aeabi_memcpy8; # arm
+ __aeabi_memmove; # arm
+ __aeabi_memmove4; # arm
+ __aeabi_memmove8; # arm
+ __aeabi_memset; # arm
+ __aeabi_memset4; # arm
+ __aeabi_memset8; # arm
+ __aeabi_ui2d; # arm
+ __aeabi_ui2f; # arm
+ __aeabi_uidiv; # arm
+ __aeabi_uidivmod; # arm
+ __aeabi_ul2d; # arm
+ __aeabi_ul2f; # arm
+ __aeabi_uldivmod; # arm
+ __aeabi_unwind_cpp_pr0; # arm
+ __aeabi_unwind_cpp_pr1; # arm
+ __aeabi_unwind_cpp_pr2; # arm
+ __arm_fadvise64_64; # arm
+ __ashldi3; # arm
+ __ashrdi3; # arm
+ __bionic_brk; # arm x86 mips
+ __bionic_libgcc_compat_symbols; # arm x86
+ __bionic_libgcc_unwind_symbols; # arm
+ __dso_handle; # arm
+ __gnu_Unwind_Backtrace; # arm
+ __gnu_unwind_execute; # arm
+ __gnu_Unwind_Find_exidx; # arm
+ __gnu_Unwind_ForcedUnwind; # arm
+ __gnu_unwind_frame; # arm
+ __gnu_Unwind_RaiseException; # arm
+ __gnu_Unwind_Restore_VFP; # arm
+ __gnu_Unwind_Restore_VFP_D; # arm
+ __gnu_Unwind_Restore_VFP_D_16_to_31; # arm
+ __gnu_Unwind_Restore_WMMXC; # arm
+ __gnu_Unwind_Restore_WMMXD; # arm
+ __gnu_Unwind_Resume; # arm
+ __gnu_Unwind_Resume_or_Rethrow; # arm
+ __gnu_Unwind_Save_VFP; # arm
+ __gnu_Unwind_Save_VFP_D; # arm
+ __gnu_Unwind_Save_VFP_D_16_to_31; # arm
+ __gnu_Unwind_Save_WMMXC; # arm
+ __gnu_Unwind_Save_WMMXD; # arm
+ _Unwind_Backtrace; # arm
+ _Unwind_Complete; # arm
+ _Unwind_DeleteException; # arm
+ _Unwind_ForcedUnwind; # arm
+ _Unwind_GetCFA; # arm
+ _Unwind_GetDataRelBase; # arm
+ _Unwind_GetLanguageSpecificData; # arm
+ _Unwind_GetRegionStart; # arm
+ _Unwind_GetTextRelBase; # arm
+ _Unwind_RaiseException; # arm
+ _Unwind_Resume; # arm
+ _Unwind_Resume_or_Rethrow; # arm
+ _Unwind_VRS_Get; # arm
+ _Unwind_VRS_Pop; # arm
+ _Unwind_VRS_Set; # arm
+ atexit; # arm
+ dlmalloc; # arm x86 mips
+ dlmalloc_inspect_all;
+ dlmalloc_trim;
+ dlmalloc_usable_size; # arm x86 mips
+ gMallocLeakZygoteChild;
+ SHA1Final; # arm x86 mips
+ SHA1Init; # arm x86 mips
+ SHA1Transform; # arm x86 mips
+ SHA1Update; # arm x86 mips
+} LIBC;
diff --git a/libc/private/ScopedFd.h b/libc/private/ScopedFd.h
deleted file mode 100644
index e56c139..0000000
--- a/libc/private/ScopedFd.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SCOPED_FD_H
-#define SCOPED_FD_H
-
-#include <unistd.h>
-#include "bionic_macros.h"
-
-// A smart pointer that closes the given fd on going out of scope.
-// Use this when the fd is incidental to the purpose of your function,
-// but needs to be cleaned up on exit.
-class ScopedFd {
-public:
- explicit ScopedFd(int fd) : fd(fd) {
- }
-
- ~ScopedFd() {
- reset();
- }
-
- int get() const {
- return fd;
- }
-
- int release() __attribute__((warn_unused_result)) {
- int localFd = fd;
- fd = -1;
- return localFd;
- }
-
- void reset(int new_fd = -1) {
- if (fd != -1) {
- TEMP_FAILURE_RETRY(close(fd));
- }
- fd = new_fd;
- }
-
-private:
- int fd;
-
- // Disallow copy and assignment.
- DISALLOW_COPY_AND_ASSIGN(ScopedFd);
-};
-
-#endif // SCOPED_FD_H
diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c
index 13b9887..fc2115e 100644
--- a/libc/stdio/stdio.c
+++ b/libc/stdio/stdio.c
@@ -86,5 +86,5 @@ __sseek(void *cookie, fpos_t offset, int whence)
int
__sclose(void *cookie)
{
- return TEMP_FAILURE_RETRY(close(((FILE *)cookie)->_file));
+ return close(((FILE *)cookie)->_file);
}
diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c
index df2b1b5..a6970dd 100644
--- a/libc/stdlib/atexit.c
+++ b/libc/stdlib/atexit.c
@@ -37,7 +37,18 @@
#include "atexit.h"
#include "private/thread_private.h"
-struct atexit *__atexit;
+struct atexit {
+ struct atexit *next; /* next in list */
+ int ind; /* next index in this table */
+ int max; /* max entries >= ATEXIT_SIZE */
+ struct atexit_fn {
+ void (*fn_ptr)(void *);
+ void *fn_arg; /* argument for CXA callback */
+ void *fn_dso; /* shared module handle */
+ } fns[1]; /* the table itself */
+};
+
+static struct atexit *__atexit;
static int restartloop;
/* BEGIN android-changed: __unregister_atfork is used by __cxa_finalize */
diff --git a/libc/stdlib/atexit.h b/libc/stdlib/atexit.h
index 3de2aa3..e01bb34 100644
--- a/libc/stdlib/atexit.h
+++ b/libc/stdlib/atexit.h
@@ -30,18 +30,5 @@
*
*/
-struct atexit {
- struct atexit *next; /* next in list */
- int ind; /* next index in this table */
- int max; /* max entries >= ATEXIT_SIZE */
- struct atexit_fn {
- void (*fn_ptr)(void *);
- void *fn_arg; /* argument for CXA callback */
- void *fn_dso; /* shared module handle */
- } fns[1]; /* the table itself */
-};
-
-extern struct atexit *__atexit; /* points to head of LIFO stack */
-
int __cxa_atexit(void (*)(void *), void *, void *);
void __cxa_finalize(void *);
diff --git a/libc/tools/check-symbols.py b/libc/tools/check-symbols.py
index 0922548..a217ff7 100755
--- a/libc/tools/check-symbols.py
+++ b/libc/tools/check-symbols.py
@@ -41,10 +41,11 @@ def CheckSymbols(library, functions_or_variables):
for line in subprocess.check_output(['readelf', '--dyn-syms', so_file]).split('\n'):
m = r.match(line)
if m:
+ symbol = string.split(m.group(2), '@')[0]
if m.group(1) == 'FUNC' and functions_or_variables == 'functions':
- actual_symbols.add(m.group(2))
+ actual_symbols.add(symbol)
elif m.group(1) == 'OBJECT' and functions_or_variables == 'variables':
- actual_symbols.add(m.group(2))
+ actual_symbols.add(symbol)
#else:
#print 'ignoring: ' % line
diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h
index 8f55a26..47bacc3 100644
--- a/libc/upstream-openbsd/android/include/openbsd-compat.h
+++ b/libc/upstream-openbsd/android/include/openbsd-compat.h
@@ -74,7 +74,6 @@ __LIBC_HIDDEN__ void* reallocarray(void*, size_t, size_t);
__LIBC64_HIDDEN__ extern const short* _tolower_tab_;
__LIBC64_HIDDEN__ extern const short* _toupper_tab_;
-__LIBC_HIDDEN__ extern struct atexit* __atexit;
__LIBC_HIDDEN__ extern const char _C_ctype_[];
__LIBC_HIDDEN__ extern const short _C_toupper_[];
__LIBC_HIDDEN__ extern const short _C_tolower_[];
diff --git a/libc/version_script.txt b/libc/version_script.txt
index 349a2fc..afc5e5c 100644
--- a/libc/version_script.txt
+++ b/libc/version_script.txt
@@ -1,9 +1,4 @@
LIBC {
- global:
- /* Work-around for http://b/20065774. */
- __clear_cache;
- _Unwind_Backtrace;
- _Unwind_GetIP;
local:
_ZSt7nothrow;
_ZdaPv;
diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata
index 3661b68..f22464e 100644
--- a/libc/zoneinfo/tzdata
+++ b/libc/zoneinfo/tzdata
Binary files differ
diff --git a/libdl/Android.mk b/libdl/Android.mk
index 2a0724a..7b97dc4 100644
--- a/libdl/Android.mk
+++ b/libdl/Android.mk
@@ -15,7 +15,7 @@ include $(CLEAR_VARS)
#
# DO NOT REMOVE --exclude-libs!
-LOCAL_LDFLAGS := -Wl,--exclude-libs=libgcc.a
+LOCAL_LDFLAGS := -Wl,--exclude-libs=libgcc.a -Wl,--version-script=$(LOCAL_PATH)/libdl.map
# for x86, exclude libgcc_eh.a for the same reasons as above
LOCAL_LDFLAGS_x86 := -Wl,--exclude-libs=libgcc_eh.a
diff --git a/libdl/libdl.c b/libdl/libdl.c
index dca51b0..9a858a3 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -17,6 +17,7 @@
#include <dlfcn.h>
#include <link.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <android/dlext.h>
// These are stubs for functions that are actually defined
@@ -38,3 +39,6 @@ void android_get_LD_LIBRARY_PATH(char* buffer __unused, size_t buffer_size __unu
void android_update_LD_LIBRARY_PATH(const char* ld_library_path __unused) { }
void* android_dlopen_ext(const char* filename __unused, int flag __unused, const android_dlextinfo* extinfo __unused) { return 0; }
+
+void android_set_application_target_sdk_version(uint32_t target __unused) { }
+uint32_t android_get_application_target_sdk_version() { return 0; }
diff --git a/libdl/libdl.map b/libdl/libdl.map
new file mode 100644
index 0000000..a911cb6
--- /dev/null
+++ b/libdl/libdl.map
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LIBC {
+ global:
+ android_dlopen_ext;
+ dl_iterate_phdr;
+# begin arm-only
+ dl_unwind_find_exidx;
+# end arm-only
+ dladdr;
+ dlclose;
+ dlerror;
+ dlopen;
+ dlsym;
+ local:
+ *;
+};
+
+LIBC_PRIVATE {
+ global:
+ android_get_application_target_sdk_version;
+ android_set_application_target_sdk_version;
+ android_get_LD_LIBRARY_PATH;
+ android_update_LD_LIBRARY_PATH;
+} LIBC;
diff --git a/libm/Android.mk b/libm/Android.mk
index 6472a15..e919129 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -513,8 +513,13 @@ include $(BUILD_STATIC_LIBRARY)
# -----------------------------------------------------------------------------
include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/libm.map
+
# TODO: This is to work around b/19059885. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
+LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
+
+LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/libm.map
LOCAL_MODULE := libm
LOCAL_CLANG := $(libm_clang)
diff --git a/libm/NOTICE b/libm/NOTICE
index 70f2f46..a2cfad3 100644
--- a/libm/NOTICE
+++ b/libm/NOTICE
@@ -1002,6 +1002,114 @@ SUCH DAMAGE.
-------------------------------------------------------------------
+Copyright (c) 2013-2014, NVIDIA Corporation. All rights reserved.
+Johhnny Qiu <joqiu@nvidia.com>
+Shu Zhang <chazhang@nvidia.com>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013-2014, NVIDIA Corporation. All rights reserved.
+Johnny Qiu <joqiu@nvidia.com>
+Shu Zhang <chazhang@nvidia.com>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2014, Intel Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+
+ * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright 2015, The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
From: @(#)s_ilogb.c 5.1 93/09/24
====================================================
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
diff --git a/libm/libm.map b/libm/libm.map
new file mode 100644
index 0000000..7f02f42
--- /dev/null
+++ b/libm/libm.map
@@ -0,0 +1,378 @@
+LIBC {
+ global:
+ __fe_dfl_env;
+ __signbit;
+ __signbitf;
+ __signbitl;
+ acos;
+ acosf;
+ acosh;
+ acoshf;
+ acoshl;
+ acosl;
+ asin;
+ asinf;
+ asinh;
+ asinhf;
+ asinhl;
+ asinl;
+ atan;
+ atan2;
+ atan2f;
+ atan2l;
+ atanf;
+ atanh;
+ atanhf;
+ atanhl;
+ atanl;
+ cabs;
+ cabsf;
+ cabsl;
+ cacos;
+ cacosf;
+ cacosh;
+ cacoshf;
+ carg;
+ cargf;
+ cargl;
+ casin;
+ casinf;
+ casinh;
+ casinhf;
+ catan;
+ catanf;
+ catanh;
+ catanhf;
+ cbrt;
+ cbrtf;
+ cbrtl;
+ ccos;
+ ccosf;
+ ccosh;
+ ccoshf;
+ ceil;
+ ceilf;
+ ceill;
+ cexp;
+ cexpf;
+ cimag;
+ cimagf;
+ cimagl;
+ conj;
+ conjf;
+ conjl;
+ copysign;
+ copysignf;
+ copysignl;
+ cos;
+ cosf;
+ cosh;
+ coshf;
+ coshl;
+ cosl;
+ cproj;
+ cprojf;
+ cprojl;
+ creal;
+ crealf;
+ creall;
+ csin;
+ csinf;
+ csinh;
+ csinhf;
+ csqrt;
+ csqrtf;
+ csqrtl;
+ ctan;
+ ctanf;
+ ctanh;
+ ctanhf;
+ drem;
+ dremf;
+ erf;
+ erfc;
+ erfcf;
+ erfcl;
+ erff;
+ erfl;
+ exp;
+ exp2;
+ exp2f;
+ exp2l;
+ expf;
+ expl;
+ expm1;
+ expm1f;
+ expm1l;
+ fabs;
+ fabsf;
+ fabsl;
+ fdim;
+ fdimf;
+ fdiml;
+ feclearexcept;
+ fedisableexcept;
+ feenableexcept;
+ fegetenv;
+ fegetexcept;
+ fegetexceptflag;
+ fegetround;
+ feholdexcept;
+ feraiseexcept;
+ fesetenv;
+ fesetexceptflag;
+ fesetround;
+ fetestexcept;
+ feupdateenv;
+ finite;
+ finitef;
+ floor;
+ floorf;
+ floorl;
+ fma;
+ fmaf;
+ fmal;
+ fmax;
+ fmaxf;
+ fmaxl;
+ fmin;
+ fminf;
+ fminl;
+ fmod;
+ fmodf;
+ fmodl;
+ frexp;
+ frexpf;
+ frexpl;
+ gamma;
+ gamma_r;
+ gammaf;
+ gammaf_r;
+ hypot;
+ hypotf;
+ hypotl;
+ ilogb;
+ ilogbf;
+ ilogbl;
+ j0;
+ j0f;
+ j1;
+ j1f;
+ jn;
+ jnf;
+ ldexpf;
+ ldexpl;
+ lgamma;
+ lgamma_r;
+ lgammaf;
+ lgammaf_r;
+ lgammal;
+ lgammal_r;
+ llrint;
+ llrintf;
+ llrintl;
+ llround;
+ llroundf;
+ llroundl;
+ log;
+ log10;
+ log10f;
+ log10l;
+ log1p;
+ log1pf;
+ log1pl;
+ log2;
+ log2f;
+ log2l;
+ logb;
+ logbf;
+ logbl;
+ logf;
+ logl;
+ lrint;
+ lrintf;
+ lrintl;
+ lround;
+ lroundf;
+ lroundl;
+ modf;
+ modff;
+ modfl;
+ nan;
+ nanf;
+ nanl;
+ nearbyint;
+ nearbyintf;
+ nearbyintl;
+ nextafter;
+ nextafterf;
+ nextafterl;
+ nexttoward;
+ nexttowardf;
+ nexttowardl;
+ pow;
+ powf;
+ powl;
+ remainder;
+ remainderf;
+ remainderl;
+ remquo;
+ remquof;
+ remquol;
+ rint;
+ rintf;
+ rintl;
+ round;
+ roundf;
+ roundl;
+ scalb;
+ scalbf;
+ scalbln;
+ scalblnf;
+ scalblnl;
+ scalbn;
+ scalbnf;
+ scalbnl;
+ signgam;
+ significand;
+ significandf;
+ significandl;
+ sin;
+ sincos;
+ sincosf;
+ sincosl;
+ sinf;
+ sinh;
+ sinhf;
+ sinhl;
+ sinl;
+ sqrt;
+ sqrtf;
+ sqrtl;
+ tan;
+ tanf;
+ tanh;
+ tanhf;
+ tanhl;
+ tanl;
+ tgamma;
+ tgammaf;
+ tgammal;
+ trunc;
+ truncf;
+ truncl;
+ y0;
+ y0f;
+ y1;
+ y1f;
+ yn;
+ ynf;
+ local:
+ *;
+};
+
+LIBC_PRIVATE {
+ global:
+ ___Unwind_Backtrace; # arm
+ ___Unwind_ForcedUnwind; # arm
+ ___Unwind_RaiseException; # arm
+ ___Unwind_Resume; # arm
+ ___Unwind_Resume_or_Rethrow; # arm
+ __adddf3; # arm
+ __aeabi_cdcmpeq; # arm
+ __aeabi_cdcmple; # arm
+ __aeabi_cdrcmple; # arm
+ __aeabi_cfcmpeq; # arm
+ __aeabi_cfcmple; # arm
+ __aeabi_cfrcmple; # arm
+ __aeabi_d2lz; # arm
+ __aeabi_d2uiz; # arm
+ __aeabi_d2ulz; # arm
+ __aeabi_dadd; # arm
+ __aeabi_dcmpeq; # arm
+ __aeabi_dcmpge; # arm
+ __aeabi_dcmpgt; # arm
+ __aeabi_dcmple; # arm
+ __aeabi_dcmplt; # arm
+ __aeabi_ddiv; # arm
+ __aeabi_dmul; # arm
+ __aeabi_drsub; # arm
+ __aeabi_dsub; # arm
+ __aeabi_f2d; # arm
+ __aeabi_f2lz; # arm
+ __aeabi_f2ulz; # arm
+ __aeabi_fcmpeq; # arm
+ __aeabi_fcmpge; # arm
+ __aeabi_fcmpgt; # arm
+ __aeabi_fcmple; # arm
+ __aeabi_fcmplt; # arm
+ __aeabi_i2d; # arm
+ __aeabi_l2d; # arm
+ __aeabi_ui2d; # arm
+ __aeabi_ul2d; # arm
+ __aeabi_unwind_cpp_pr0; # arm
+ __aeabi_unwind_cpp_pr1; # arm
+ __aeabi_unwind_cpp_pr2; # arm
+ __cmpdf2; # arm
+ __cmpsf2; # arm
+ __divdf3; # arm
+ __eqdf2; # arm
+ __eqsf2; # arm
+ __extendsfdf2; # arm
+ __fixdfdi; # arm mips
+ __fixsfdi; # arm mips
+ __fixunsdfdi; # arm mips
+ __fixunsdfsi; # arm
+ __fixunssfdi; # arm mips
+ __floatdidf; # arm
+ __floatsidf; # arm
+ __floatundidf; # arm
+ __floatunsidf; # arm
+ __gedf2; # arm
+ __gesf2; # arm
+ __gnu_Unwind_Backtrace; # arm
+ __gnu_unwind_execute; # arm
+ __gnu_Unwind_ForcedUnwind; # arm
+ __gnu_unwind_frame; # arm
+ __gnu_Unwind_RaiseException; # arm
+ __gnu_Unwind_Restore_VFP; # arm
+ __gnu_Unwind_Restore_VFP_D; # arm
+ __gnu_Unwind_Restore_VFP_D_16_to_31; # arm
+ __gnu_Unwind_Restore_WMMXC; # arm
+ __gnu_Unwind_Restore_WMMXD; # arm
+ __gnu_Unwind_Resume; # arm
+ __gnu_Unwind_Resume_or_Rethrow; # arm
+ __gnu_Unwind_Save_VFP; # arm
+ __gnu_Unwind_Save_VFP_D; # arm
+ __gnu_Unwind_Save_VFP_D_16_to_31; # arm
+ __gnu_Unwind_Save_WMMXC; # arm
+ __gnu_Unwind_Save_WMMXD; # arm
+ __gtdf2; # arm
+ __gtsf2; # arm
+ __ledf2; # arm
+ __lesf2; # arm
+ __ltdf2; # arm
+ __ltsf2; # arm
+ __muldc3; # arm x86 mips
+ __muldf3; # arm
+ __nedf2; # arm
+ __nesf2; # arm
+ __restore_core_regs; # arm
+ __subdf3; # arm
+ _Unwind_Backtrace; # arm
+ _Unwind_Complete; # arm
+ _Unwind_DeleteException; # arm
+ _Unwind_ForcedUnwind; # arm
+ _Unwind_GetCFA; # arm
+ _Unwind_GetDataRelBase; # arm
+ _Unwind_GetLanguageSpecificData; # arm
+ _Unwind_GetRegionStart; # arm
+ _Unwind_GetTextRelBase; # arm
+ _Unwind_RaiseException; # arm
+ _Unwind_Resume; # arm
+ _Unwind_Resume_or_Rethrow; # arm
+ _Unwind_VRS_Get; # arm
+ _Unwind_VRS_Pop; # arm
+ _Unwind_VRS_Set; # arm
+ restore_core_regs; # arm
+} LIBC;
diff --git a/linker/Android.mk b/linker/Android.mk
index 5bdc2f9..7a9b5d9 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -7,8 +7,8 @@ LOCAL_SRC_FILES:= \
dlfcn.cpp \
linker.cpp \
linker_allocator.cpp \
+ linker_sdk_versions.cpp \
linker_block_allocator.cpp \
- linker_environ.cpp \
linker_libc_support.c \
linker_memory.cpp \
linker_phdr.cpp \
@@ -35,6 +35,9 @@ LOCAL_CFLAGS += \
-fvisibility=hidden \
-Wall -Wextra -Wunused -Werror \
+LOCAL_CFLAGS_arm += -D__work_around_b_19059885__
+LOCAL_CFLAGS_x86 += -D__work_around_b_19059885__
+
LOCAL_CONLYFLAGS += \
-std=gnu99 \
diff --git a/linker/NOTICE b/linker/NOTICE
index cb3a1dd..139b26e 100644
--- a/linker/NOTICE
+++ b/linker/NOTICE
@@ -42,7 +42,7 @@ SUCH DAMAGE.
-------------------------------------------------------------------
-Copyright (C) 2008, 2009 The Android Open Source Project
+Copyright (C) 2010 The Android Open Source Project
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -70,7 +70,7 @@ SUCH DAMAGE.
-------------------------------------------------------------------
-Copyright (C) 2008-2010 The Android Open Source Project
+Copyright (C) 2012 The Android Open Source Project
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -98,35 +98,23 @@ SUCH DAMAGE.
-------------------------------------------------------------------
-Copyright (C) 2010 The Android Open Source Project
-All rights reserved.
+Copyright (C) 2013 The Android Open Source Project
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
-------------------------------------------------------------------
-Copyright (C) 2012 The Android Open Source Project
+Copyright (C) 2013 The Android Open Source Project
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -154,7 +142,7 @@ SUCH DAMAGE.
-------------------------------------------------------------------
-Copyright (C) 2013 The Android Open Source Project
+Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -170,7 +158,23 @@ limitations under the License.
-------------------------------------------------------------------
-Copyright (C) 2013 The Android Open Source Project
+Copyright (C) 2015 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2015 The Android Open Source Project
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -198,19 +202,3 @@ SUCH DAMAGE.
-------------------------------------------------------------------
-Copyright (C) 2014 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
--------------------------------------------------------------------
-
diff --git a/linker/debugger.cpp b/linker/debugger.cpp
index 357fbdc..46c97af 100644
--- a/linker/debugger.cpp
+++ b/linker/debugger.cpp
@@ -205,15 +205,6 @@ static bool have_siginfo(int signum) {
}
static void send_debuggerd_packet(siginfo_t* info) {
- if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) {
- // process has disabled core dumps and PTRACE_ATTACH, and does not want to be dumped.
- // Honor that intention by not connecting to debuggerd and asking it
- // to dump our internal state.
- __libc_format_log(ANDROID_LOG_INFO, "libc",
- "Suppressing debuggerd output because prctl(PR_GET_DUMPABLE)==0");
- return;
- }
-
// Mutex to prevent multiple crashing threads from trying to talk
// to debuggerd at the same time.
static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 057c217..ef454ab 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <android/dlext.h>
+#include <android/api-level.h>
#include <bionic/pthread_internal.h>
#include "private/bionic_tls.h"
@@ -157,6 +158,21 @@ int dlclose(void* handle) {
return 0;
}
+int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
+ ScopedPthreadMutexLocker locker(&g_dl_mutex);
+ return do_dl_iterate_phdr(cb, data);
+}
+
+void android_set_application_target_sdk_version(uint32_t target) {
+ // lock to avoid modification in the middle of dlopen.
+ ScopedPthreadMutexLocker locker(&g_dl_mutex);
+ set_application_target_sdk_version(target);
+}
+
+uint32_t android_get_application_target_sdk_version() {
+ return get_application_target_sdk_version();
+}
+
// name_offset: starting index of the name in libdl_info.strtab
#define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
{ name_offset, \
@@ -176,19 +192,21 @@ int dlclose(void* handle) {
/* st_size */ 0, \
}
+static const char ANDROID_LIBDL_STRTAB[] =
+ // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888888888899999 99999
+ // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012345678901234 56789
+ "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0android_get_LD_LIBRARY_PATH\0dl_it"
+ // 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
+ // 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
+ "erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
+ // 0000000000111111
+ // 0123456789012345
+ "get_sdk_version\0"
#if defined(__arm__)
- // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888888888899999 9999900000000001 1111111112222222222 333333333344444444445
- // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012345678901234 5678901234567890 1234567890123456789 012345678901234567890
-# define ANDROID_LIBDL_STRTAB \
- "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0android_get_LD_LIBRARY_PATH\0dl_iterate_phdr\0android_dlopen_ext\0dl_unwind_find_exidx\0"
-#elif defined(__aarch64__) || defined(__i386__) || defined(__mips__) || defined(__x86_64__)
- // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888888888899999 9999900000000001 1111111112222222222
- // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012345678901234 5678901234567890 1234567890123456789
-# define ANDROID_LIBDL_STRTAB \
- "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0android_get_LD_LIBRARY_PATH\0dl_iterate_phdr\0android_dlopen_ext\0"
-#else
-# error Unsupported architecture. Only arm, arm64, mips, mips64, x86 and x86_64 are presently supported.
+ // 216
+ "dl_unwind_find_exidx\0"
#endif
+ ;
static ElfW(Sym) g_libdl_symtab[] = {
// Total length of libdl_info.strtab, including trailing 0.
@@ -205,8 +223,10 @@ static ElfW(Sym) g_libdl_symtab[] = {
ELFW(SYM_INITIALIZER)( 67, &android_get_LD_LIBRARY_PATH, 1),
ELFW(SYM_INITIALIZER)( 95, &dl_iterate_phdr, 1),
ELFW(SYM_INITIALIZER)(111, &android_dlopen_ext, 1),
+ ELFW(SYM_INITIALIZER)(130, &android_set_application_target_sdk_version, 1),
+ ELFW(SYM_INITIALIZER)(173, &android_get_application_target_sdk_version, 1),
#if defined(__arm__)
- ELFW(SYM_INITIALIZER)(130, &dl_unwind_find_exidx, 1),
+ ELFW(SYM_INITIALIZER)(216, &dl_unwind_find_exidx, 1),
#endif
};
@@ -223,9 +243,9 @@ static ElfW(Sym) g_libdl_symtab[] = {
// Note that adding any new symbols here requires stubbing them out in libdl.
static unsigned g_libdl_buckets[1] = { 1 };
#if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0 };
#else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 };
#endif
static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
@@ -246,6 +266,7 @@ soinfo* get_libdl_info() {
__libdl_info->strtab_size_ = sizeof(ANDROID_LIBDL_STRTAB);
__libdl_info->local_group_root_ = __libdl_info;
__libdl_info->soname_ = "libdl.so";
+ __libdl_info->target_sdk_version_ = __ANDROID_API__;
#if defined(__arm__)
strlcpy(__libdl_info->old_name_, __libdl_info->soname_, sizeof(__libdl_info->old_name_));
#endif
diff --git a/linker/linker.cpp b/linker/linker.cpp
index be7b10c..b860f70 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -26,6 +26,7 @@
* SUCH DAMAGE.
*/
+#include <android/api-level.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
@@ -36,7 +37,6 @@
#include <string.h>
#include <sys/mman.h>
#include <sys/param.h>
-#include <sys/personality.h>
#include <unistd.h>
#include <new>
@@ -47,36 +47,21 @@
#include "private/bionic_tls.h"
#include "private/KernelArgumentBlock.h"
#include "private/ScopedPthreadMutexLocker.h"
-#include "private/ScopedFd.h"
#include "private/ScopeGuard.h"
#include "private/UniquePtr.h"
#include "linker.h"
#include "linker_block_allocator.h"
#include "linker_debug.h"
-#include "linker_environ.h"
#include "linker_sleb128.h"
#include "linker_phdr.h"
#include "linker_relocs.h"
#include "linker_reloc_iterators.h"
#include "ziparchive/zip_archive.h"
-/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
- *
- * Do NOT use malloc() and friends or pthread_*() code here.
- * Don't use printf() either; it's caused mysterious memory
- * corruption in the past.
- * The linker runs before we bring up libc and it's easiest
- * to make sure it does not depend on any complex libc features
- *
- * open issues / todo:
- *
- * - cleaner error reporting
- * - after linking, set as much stuff as possible to READONLY
- * and NOEXEC
- */
+extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
-// Override macros to use C++ style casts
+// Override macros to use C++ style casts.
#undef ELF_ST_TYPE
#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
@@ -267,7 +252,7 @@ static void soinfo_free(soinfo* si) {
soinfo *prev = nullptr, *trav;
- TRACE("name %s: freeing soinfo @ %p", si->get_soname(), si);
+ TRACE("name %s: freeing soinfo @ %p", si->get_realpath(), si);
for (trav = solist; trav != nullptr; trav = trav->next) {
if (trav == si) {
@@ -278,7 +263,7 @@ static void soinfo_free(soinfo* si) {
if (trav == nullptr) {
// si was not in solist
- DL_ERR("name \"%s\"@%p is not in solist!", si->get_soname(), si);
+ DL_ERR("name \"%s\"@%p is not in solist!", si->get_realpath(), si);
return;
}
@@ -292,6 +277,7 @@ static void soinfo_free(soinfo* si) {
sonext = prev;
}
+ si->~soinfo();
g_soinfo_allocator.free(si);
}
@@ -332,6 +318,7 @@ static bool realpath_fd(int fd, std::string* realpath) {
std::vector<char> buf(PATH_MAX), proc_self_fd(PATH_MAX);
snprintf(&proc_self_fd[0], proc_self_fd.size(), "/proc/self/fd/%d", fd);
if (readlink(&proc_self_fd[0], &buf[0], buf.size()) == -1) {
+ PRINT("readlink('%s') failed: %s [fd=%d]", &proc_self_fd[0], strerror(errno), fd);
return false;
}
@@ -366,7 +353,7 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
// Here, we only have to provide a callback to iterate across all the
// loaded libraries. gcc_eh does the rest.
-int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
+int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
int rv = 0;
for (soinfo* si = solist; si != nullptr; si = si->next) {
dl_phdr_info dl_info;
@@ -443,7 +430,7 @@ static bool for_each_verdef(const soinfo* si, F functor) {
if (verdef->vd_version != 1) {
DL_ERR("unsupported verdef[%zd] vd_version: %d (expected 1) library: %s",
- i, verdef->vd_version, si->get_soname());
+ i, verdef->vd_version, si->get_realpath());
return false;
}
@@ -513,7 +500,7 @@ static bool is_symbol_global_and_defined(const soinfo* si, const ElfW(Sym)* s) {
return s->st_shndx != SHN_UNDEF;
} else if (ELF_ST_BIND(s->st_info) != STB_LOCAL) {
DL_WARN("unexpected ST_BIND value: %d for '%s' in '%s'",
- ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_soname());
+ ELF_ST_BIND(s->st_info), si->get_string(s->st_name), si->get_realpath());
}
return false;
@@ -546,12 +533,12 @@ bool soinfo::gnu_lookup(SymbolName& symbol_name,
*symbol_index = 0;
TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p (gnu)",
- symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
+ symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
// test against bloom filter
if ((1 & (bloom_word >> (hash % bloom_mask_bits)) & (bloom_word >> (h2 % bloom_mask_bits))) == 0) {
TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
- symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
+ symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
return true;
}
@@ -561,7 +548,7 @@ bool soinfo::gnu_lookup(SymbolName& symbol_name,
if (n == 0) {
TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
- symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
+ symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
return true;
}
@@ -589,7 +576,7 @@ bool soinfo::gnu_lookup(SymbolName& symbol_name,
strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
is_symbol_global_and_defined(this, s)) {
TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
- symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(s->st_value),
+ symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(s->st_value),
static_cast<size_t>(s->st_size));
*symbol_index = n;
return true;
@@ -597,7 +584,7 @@ bool soinfo::gnu_lookup(SymbolName& symbol_name,
} while ((gnu_chain_[n++] & 1) == 0);
TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p",
- symbol_name.get_name(), get_soname(), reinterpret_cast<void*>(base));
+ symbol_name.get_name(), get_realpath(), reinterpret_cast<void*>(base));
return true;
}
@@ -608,7 +595,7 @@ bool soinfo::elf_lookup(SymbolName& symbol_name,
uint32_t hash = symbol_name.elf_hash();
TRACE_TYPE(LOOKUP, "SEARCH %s in %s@%p h=%x(elf) %zd",
- symbol_name.get_name(), get_soname(),
+ symbol_name.get_name(), get_realpath(),
reinterpret_cast<void*>(base), hash, hash % nbucket_);
ElfW(Versym) verneed = 0;
@@ -629,7 +616,7 @@ bool soinfo::elf_lookup(SymbolName& symbol_name,
strcmp(get_string(s->st_name), symbol_name.get_name()) == 0 &&
is_symbol_global_and_defined(this, s)) {
TRACE_TYPE(LOOKUP, "FOUND %s in %s (%p) %zd",
- symbol_name.get_name(), get_soname(),
+ symbol_name.get_name(), get_realpath(),
reinterpret_cast<void*>(s->st_value),
static_cast<size_t>(s->st_size));
*symbol_index = n;
@@ -638,7 +625,7 @@ bool soinfo::elf_lookup(SymbolName& symbol_name,
}
TRACE_TYPE(LOOKUP, "NOT FOUND %s in %s@%p %x %zd",
- symbol_name.get_name(), get_soname(),
+ symbol_name.get_name(), get_realpath(),
reinterpret_cast<void*>(base), hash, hash % nbucket_);
*symbol_index = 0;
@@ -718,7 +705,7 @@ bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
* relocations for -Bsymbolic linked dynamic executables.
*/
if (si_from->has_DT_SYMBOLIC) {
- DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_soname(), name);
+ DEBUG("%s: looking up %s in local scope (DT_SYMBOLIC)", si_from->get_realpath(), name);
if (!si_from->find_symbol_by_name(symbol_name, vi, &s)) {
return false;
}
@@ -733,7 +720,7 @@ bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
bool error = false;
global_group.visit([&](soinfo* global_si) {
DEBUG("%s: looking up %s in %s (from global group)",
- si_from->get_soname(), name, global_si->get_soname());
+ si_from->get_realpath(), name, global_si->get_realpath());
if (!global_si->find_symbol_by_name(symbol_name, vi, &s)) {
error = true;
return false;
@@ -762,7 +749,7 @@ bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
}
DEBUG("%s: looking up %s in %s (from local group)",
- si_from->get_soname(), name, local_si->get_soname());
+ si_from->get_realpath(), name, local_si->get_realpath());
if (!local_si->find_symbol_by_name(symbol_name, vi, &s)) {
error = true;
return false;
@@ -784,8 +771,8 @@ bool soinfo_do_lookup(soinfo* si_from, const char* name, const version_info* vi,
if (s != nullptr) {
TRACE_TYPE(LOOKUP, "si %s sym %s s->st_value = %p, "
"found in %s, base = %p, load bias = %p",
- si_from->get_soname(), name, reinterpret_cast<void*>(s->st_value),
- (*si_found_in)->get_soname(), reinterpret_cast<void*>((*si_found_in)->base),
+ si_from->get_realpath(), name, reinterpret_cast<void*>(s->st_value),
+ (*si_found_in)->get_realpath(), reinterpret_cast<void*>((*si_found_in)->base),
reinterpret_cast<void*>((*si_found_in)->load_bias));
}
@@ -933,13 +920,17 @@ static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_s
}
-// This is used by dlsym(3). It performs symbol lookup only within the
-// specified soinfo object and its dependencies in breadth first order.
-const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
+static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
+ soinfo** found, SymbolName& symbol_name) {
const ElfW(Sym)* result = nullptr;
- SymbolName symbol_name(name);
+ bool skip_lookup = skip_until != nullptr;
+
+ walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
+ if (skip_lookup) {
+ skip_lookup = current_soinfo != skip_until;
+ return true;
+ }
- walk_dependencies_tree(&si, 1, [&](soinfo* current_soinfo) {
if (!current_soinfo->find_symbol_by_name(symbol_name, nullptr, &result)) {
result = nullptr;
return false;
@@ -956,6 +947,24 @@ const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* nam
return result;
}
+// This is used by dlsym(3). It performs symbol lookup only within the
+// specified soinfo object and its dependencies in breadth first order.
+const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found, const char* name) {
+ // According to man dlopen(3) and posix docs in the case when si is handle
+ // of the main executable we need to search not only in the executable and its
+ // dependencies but also in all libraries loaded with RTLD_GLOBAL.
+ //
+ // Since RTLD_GLOBAL is always set for the main executable and all dt_needed shared
+ // libraries and they are loaded in breath-first (correct) order we can just execute
+ // dlsym(RTLD_DEFAULT, ...); instead of doing two stage lookup.
+ if (si == somain) {
+ return dlsym_linear_lookup(name, found, nullptr, RTLD_DEFAULT);
+ }
+
+ SymbolName symbol_name(name);
+ return dlsym_handle_lookup(si, nullptr, found, symbol_name);
+}
+
/* This is used by dlsym(3) to performs a global symbol lookup. If the
start value is null (for RTLD_DEFAULT), the search starts at the
beginning of the global solist. Otherwise the search starts at the
@@ -970,7 +979,7 @@ const ElfW(Sym)* dlsym_linear_lookup(const char* name,
soinfo* start = solist;
if (handle == RTLD_NEXT) {
- if (caller == nullptr || caller->next == nullptr) {
+ if (caller == nullptr) {
return nullptr;
} else {
start = caller->next;
@@ -979,7 +988,10 @@ const ElfW(Sym)* dlsym_linear_lookup(const char* name,
const ElfW(Sym)* s = nullptr;
for (soinfo* si = start; si != nullptr; si = si->next) {
- if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0) {
+ // Do not skip RTLD_LOCAL libraries in dlsym(RTLD_DEFAULT, ...)
+ // if the library is opened by application with target api level <= 22
+ // See http://b/21565766
+ if ((si->get_rtld_flags() & RTLD_GLOBAL) == 0 && si->get_target_sdk_version() > 22) {
continue;
}
@@ -993,31 +1005,13 @@ const ElfW(Sym)* dlsym_linear_lookup(const char* name,
}
}
- // If not found - look into local_group unless
- // caller is part of the global group in which
+ // If not found - use dlsym_handle_lookup for caller's
+ // local_group unless it is part of the global group in which
// case we already did it.
if (s == nullptr && caller != nullptr &&
(caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
- soinfo* local_group_root = caller->get_local_group_root();
-
- if (handle == RTLD_DEFAULT) {
- start = local_group_root;
- }
-
- for (soinfo* si = start; si != nullptr; si = si->next) {
- if (si->get_local_group_root() != local_group_root) {
- break;
- }
-
- if (!si->find_symbol_by_name(symbol_name, nullptr, &s)) {
- return nullptr;
- }
-
- if (s != nullptr) {
- *found = si;
- break;
- }
- }
+ return dlsym_handle_lookup(caller->get_local_group_root(),
+ (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name);
}
if (s != nullptr) {
@@ -1088,11 +1082,11 @@ static int open_library_in_zipfile(const char* const path,
off64_t* file_offset) {
TRACE("Trying zip file open from path '%s'", path);
- // Treat an '!' character inside a path as the separator between the name
+ // Treat an '!/' separator inside a path as the separator between the name
// of the zip file on disk and the subdirectory to search within it.
- // For example, if path is "foo.zip!bar/bas/x.so", then we search for
+ // For example, if path is "foo.zip!/bar/bas/x.so", then we search for
// "bar/bas/x.so" within "foo.zip".
- const char* separator = strchr(path, '!');
+ const char* separator = strstr(path, "!/");
if (separator == nullptr) {
return -1;
}
@@ -1106,7 +1100,7 @@ static int open_library_in_zipfile(const char* const path,
buf[separator - path] = '\0';
const char* zip_path = buf;
- const char* file_path = &buf[separator - path + 1];
+ const char* file_path = &buf[separator - path + 2];
int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
if (fd == -1) {
return -1;
@@ -1223,38 +1217,34 @@ static int open_library(const char* name, off64_t* file_offset) {
return fd;
}
+static const char* fix_dt_needed(const char* dt_needed, const char* sopath __unused) {
+#if !defined(__LP64__)
+ // Work around incorrect DT_NEEDED entries for old apps: http://b/21364029
+ if (get_application_target_sdk_version() <= 22) {
+ const char* bname = basename(dt_needed);
+ if (bname != dt_needed) {
+ DL_WARN("'%s' library has invalid DT_NEEDED entry '%s'", sopath, dt_needed);
+ }
+
+ return bname;
+ }
+#endif
+ return dt_needed;
+}
+
template<typename F>
static void for_each_dt_needed(const soinfo* si, F action) {
for (ElfW(Dyn)* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
if (d->d_tag == DT_NEEDED) {
- action(si->get_string(d->d_un.d_val));
+ action(fix_dt_needed(si->get_string(d->d_un.d_val), si->get_realpath()));
}
}
}
-static soinfo* load_library(LoadTaskList& load_tasks,
+static soinfo* load_library(int fd, off64_t file_offset,
+ LoadTaskList& load_tasks,
const char* name, int rtld_flags,
const android_dlextinfo* extinfo) {
- int fd = -1;
- off64_t file_offset = 0;
- ScopedFd file_guard(-1);
-
- if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
- fd = extinfo->library_fd;
- if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
- file_offset = extinfo->library_fd_offset;
- }
- } else {
- // Open the file.
- fd = open_library(name, &file_offset);
- if (fd == -1) {
- DL_ERR("library \"%s\" not found", name);
- return nullptr;
- }
-
- file_guard.reset(fd);
- }
-
if ((file_offset % PAGE_SIZE) != 0) {
DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
return nullptr;
@@ -1298,12 +1288,12 @@ static soinfo* load_library(LoadTaskList& load_tasks,
std::string realpath = name;
if (!realpath_fd(fd, &realpath)) {
- PRINT("cannot resolve realpath for the library \"%s\": %s", name, strerror(errno));
+ PRINT("warning: unable to get realpath for the library \"%s\". Will use given name.", name);
realpath = name;
}
// Read the ELF header and load the segments.
- ElfReader elf_reader(realpath.c_str(), fd, file_offset);
+ ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size);
if (!elf_reader.Load(extinfo)) {
return nullptr;
}
@@ -1330,30 +1320,86 @@ static soinfo* load_library(LoadTaskList& load_tasks,
return si;
}
-static soinfo *find_loaded_library_by_soname(const char* name) {
+static soinfo* load_library(LoadTaskList& load_tasks,
+ const char* name, int rtld_flags,
+ const android_dlextinfo* extinfo) {
+ if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
+ off64_t file_offset = 0;
+ if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
+ file_offset = extinfo->library_fd_offset;
+ }
+ return load_library(extinfo->library_fd, file_offset, load_tasks, name, rtld_flags, extinfo);
+ }
+
+ // Open the file.
+ off64_t file_offset;
+ int fd = open_library(name, &file_offset);
+ if (fd == -1) {
+ DL_ERR("library \"%s\" not found", name);
+ return nullptr;
+ }
+ soinfo* result = load_library(fd, file_offset, load_tasks, name, rtld_flags, extinfo);
+ close(fd);
+ return result;
+}
+
+// Returns true if library was found and false in 2 cases
+// 1. The library was found but loaded under different target_sdk_version
+// (*candidate != nullptr)
+// 2. The library was not found by soname (*candidate is nullptr)
+static bool find_loaded_library_by_soname(const char* name, soinfo** candidate) {
+ *candidate = nullptr;
+
// Ignore filename with path.
if (strchr(name, '/') != nullptr) {
- return nullptr;
+ return false;
}
+ uint32_t target_sdk_version = get_application_target_sdk_version();
+
for (soinfo* si = solist; si != nullptr; si = si->next) {
const char* soname = si->get_soname();
if (soname != nullptr && (strcmp(name, soname) == 0)) {
- return si;
+ // If the library was opened under different target sdk version
+ // skip this step and try to reopen it. The exceptions are
+ // "libdl.so" and global group. There is no point in skipping
+ // them because relocation process is going to use them
+ // in any case.
+ bool is_libdl = si == solist;
+ if (is_libdl || (si->get_dt_flags_1() & DF_1_GLOBAL) != 0 ||
+ !si->is_linked() || si->get_target_sdk_version() == target_sdk_version) {
+ *candidate = si;
+ return true;
+ } else if (*candidate == nullptr) {
+ // for the different sdk version - remember the first library.
+ *candidate = si;
+ }
}
}
- return nullptr;
+
+ return false;
}
static soinfo* find_library_internal(LoadTaskList& load_tasks, const char* name,
int rtld_flags, const android_dlextinfo* extinfo) {
- soinfo* si = find_loaded_library_by_soname(name);
+ soinfo* candidate;
+
+ if (find_loaded_library_by_soname(name, &candidate)) {
+ return candidate;
+ }
// Library might still be loaded, the accurate detection
// of this fact is done by load_library.
- if (si == nullptr) {
- TRACE("[ '%s' has not been found by soname. Trying harder...]", name);
- si = load_library(load_tasks, name, rtld_flags, extinfo);
+ TRACE("[ '%s' find_loaded_library_by_soname returned false (*candidate=%s@%p). Trying harder...]",
+ name, candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
+
+ soinfo* si = load_library(load_tasks, name, rtld_flags, extinfo);
+
+ // In case we were unable to load the library but there
+ // is a candidate loaded under the same soname but different
+ // sdk level - return it anyways.
+ if (si == nullptr && candidate != nullptr) {
+ si = candidate;
}
return si;
@@ -1513,7 +1559,7 @@ static void soinfo_unload(soinfo* root) {
}
if (!root->can_unload()) {
- TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->get_soname());
+ TRACE("not unloading '%s' - the binary is flagged with NODELETE", root->get_realpath());
return;
}
@@ -1536,7 +1582,9 @@ static void soinfo_unload(soinfo* root) {
if (si->has_min_version(0)) {
soinfo* child = nullptr;
while ((child = si->get_children().pop_front()) != nullptr) {
- TRACE("%s@%p needs to unload %s@%p", si->get_soname(), si, child->get_soname(), child);
+ TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
+ child->get_realpath(), child);
+
if (local_unload_list.contains(child)) {
continue;
} else if (child->is_linked() && child->get_local_group_root() != root) {
@@ -1546,20 +1594,20 @@ static void soinfo_unload(soinfo* root) {
}
}
} else {
-#if !defined(__arm__)
- __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_soname(), si);
+#if !defined(__work_around_b_19059885__)
+ __libc_fatal("soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
#else
- PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_soname(), si);
+ PRINT("warning: soinfo for \"%s\"@%p has no version", si->get_realpath(), si);
for_each_dt_needed(si, [&] (const char* library_name) {
TRACE("deprecated (old format of soinfo): %s needs to unload %s",
- si->get_soname(), library_name);
+ si->get_realpath(), library_name);
soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
if (needed != nullptr) {
// Not found: for example if symlink was deleted between dlopen and dlclose
// Since we cannot really handle errors at this point - print and continue.
PRINT("warning: couldn't find %s needed by %s on unload.",
- library_name, si->get_soname());
+ library_name, si->get_realpath());
return;
} else if (local_unload_list.contains(needed)) {
// already visited
@@ -1589,7 +1637,8 @@ static void soinfo_unload(soinfo* root) {
soinfo_unload(si);
}
} else {
- TRACE("not unloading '%s' group, decrementing ref_count to %zd", root->get_soname(), ref_count);
+ TRACE("not unloading '%s' group, decrementing ref_count to %zd",
+ root->get_realpath(), ref_count);
}
}
@@ -1701,12 +1750,12 @@ bool VersionTracker::init_verneed(const soinfo* si_from) {
const char* target_soname = si_from->get_string(verneed->vn_file);
// find it in dependencies
soinfo* target_si = si_from->get_children().find_if([&](const soinfo* si) {
- return strcmp(si->get_soname(), target_soname) == 0;
+ return si->get_soname() != nullptr && strcmp(si->get_soname(), target_soname) == 0;
});
if (target_si == nullptr) {
DL_ERR("cannot find \"%s\" from verneed[%zd] in DT_NEEDED list for \"%s\"",
- target_soname, i, si_from->get_soname());
+ target_soname, i, si_from->get_realpath());
return false;
}
@@ -1743,6 +1792,27 @@ bool VersionTracker::init(const soinfo* si_from) {
return init_verneed(si_from) && init_verdef(si_from);
}
+bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
+ const char* sym_name, const version_info** vi) {
+ const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
+ ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
+
+ if (sym_ver != VER_NDX_LOCAL && sym_ver != VER_NDX_GLOBAL) {
+ *vi = version_tracker.get_version_info(sym_ver);
+
+ if (*vi == nullptr) {
+ DL_ERR("cannot find verneed/verdef for version index=%d "
+ "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_realpath());
+ return false;
+ }
+ } else {
+ // there is no version info
+ *vi = nullptr;
+ }
+
+ return true;
+}
+
#if !defined(__mips__)
#if defined(USE_RELA)
static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
@@ -1759,14 +1829,8 @@ static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
#endif
template<typename ElfRelIteratorT>
-bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group,
- const soinfo_list_t& local_group) {
- VersionTracker version_tracker;
-
- if (!version_tracker.init(this)) {
- return false;
- }
-
+bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
+ const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
const auto rel = rel_iterator.next();
if (rel == nullptr) {
@@ -1781,7 +1845,7 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& globa
const char* sym_name = nullptr;
ElfW(Addr) addend = get_addend(rel, reloc);
- DEBUG("Processing '%s' relocation at index %zd", get_soname(), idx);
+ DEBUG("Processing '%s' relocation at index %zd", get_realpath(), idx);
if (type == R_GENERIC_NONE) {
continue;
}
@@ -1791,32 +1855,21 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& globa
if (sym != 0) {
sym_name = get_string(symtab_[sym].st_name);
- const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
- ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
-
- if (sym_ver == VER_NDX_LOCAL || sym_ver == VER_NDX_GLOBAL) {
- // there is no version info for this one
- if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) {
- return false;
- }
- } else {
- const version_info* vi = version_tracker.get_version_info(sym_ver);
+ const version_info* vi = nullptr;
- if (vi == nullptr) {
- DL_ERR("cannot find verneed/verdef for version index=%d "
- "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_soname());
- return false;
- }
+ if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
+ return false;
+ }
- if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
- return false;
- }
+ if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
+ return false;
}
+
if (s == nullptr) {
// We only allow an undefined symbol if this is a weak reference...
s = &symtab_[sym];
if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
- DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_soname());
+ DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, get_realpath());
return false;
}
@@ -1868,9 +1921,32 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& globa
DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
return false;
}
- } else {
- // We got a definition.
+ } else { // We got a definition.
+#if !defined(__LP64__)
+ // When relocating dso with text_relocation .text segment is
+ // not executable. We need to restore elf flags before resolving
+ // STT_GNU_IFUNC symbol.
+ bool protect_segments = has_text_relocations &&
+ lsi == this &&
+ ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC;
+ if (protect_segments) {
+ if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
+ DL_ERR("can't protect segments for \"%s\": %s",
+ get_realpath(), strerror(errno));
+ return false;
+ }
+ }
+#endif
sym_addr = lsi->resolve_symbol_address(s);
+#if !defined(__LP64__)
+ if (protect_segments) {
+ if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
+ DL_ERR("can't unprotect loadable segments for \"%s\": %s",
+ get_realpath(), strerror(errno));
+ return false;
+ }
+ }
+#endif
}
count_relocation(kRelocSymbol);
}
@@ -1907,7 +1983,32 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& globa
TRACE_TYPE(RELO, "RELO IRELATIVE %16p <- %16p\n",
reinterpret_cast<void*>(reloc),
reinterpret_cast<void*>(load_bias + addend));
- *reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(load_bias + addend);
+ {
+#if !defined(__LP64__)
+ // When relocating dso with text_relocation .text segment is
+ // not executable. We need to restore elf flags for this
+ // particular call.
+ if (has_text_relocations) {
+ if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
+ DL_ERR("can't protect segments for \"%s\": %s",
+ get_realpath(), strerror(errno));
+ return false;
+ }
+ }
+#endif
+ ElfW(Addr) ifunc_addr = call_ifunc_resolver(load_bias + addend);
+#if !defined(__LP64__)
+ // Unprotect it afterwards...
+ if (has_text_relocations) {
+ if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
+ DL_ERR("can't unprotect loadable segments for \"%s\": %s",
+ get_realpath(), strerror(errno));
+ return false;
+ }
+ }
+#endif
+ *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
+ }
break;
#if defined(__aarch64__)
@@ -2012,7 +2113,7 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& globa
* R_AARCH64_COPY may only appear in executable objects where e_type is
* set to ET_EXEC.
*/
- DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_soname());
+ DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
return false;
case R_AARCH64_TLS_TPREL64:
TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
@@ -2069,7 +2170,7 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& globa
* R_ARM_COPY may only appear in executable objects where e_type is
* set to ET_EXEC.
*/
- DL_ERR("%s R_ARM_COPY relocations are not supported", get_soname());
+ DL_ERR("%s R_ARM_COPY relocations are not supported", get_realpath());
return false;
#elif defined(__i386__)
case R_386_32:
@@ -2101,7 +2202,7 @@ void soinfo::call_array(const char* array_name __unused, linker_function_t* func
return;
}
- TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_soname());
+ TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, get_realpath());
int begin = reverse ? (count - 1) : 0;
int end = reverse ? -1 : count;
@@ -2112,7 +2213,7 @@ void soinfo::call_array(const char* array_name __unused, linker_function_t* func
call_function("function", functions[i]);
}
- TRACE("[ Done calling %s for '%s' ]", array_name, get_soname());
+ TRACE("[ Done calling %s for '%s' ]", array_name, get_realpath());
}
void soinfo::call_function(const char* function_name __unused, linker_function_t function) {
@@ -2120,9 +2221,9 @@ void soinfo::call_function(const char* function_name __unused, linker_function_t
return;
}
- TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_soname());
+ TRACE("[ Calling %s @ %p for '%s' ]", function_name, function, get_realpath());
function();
- TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_soname());
+ TRACE("[ Done calling %s @ %p for '%s' ]", function_name, function, get_realpath());
}
void soinfo::call_pre_init_constructors() {
@@ -2151,14 +2252,14 @@ void soinfo::call_constructors() {
if (!is_main_executable() && preinit_array_ != nullptr) {
// The GNU dynamic linker silently ignores these, but we warn the developer.
PRINT("\"%s\": ignoring %zd-entry DT_PREINIT_ARRAY in shared library!",
- get_soname(), preinit_array_count_);
+ get_realpath(), preinit_array_count_);
}
get_children().for_each([] (soinfo* si) {
si->call_constructors();
});
- TRACE("\"%s\": calling constructors", get_soname());
+ TRACE("\"%s\": calling constructors", get_realpath());
// DT_INIT should be called before DT_INIT_ARRAY if both are present.
call_function("DT_INIT", init_func_);
@@ -2169,7 +2270,7 @@ void soinfo::call_destructors() {
if (!constructors_called) {
return;
}
- TRACE("\"%s\": calling destructors", get_soname());
+ TRACE("\"%s\": calling destructors", get_realpath());
// DT_FINI_ARRAY must be parsed in reverse order.
call_array("DT_FINI_ARRAY", fini_array_, fini_array_count_, true);
@@ -2267,7 +2368,7 @@ void soinfo::set_dt_flags_1(uint32_t dt_flags_1) {
}
const char* soinfo::get_realpath() const {
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
if (has_min_version(2)) {
return realpath_.c_str();
} else {
@@ -2279,7 +2380,7 @@ const char* soinfo::get_realpath() const {
}
const char* soinfo::get_soname() const {
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
if (has_min_version(2)) {
return soname_;
} else {
@@ -2329,7 +2430,7 @@ ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
const char* soinfo::get_string(ElfW(Word) index) const {
if (has_min_version(1) && (index >= strtab_size_)) {
__libc_fatal("%s: strtab out of bounds error; STRSZ=%zd, name=%d",
- get_soname(), strtab_size_, index);
+ get_realpath(), strtab_size_, index);
}
return strtab_ + index;
@@ -2375,65 +2476,15 @@ soinfo* soinfo::get_local_group_root() const {
return local_group_root_;
}
-/* Force any of the closed stdin, stdout and stderr to be associated with
- /dev/null. */
-static int nullify_closed_stdio() {
- int dev_null, i, status;
- int return_value = 0;
-
- dev_null = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
- if (dev_null < 0) {
- DL_ERR("cannot open /dev/null: %s", strerror(errno));
- return -1;
+// This function returns api-level at the time of
+// dlopen/load. Note that libraries opened by system
+// will always have 'current' api level.
+uint32_t soinfo::get_target_sdk_version() const {
+ if (!has_min_version(2)) {
+ return __ANDROID_API__;
}
- TRACE("[ Opened /dev/null file-descriptor=%d]", dev_null);
-
- /* If any of the stdio file descriptors is valid and not associated
- with /dev/null, dup /dev/null to it. */
- for (i = 0; i < 3; i++) {
- /* If it is /dev/null already, we are done. */
- if (i == dev_null) {
- continue;
- }
- TRACE("[ Nullifying stdio file descriptor %d]", i);
- status = TEMP_FAILURE_RETRY(fcntl(i, F_GETFL));
-
- /* If file is opened, we are good. */
- if (status != -1) {
- continue;
- }
-
- /* The only error we allow is that the file descriptor does not
- exist, in which case we dup /dev/null to it. */
- if (errno != EBADF) {
- DL_ERR("fcntl failed: %s", strerror(errno));
- return_value = -1;
- continue;
- }
-
- /* Try dupping /dev/null to this stdio file descriptor and
- repeat if there is a signal. Note that any errors in closing
- the stdio descriptor are lost. */
- status = TEMP_FAILURE_RETRY(dup2(dev_null, i));
- if (status < 0) {
- DL_ERR("dup2 failed: %s", strerror(errno));
- return_value = -1;
- continue;
- }
- }
-
- /* If /dev/null is not one of the stdio file descriptors, close it. */
- if (dev_null > 2) {
- TRACE("[ Closing /dev/null file-descriptor=%d]", dev_null);
- status = TEMP_FAILURE_RETRY(close(dev_null));
- if (status == -1) {
- DL_ERR("close failed: %s", strerror(errno));
- return_value = -1;
- }
- }
-
- return return_value;
+ return local_group_root_->target_sdk_version_;
}
bool soinfo::prelink_image() {
@@ -2444,13 +2495,13 @@ bool soinfo::prelink_image() {
/* We can't log anything until the linker is relocated */
bool relocating_linker = (flags_ & FLAG_LINKER) != 0;
if (!relocating_linker) {
- INFO("[ linking %s ]", get_soname());
+ INFO("[ linking %s ]", get_realpath());
DEBUG("si->base = %p si->flags = 0x%08x", reinterpret_cast<void*>(base), flags_);
}
if (dynamic == nullptr) {
if (!relocating_linker) {
- DL_ERR("missing PT_DYNAMIC in \"%s\"", get_soname());
+ DL_ERR("missing PT_DYNAMIC in \"%s\"", get_realpath());
}
return false;
} else {
@@ -2743,7 +2794,7 @@ bool soinfo::prelink_image() {
set_dt_flags_1(d->d_un.d_val);
if ((d->d_un.d_val & ~SUPPORTED_DT_FLAGS_1) != 0) {
- DL_WARN("Unsupported flags DT_FLAGS_1=%p", reinterpret_cast<void*>(d->d_un.d_val));
+ DL_WARN("%s: unsupported flags DT_FLAGS_1=%p", get_realpath(), reinterpret_cast<void*>(d->d_un.d_val));
}
break;
#if defined(__mips__)
@@ -2813,17 +2864,6 @@ bool soinfo::prelink_image() {
}
}
- // second pass - parse entries relying on strtab
- for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
- if (d->d_tag == DT_SONAME) {
- soname_ = get_string(d->d_un.d_val);
-#if defined(__arm__)
- strlcpy(old_name_, soname_, sizeof(old_name_));
-#endif
- break;
- }
- }
-
DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
reinterpret_cast<void*>(base), strtab_, symtab_);
@@ -2834,17 +2874,41 @@ bool soinfo::prelink_image() {
}
if (nbucket_ == 0 && gnu_nbucket_ == 0) {
DL_ERR("empty/missing DT_HASH/DT_GNU_HASH in \"%s\" "
- "(new hash type from the future?)", get_soname());
+ "(new hash type from the future?)", get_realpath());
return false;
}
if (strtab_ == 0) {
- DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_soname());
+ DL_ERR("empty/missing DT_STRTAB in \"%s\"", get_realpath());
return false;
}
if (symtab_ == 0) {
- DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_soname());
+ DL_ERR("empty/missing DT_SYMTAB in \"%s\"", get_realpath());
return false;
}
+
+ // second pass - parse entries relying on strtab
+ for (ElfW(Dyn)* d = dynamic; d->d_tag != DT_NULL; ++d) {
+ if (d->d_tag == DT_SONAME) {
+ soname_ = get_string(d->d_un.d_val);
+#if defined(__work_around_b_19059885__)
+ strlcpy(old_name_, soname_, sizeof(old_name_));
+#endif
+ break;
+ }
+ }
+
+ // Before M release linker was using basename in place of soname.
+ // In the case when dt_soname is absent some apps stop working
+ // because they can't find dt_needed library by soname.
+ // This workaround should keep them working. (applies only
+ // for apps targeting sdk version <=22). Make an exception for
+ // the main executable and linker; they do not need to have dt_soname
+ if (soname_ == nullptr && this != somain && (flags_ & FLAG_LINKER) == 0 &&
+ get_application_target_sdk_version() <= 22) {
+ soname_ = basename(realpath_.c_str());
+ DL_WARN("%s: is missing DT_SONAME will use basename as a replacement: \"%s\"",
+ get_realpath(), soname_);
+ }
return true;
}
@@ -2856,15 +2920,32 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
local_group_root_ = this;
}
+ if ((flags_ & FLAG_LINKER) == 0 && local_group_root_ == this) {
+ target_sdk_version_ = get_application_target_sdk_version();
+ }
+
+ VersionTracker version_tracker;
+
+ if (!version_tracker.init(this)) {
+ return false;
+ }
+
#if !defined(__LP64__)
if (has_text_relocations) {
+ // Fail if app is targeting sdk version > 22
+ // TODO (dimitry): remove != __ANDROID_API__ check once http://b/20020312 is fixed
+ if (get_application_target_sdk_version() != __ANDROID_API__
+ && get_application_target_sdk_version() > 22) {
+ DL_ERR("%s: has text relocations", get_realpath());
+ return false;
+ }
// Make segments writable to allow text relocations to work properly. We will later call
// phdr_table_protect_segments() after all of them are applied and all constructors are run.
DL_WARN("%s has text relocations. This is wasting memory and prevents "
- "security hardening. Please fix.", get_soname());
+ "security hardening. Please fix.", get_realpath());
if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
DL_ERR("can't unprotect loadable segments for \"%s\": %s",
- get_soname(), strerror(errno));
+ get_realpath(), strerror(errno));
return false;
}
}
@@ -2877,13 +2958,14 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
android_relocs_[1] == 'P' &&
android_relocs_[2] == 'S' &&
android_relocs_[3] == '2') {
- DEBUG("[ android relocating %s ]", get_soname());
+ DEBUG("[ android relocating %s ]", get_realpath());
bool relocated = false;
const uint8_t* packed_relocs = android_relocs_ + 4;
const size_t packed_relocs_size = android_relocs_size_ - 4;
relocated = relocate(
+ version_tracker,
packed_reloc_iterator<sleb128_decoder>(
sleb128_decoder(packed_relocs, packed_relocs_size)),
global_group, local_group);
@@ -2899,46 +2981,50 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
#if defined(USE_RELA)
if (rela_ != nullptr) {
- DEBUG("[ relocating %s ]", get_soname());
- if (!relocate(plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
+ DEBUG("[ relocating %s ]", get_realpath());
+ if (!relocate(version_tracker,
+ plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
return false;
}
}
if (plt_rela_ != nullptr) {
- DEBUG("[ relocating %s plt ]", get_soname());
- if (!relocate(plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
+ DEBUG("[ relocating %s plt ]", get_realpath());
+ if (!relocate(version_tracker,
+ plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
return false;
}
}
#else
if (rel_ != nullptr) {
- DEBUG("[ relocating %s ]", get_soname());
- if (!relocate(plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
+ DEBUG("[ relocating %s ]", get_realpath());
+ if (!relocate(version_tracker,
+ plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
return false;
}
}
if (plt_rel_ != nullptr) {
- DEBUG("[ relocating %s plt ]", get_soname());
- if (!relocate(plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
+ DEBUG("[ relocating %s plt ]", get_realpath());
+ if (!relocate(version_tracker,
+ plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
return false;
}
}
#endif
#if defined(__mips__)
- if (!mips_relocate_got(global_group, local_group)) {
+ if (!mips_relocate_got(version_tracker, global_group, local_group)) {
return false;
}
#endif
- DEBUG("[ finished linking %s ]", get_soname());
+ DEBUG("[ finished linking %s ]", get_realpath());
#if !defined(__LP64__)
if (has_text_relocations) {
// All relocations are done, we can protect our segments back to read-only.
if (phdr_table_protect_segments(phdr, phnum, load_bias) < 0) {
DL_ERR("can't protect segments for \"%s\": %s",
- get_soname(), strerror(errno));
+ get_realpath(), strerror(errno));
return false;
}
}
@@ -2947,7 +3033,7 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
/* We can also turn on GNU RELRO protection */
if (phdr_table_protect_gnu_relro(phdr, phnum, load_bias) < 0) {
DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
- get_soname(), strerror(errno));
+ get_realpath(), strerror(errno));
return false;
}
@@ -2956,14 +3042,14 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
if (phdr_table_serialize_gnu_relro(phdr, phnum, load_bias,
extinfo->relro_fd) < 0) {
DL_ERR("failed serializing GNU RELRO section for \"%s\": %s",
- get_soname(), strerror(errno));
+ get_realpath(), strerror(errno));
return false;
}
} else if (extinfo && (extinfo->flags & ANDROID_DLEXT_USE_RELRO)) {
if (phdr_table_map_gnu_relro(phdr, phnum, load_bias,
extinfo->relro_fd) < 0) {
DL_ERR("failed mapping GNU RELRO section for \"%s\": %s",
- get_soname(), strerror(errno));
+ get_realpath(), strerror(errno));
return false;
}
}
@@ -3022,7 +3108,7 @@ static soinfo* linker_soinfo_for_gdb = nullptr;
static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
linker_soinfo_for_gdb = new (linker_soinfo_for_gdb_buf) soinfo(LINKER_PATH, nullptr, 0, 0);
- linker_soinfo_for_gdb->base = linker_base;
+ linker_soinfo_for_gdb->load_bias = linker_base;
/*
* Set the dynamic field in the link map otherwise gdb will complain with
@@ -3037,6 +3123,8 @@ static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
insert_soinfo_into_debug_map(linker_soinfo_for_gdb);
}
+extern "C" int __system_properties_init(void);
+
/*
* This code is called after the linker has linked itself and
* fixed it's own GOT. It is safe to make references to externs
@@ -3048,38 +3136,29 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
gettimeofday(&t0, 0);
#endif
- // Initialize environment functions, and get to the ELF aux vectors table.
- linker_env_init(args);
+ // Sanitize the environment.
+ __libc_init_AT_SECURE(args);
- // If this is a setuid/setgid program, close the security hole described in
- // ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
- if (get_AT_SECURE()) {
- nullify_closed_stdio();
- }
+ // Initialize system properties
+ __system_properties_init(); // may use 'environ'
debuggerd_init();
// Get a few environment variables.
- const char* LD_DEBUG = linker_env_get("LD_DEBUG");
+ const char* LD_DEBUG = getenv("LD_DEBUG");
if (LD_DEBUG != nullptr) {
g_ld_debug_verbosity = atoi(LD_DEBUG);
}
- // Normally, these are cleaned by linker_env_init, but the test
+ // These should have been sanitized by __libc_init_AT_SECURE, but the test
// doesn't cost us anything.
const char* ldpath_env = nullptr;
const char* ldpreload_env = nullptr;
- if (!get_AT_SECURE()) {
- ldpath_env = linker_env_get("LD_LIBRARY_PATH");
- ldpreload_env = linker_env_get("LD_PRELOAD");
+ if (!getauxval(AT_SECURE)) {
+ ldpath_env = getenv("LD_LIBRARY_PATH");
+ ldpreload_env = getenv("LD_PRELOAD");
}
-#if !defined(__LP64__)
- if (personality(PER_LINUX32) == -1) {
- __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
- }
-#endif
-
INFO("[ android linker & debugger ]");
soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL);
@@ -3150,6 +3229,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
for (const auto& ld_preload_name : g_ld_preload_names) {
needed_library_name_list.push_back(ld_preload_name.c_str());
++needed_libraries_count;
+ ++ld_preloads_count;
}
for_each_dt_needed(si, [&](const char* name) {
@@ -3232,7 +3312,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
fflush(stdout);
#endif
- TRACE("[ Ready to execute '%s' @ %p ]", si->get_soname(), reinterpret_cast<void*>(si->entry));
+ TRACE("[ Ready to execute '%s' @ %p ]", si->get_realpath(), reinterpret_cast<void*>(si->entry));
return si->entry;
}
@@ -3248,7 +3328,8 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
*/
static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf) {
ElfW(Addr) offset = elf->e_phoff;
- const ElfW(Phdr)* phdr_table = reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
+ const ElfW(Phdr)* phdr_table =
+ reinterpret_cast<const ElfW(Phdr)*>(reinterpret_cast<uintptr_t>(elf) + offset);
const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
diff --git a/linker/linker.h b/linker/linker.h
index dae3972..023b672 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -97,7 +97,7 @@
#define SOINFO_VERSION 2
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
#define SOINFO_NAME_LEN 128
#endif
@@ -172,7 +172,7 @@ class VersionTracker {
struct soinfo {
public:
typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
private:
char old_name_[SOINFO_NAME_LEN];
#endif
@@ -183,13 +183,13 @@ struct soinfo {
ElfW(Addr) base;
size_t size;
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
uint32_t unused1; // DO NOT USE, maintained for compatibility.
#endif
ElfW(Dyn)* dynamic;
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
uint32_t unused2; // DO NOT USE, maintained for compatibility
uint32_t unused3; // DO NOT USE, maintained for compatibility
#endif
@@ -247,7 +247,9 @@ struct soinfo {
uint32_t mips_symtabno_;
uint32_t mips_local_gotno_;
uint32_t mips_gotsym_;
- bool mips_relocate_got(const soinfo_list_t& global_group, const soinfo_list_t& local_group);
+ bool mips_relocate_got(const VersionTracker& version_tracker,
+ const soinfo_list_t& global_group,
+ const soinfo_list_t& local_group);
#endif
size_t ref_count_;
@@ -303,7 +305,7 @@ struct soinfo {
bool is_gnu_hash() const;
bool inline has_min_version(uint32_t min_version __unused) const {
-#if defined(__arm__)
+#if defined(__work_around_b_19059885__)
return (flags_ & FLAG_NEW_SOINFO) != 0 && version_ >= min_version;
#else
return true;
@@ -332,17 +334,22 @@ struct soinfo {
bool find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const;
+ uint32_t get_target_sdk_version() const;
+
private:
bool elf_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
ElfW(Sym)* elf_addr_lookup(const void* addr);
bool gnu_lookup(SymbolName& symbol_name, const version_info* vi, uint32_t* symbol_index) const;
ElfW(Sym)* gnu_addr_lookup(const void* addr);
+ bool lookup_version_info(const VersionTracker& version_tracker, ElfW(Word) sym,
+ const char* sym_name, const version_info** vi);
+
void call_array(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
void call_function(const char* function_name, linker_function_t function);
template<typename ElfRelIteratorT>
- bool relocate(ElfRelIteratorT&& rel_iterator, const soinfo_list_t& global_group,
- const soinfo_list_t& local_group);
+ bool relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
+ const soinfo_list_t& global_group, const soinfo_list_t& local_group);
private:
// This part of the structure is only available
@@ -388,6 +395,8 @@ struct soinfo {
ElfW(Addr) verneed_ptr_;
size_t verneed_cnt_;
+ uint32_t target_sdk_version_;
+
friend soinfo* get_libdl_info();
};
@@ -412,6 +421,8 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
void do_dlclose(soinfo* si);
+int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data);
+
const ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle);
soinfo* find_containing_library(const void* addr);
@@ -424,4 +435,7 @@ extern "C" void notify_gdb_of_libraries();
char* linker_get_error_buffer();
size_t linker_get_error_buffer_size();
+void set_application_target_sdk_version(uint32_t target);
+uint32_t get_application_target_sdk_version();
+
#endif
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 5ded5ab..51f8d4c 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2010 The Android Open Source Project
+ * Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/linker/linker_environ.cpp b/linker/linker_environ.cpp
deleted file mode 100644
index 9a0f009..0000000
--- a/linker/linker_environ.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "linker_environ.h"
-
-#include <linux/auxvec.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "private/KernelArgumentBlock.h"
-
-static char** _envp;
-static bool _AT_SECURE_value = true;
-
-bool get_AT_SECURE() {
- return _AT_SECURE_value;
-}
-
-static void __init_AT_SECURE(KernelArgumentBlock& args) {
- // Check auxv for AT_SECURE first to see if program is setuid, setgid,
- // has file caps, or caused a SELinux/AppArmor domain transition.
- bool kernel_supplied_AT_SECURE;
- _AT_SECURE_value = args.getauxval(AT_SECURE, &kernel_supplied_AT_SECURE);
-
- // We don't support ancient kernels.
- if (!kernel_supplied_AT_SECURE) {
- const char* msg = "FATAL: kernel did not supply AT_SECURE\n";
- write(2, msg, strlen(msg));
- exit(EXIT_FAILURE);
- }
-}
-
-// Check if the environment variable definition at 'envstr'
-// starts with '<name>=', and if so return the address of the
-// first character after the equal sign. Otherwise return null.
-static const char* env_match(const char* envstr, const char* name) {
- size_t i = 0;
-
- while (envstr[i] == name[i] && name[i] != '\0') {
- ++i;
- }
-
- if (name[i] == '\0' && envstr[i] == '=') {
- return envstr + i + 1;
- }
-
- return nullptr;
-}
-
-static bool __is_valid_environment_variable(const char* name) {
- // According to its sources, the kernel uses 32*PAGE_SIZE by default
- // as the maximum size for an env. variable definition.
- const int MAX_ENV_LEN = 32*4096;
-
- if (name == nullptr) {
- return false;
- }
-
- // Parse the string, looking for the first '=' there, and its size.
- int pos = 0;
- int first_equal_pos = -1;
- while (pos < MAX_ENV_LEN) {
- if (name[pos] == '\0') {
- break;
- }
- if (name[pos] == '=' && first_equal_pos < 0) {
- first_equal_pos = pos;
- }
- pos++;
- }
-
- // Check that it's smaller than MAX_ENV_LEN (to detect non-zero terminated strings).
- if (pos >= MAX_ENV_LEN) {
- return false;
- }
-
- // Check that it contains at least one equal sign that is not the first character
- if (first_equal_pos < 1) {
- return false;
- }
-
- return true;
-}
-
-static bool __is_unsafe_environment_variable(const char* name) {
- // None of these should be allowed in setuid programs.
- static const char* const UNSAFE_VARIABLE_NAMES[] = {
- "GCONV_PATH",
- "GETCONF_DIR",
- "HOSTALIASES",
- "JE_MALLOC_CONF",
- "LD_AOUT_LIBRARY_PATH",
- "LD_AOUT_PRELOAD",
- "LD_AUDIT",
- "LD_DEBUG",
- "LD_DEBUG_OUTPUT",
- "LD_DYNAMIC_WEAK",
- "LD_LIBRARY_PATH",
- "LD_ORIGIN_PATH",
- "LD_PRELOAD",
- "LD_PROFILE",
- "LD_SHOW_AUXV",
- "LD_USE_LOAD_BIAS",
- "LOCALDOMAIN",
- "LOCPATH",
- "MALLOC_CHECK_",
- "MALLOC_CONF",
- "MALLOC_TRACE",
- "NIS_PATH",
- "NLSPATH",
- "RESOLV_HOST_CONF",
- "RES_OPTIONS",
- "TMPDIR",
- "TZDIR",
- nullptr
- };
- for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != nullptr; ++i) {
- if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != nullptr) {
- return true;
- }
- }
- return false;
-}
-
-static void __sanitize_environment_variables() {
- char** src = _envp;
- char** dst = _envp;
- for (; src[0] != nullptr; ++src) {
- if (!__is_valid_environment_variable(src[0])) {
- continue;
- }
- // Remove various unsafe environment variables if we're loading a setuid program.
- if (get_AT_SECURE() && __is_unsafe_environment_variable(src[0])) {
- continue;
- }
- dst[0] = src[0];
- ++dst;
- }
- dst[0] = nullptr;
-}
-
-void linker_env_init(KernelArgumentBlock& args) {
- // Store environment pointer - can't be null.
- _envp = args.envp;
-
- __init_AT_SECURE(args);
- __sanitize_environment_variables();
-}
-
-const char* linker_env_get(const char* name) {
- if (name == nullptr || name[0] == '\0') {
- return nullptr;
- }
-
- for (char** p = _envp; p[0] != nullptr; ++p) {
- const char* val = env_match(p[0], name);
- if (val != nullptr) {
- if (val[0] == '\0') {
- return nullptr; // Return null for empty strings.
- }
- return val;
- }
- }
- return nullptr;
-}
diff --git a/linker/linker_mips.cpp b/linker/linker_mips.cpp
index 0769f82..a7a4bc0 100644
--- a/linker/linker_mips.cpp
+++ b/linker/linker_mips.cpp
@@ -32,25 +32,22 @@
#include "linker_reloc_iterators.h"
#include "linker_sleb128.h"
-template bool soinfo::relocate<plain_reloc_iterator>(plain_reloc_iterator&& rel_iterator,
+template bool soinfo::relocate<plain_reloc_iterator>(const VersionTracker& version_tracker,
+ plain_reloc_iterator&& rel_iterator,
const soinfo_list_t& global_group,
const soinfo_list_t& local_group);
template bool soinfo::relocate<packed_reloc_iterator<sleb128_decoder>>(
+ const VersionTracker& version_tracker,
packed_reloc_iterator<sleb128_decoder>&& rel_iterator,
const soinfo_list_t& global_group,
const soinfo_list_t& local_group);
template <typename ElfRelIteratorT>
-bool soinfo::relocate(ElfRelIteratorT&& rel_iterator,
+bool soinfo::relocate(const VersionTracker& version_tracker,
+ ElfRelIteratorT&& rel_iterator,
const soinfo_list_t& global_group,
const soinfo_list_t& local_group) {
- VersionTracker version_tracker;
-
- if (!version_tracker.init(this)) {
- return false;
- }
-
for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
const auto rel = rel_iterator.next();
@@ -75,26 +72,14 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator,
if (sym != 0) {
sym_name = get_string(symtab_[sym].st_name);
- const ElfW(Versym)* sym_ver_ptr = get_versym(sym);
- ElfW(Versym) sym_ver = sym_ver_ptr == nullptr ? 0 : *sym_ver_ptr;
-
- if (sym_ver == VER_NDX_LOCAL || sym_ver == VER_NDX_GLOBAL) {
- // there is no version info for this one
- if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) {
- return false;
- }
- } else {
- const version_info* vi = version_tracker.get_version_info(sym_ver);
+ const version_info* vi = nullptr;
- if (vi == nullptr) {
- DL_ERR("cannot find verneed/verdef for version index=%d "
- "referenced by symbol \"%s\" at \"%s\"", sym_ver, sym_name, get_soname());
- return false;
- }
+ if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
+ return false;
+ }
- if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
- return false;
- }
+ if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
+ return false;
}
if (s == nullptr) {
@@ -128,7 +113,7 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator,
if (s != nullptr) {
*reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
} else {
- *reinterpret_cast<ElfW(Addr)*>(reloc) += base;
+ *reinterpret_cast<ElfW(Addr)*>(reloc) += load_bias;
}
break;
default:
@@ -139,7 +124,8 @@ bool soinfo::relocate(ElfRelIteratorT&& rel_iterator,
return true;
}
-bool soinfo::mips_relocate_got(const soinfo_list_t& global_group,
+bool soinfo::mips_relocate_got(const VersionTracker& version_tracker,
+ const soinfo_list_t& global_group,
const soinfo_list_t& local_group) {
ElfW(Addr)** got = plt_got_;
if (got == nullptr) {
@@ -163,22 +149,42 @@ bool soinfo::mips_relocate_got(const soinfo_list_t& global_group,
}
// Now for the global GOT entries...
- ElfW(Sym)* sym = symtab_ + mips_gotsym_;
got = plt_got_ + mips_local_gotno_;
- for (size_t g = mips_gotsym_; g < mips_symtabno_; g++, sym++, got++) {
+ for (ElfW(Word) sym = mips_gotsym_; sym < mips_symtabno_; sym++, got++) {
// This is an undefined reference... try to locate it.
- const char* sym_name = get_string(sym->st_name);
+ const ElfW(Sym)* local_sym = symtab_ + sym;
+ const char* sym_name = get_string(local_sym->st_name);
soinfo* lsi = nullptr;
const ElfW(Sym)* s = nullptr;
- if (!soinfo_do_lookup(this, sym_name, nullptr, &lsi, global_group, local_group, &s)) {
+
+ ElfW(Word) st_visibility = (local_sym->st_other & 0x3);
+
+ if (st_visibility == STV_DEFAULT) {
+ const version_info* vi = nullptr;
+
+ if (!lookup_version_info(version_tracker, sym, sym_name, &vi)) {
+ return false;
+ }
+
+ if (!soinfo_do_lookup(this, sym_name, vi, &lsi, global_group, local_group, &s)) {
+ return false;
+ }
+ } else if (st_visibility == STV_PROTECTED) {
+ if (local_sym->st_value == 0) {
+ DL_ERR("%s: invalid symbol \"%s\" (PROTECTED/UNDEFINED) ", get_soname(), sym_name);
+ return false;
+ }
+ s = local_sym;
+ lsi = this;
+ } else {
+ DL_ERR("%s: invalid symbol \"%s\" visibility: 0x%x", get_soname(), sym_name, st_visibility);
return false;
}
if (s == nullptr) {
// We only allow an undefined symbol if this is a weak reference.
- s = &symtab_[g];
- if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
- DL_ERR("cannot locate \"%s\"...", sym_name);
+ if (ELF_ST_BIND(local_sym->st_info) != STB_WEAK) {
+ DL_ERR("%s: cannot locate \"%s\"...", get_soname(), sym_name);
return false;
}
*got = 0;
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 638c9d6..30118e3 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -133,8 +133,8 @@ static int GetTargetElfMachine() {
MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
-ElfReader::ElfReader(const char* name, int fd, off64_t file_offset)
- : name_(name), fd_(fd), file_offset_(file_offset),
+ElfReader::ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size)
+ : name_(name), fd_(fd), file_offset_(file_offset), file_size_(file_size),
phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0),
load_start_(nullptr), load_size_(0), load_bias_(0),
loaded_phdr_(nullptr) {
@@ -316,6 +316,8 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
void* start;
size_t reserved_size = 0;
bool reserved_hint = true;
+ // Assume position independent executable by default.
+ uint8_t* mmap_hint = nullptr;
if (extinfo != nullptr) {
if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
@@ -324,6 +326,10 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
} else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
reserved_size = extinfo->reserved_size;
}
+
+ if ((extinfo->flags & ANDROID_DLEXT_FORCE_FIXED_VADDR) != 0) {
+ mmap_hint = addr;
+ }
}
if (load_size_ > reserved_size) {
@@ -333,7 +339,7 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
return false;
}
int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
- start = mmap(nullptr, load_size_, PROT_NONE, mmap_flags, -1, 0);
+ start = mmap(mmap_hint, load_size_, PROT_NONE, mmap_flags, -1, 0);
if (start == MAP_FAILED) {
DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_);
return false;
@@ -371,6 +377,20 @@ bool ElfReader::LoadSegments() {
ElfW(Addr) file_page_start = PAGE_START(file_start);
ElfW(Addr) file_length = file_end - file_page_start;
+ if (file_size_ <= 0) {
+ DL_ERR("\"%s\" invalid file size: %" PRId64, name_, file_size_);
+ return false;
+ }
+
+ if (file_end >= static_cast<size_t>(file_size_)) {
+ DL_ERR("invalid ELF file \"%s\" load segment[%zd]:"
+ " p_offset (%p) + p_filesz (%p) ( = %p) past end of file (0x%" PRIx64 ")",
+ name_, i, reinterpret_cast<void*>(phdr->p_offset),
+ reinterpret_cast<void*>(phdr->p_filesz),
+ reinterpret_cast<void*>(file_end), file_size_);
+ return false;
+ }
+
if (file_length != 0) {
void* seg_addr = mmap64(reinterpret_cast<void*>(seg_page_start),
file_length,
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 50f2117..3affa66 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -39,7 +39,7 @@
class ElfReader {
public:
- ElfReader(const char* name, int fd, off64_t file_offset);
+ ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size);
~ElfReader();
bool Load(const android_dlextinfo* extinfo);
@@ -62,6 +62,7 @@ class ElfReader {
const char* name_;
int fd_;
off64_t file_offset_;
+ off64_t file_size_;
ElfW(Ehdr) header_;
size_t phdr_num_;
diff --git a/linker/linker_sdk_versions.cpp b/linker/linker_sdk_versions.cpp
new file mode 100644
index 0000000..9aebb06
--- /dev/null
+++ b/linker/linker_sdk_versions.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "linker.h"
+#include <android/api-level.h>
+#include <atomic>
+
+static std::atomic<uint32_t> g_target_sdk_version(__ANDROID_API__);
+
+void set_application_target_sdk_version(uint32_t target) {
+ // translate current sdk_version to platform sdk_version
+ if (target == 0) {
+ target = __ANDROID_API__;
+ }
+ g_target_sdk_version = target;
+}
+
+uint32_t get_application_target_sdk_version() {
+ return g_target_sdk_version;
+}
+
diff --git a/tests/Android.mk b/tests/Android.mk
index cd65c10..dc2e410 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -93,6 +93,7 @@ libBionicStandardTests_src_files := \
sys_epoll_test.cpp \
sys_mman_test.cpp \
sys_personality_test.cpp \
+ sys_procfs_test.cpp \
sys_resource_test.cpp \
sys_select_test.cpp \
sys_sendfile_test.cpp \
@@ -103,7 +104,9 @@ libBionicStandardTests_src_files := \
sys_sysinfo_test.cpp \
sys_time_test.cpp \
sys_types_test.cpp \
+ sys_uio_test.cpp \
sys_vfs_test.cpp \
+ sys_xattr_test.cpp \
system_properties_test.cpp \
time_test.cpp \
uchar_test.cpp \
@@ -238,7 +241,12 @@ libBionicCtsGtestMain_src_files := gtest_main.cpp
libBionicCtsGtestMain_cflags := $(test_cflags)
-libBionicCtsGtestMain_cppflags := $(test_cppflags) -DUSING_GTEST_OUTPUT_FORMAT
+libBionicCtsGtestMain_cppflags := $(test_cppflags) -DUSING_GTEST_OUTPUT_FORMAT \
+
+# Temporarily fix the job count to 1 for CTS since on some devices the
+# number of online cores is incorrectly read as the total number of cores
+# in the system. When b/24376925 is fixed, this should be removed.
+libBionicCtsGtestMain_cppflags += -DJOB_COUNT_FIXED=1
module := libBionicCtsGtestMain
module_tag := optional
@@ -269,6 +277,8 @@ bionic-unit-tests_src_files := \
dlext_test.cpp \
__cxa_thread_atexit_test.cpp \
dlfcn_test.cpp \
+ libdl_test.cpp \
+ pthread_dlfcn_test.cpp \
bionic-unit-tests_cflags := $(test_cflags)
@@ -346,6 +356,7 @@ bionic-unit-tests-glibc_src_files := \
atexit_test.cpp \
dlfcn_test.cpp \
dl_test.cpp \
+ pthread_dlfcn_test.cpp \
bionic-unit-tests-glibc_shared_libraries := \
libdl_preempt_test_1 \
@@ -396,7 +407,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES := \
LOCAL_CXX = $(LOCAL_PATH)/file-check-cxx \
$(HOST_OUT_EXECUTABLES)/FileCheck \
- $($(LOCAL_2ND_ARCH_VAR_PREFIX)CXX_BARE) \
+ $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_CXX) \
GCC \
LOCAL_CLANG := false
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index 56a8f6f..f901708 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -214,7 +214,7 @@ TEST(dlext, android_dlopen_ext_force_load_soname_exception) {
TEST(dlfcn, dlopen_from_zip_absolute_path) {
const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
- void* handle = dlopen((lib_path + "!libdir/libdlext_test_fd.so").c_str(), RTLD_NOW);
+ void* handle = dlopen((lib_path + "!/libdir/libdlext_test_fd.so").c_str(), RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
int (*fn)(void);
@@ -226,7 +226,7 @@ TEST(dlfcn, dlopen_from_zip_absolute_path) {
}
TEST(dlfcn, dlopen_from_zip_ld_library_path) {
- const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!libdir";
+ const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!/libdir";
typedef void (*fn_t)(const char*);
fn_t android_update_LD_LIBRARY_PATH =
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 6b1f109..3c9b8e3 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -71,30 +71,102 @@ TEST(dlfcn, dlsym_from_sofile) {
void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_LAZY | RTLD_LOCAL);
ASSERT_TRUE(handle != nullptr) << dlerror();
- // check that we cant find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
+ // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
ASSERT_TRUE(symbol == nullptr);
ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
typedef int* (*fn_t)();
- fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
+ fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
+ ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
- ASSERT_TRUE(fn != nullptr) << dlerror();
+ int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
+ ASSERT_TRUE(ptr != nullptr) << dlerror();
+ ASSERT_EQ(42, *ptr);
+
+ fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
+ ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
+
+ ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
+ ASSERT_TRUE(ptr != nullptr) << dlerror();
+ ASSERT_EQ(44, *ptr);
+
+ fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
+ ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
+
+ ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
+ ASSERT_TRUE(ptr != nullptr) << dlerror();
+ ASSERT_EQ(43, *ptr);
+
+ dlclose(handle);
+}
+
+TEST(dlfcn, dlsym_from_sofile_with_preload) {
+ void* preload = dlopen("libtest_dlsym_from_this_grandchild.so", RTLD_NOW | RTLD_LOCAL);
+ ASSERT_TRUE(preload != nullptr) << dlerror();
+
+ void* handle = dlopen("libtest_dlsym_from_this.so", RTLD_NOW | RTLD_LOCAL);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+
+ // check that we can't find '_test_dlsym_symbol' via dlsym(RTLD_DEFAULT)
+ void* symbol = dlsym(RTLD_DEFAULT, "test_dlsym_symbol");
+ ASSERT_TRUE(symbol == nullptr);
+ ASSERT_SUBSTR("undefined symbol: test_dlsym_symbol", dlerror());
+
+ typedef int* (*fn_t)();
+ fn_t lookup_dlsym_symbol_using_RTLD_DEFAULT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_DEFAULT"));
+ ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_DEFAULT != nullptr) << dlerror();
- int* ptr = fn();
+ int* ptr = lookup_dlsym_symbol_using_RTLD_DEFAULT();
ASSERT_TRUE(ptr != nullptr) << dlerror();
ASSERT_EQ(42, *ptr);
+ fn_t lookup_dlsym_symbol2_using_RTLD_DEFAULT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol2_using_RTLD_DEFAULT"));
+ ASSERT_TRUE(lookup_dlsym_symbol2_using_RTLD_DEFAULT != nullptr) << dlerror();
+
+ ptr = lookup_dlsym_symbol2_using_RTLD_DEFAULT();
+ ASSERT_TRUE(ptr != nullptr) << dlerror();
+ ASSERT_EQ(44, *ptr);
+
+ fn_t lookup_dlsym_symbol_using_RTLD_NEXT =
+ reinterpret_cast<fn_t>(dlsym(handle, "lookup_dlsym_symbol_using_RTLD_NEXT"));
+ ASSERT_TRUE(lookup_dlsym_symbol_using_RTLD_NEXT != nullptr) << dlerror();
+
+ ptr = lookup_dlsym_symbol_using_RTLD_NEXT();
+ ASSERT_TRUE(ptr != nullptr) << dlerror();
+ ASSERT_EQ(43, *ptr);
+
+ dlclose(handle);
+ dlclose(preload);
+}
+
+TEST(dlfcn, dlsym_handle_global_sym) {
+ // check that we do not look into global group
+ // when looking up symbol by handle
+ void* handle = dlopen("libtest_empty.so", RTLD_NOW);
+ dlopen("libtest_with_dependency.so", RTLD_NOW | RTLD_GLOBAL);
+ void* sym = dlsym(handle, "getRandomNumber");
+ ASSERT_TRUE(sym == nullptr);
+ ASSERT_SUBSTR("undefined symbol: getRandomNumber", dlerror());
+
+ sym = dlsym(handle, "DlSymTestFunction");
+ ASSERT_TRUE(sym == nullptr);
+ ASSERT_SUBSTR("undefined symbol: DlSymTestFunction", dlerror());
dlclose(handle);
}
TEST(dlfcn, dlsym_with_dependencies) {
void* handle = dlopen("libtest_with_dependency.so", RTLD_NOW);
- ASSERT_TRUE(handle != NULL);
+ ASSERT_TRUE(handle != nullptr);
dlerror();
// This symbol is in DT_NEEDED library.
void* sym = dlsym(handle, "getRandomNumber");
- ASSERT_TRUE(sym != NULL);
+ ASSERT_TRUE(sym != nullptr) << dlerror();
int (*fn)(void);
fn = reinterpret_cast<int (*)(void)>(sym);
EXPECT_EQ(4, fn());
@@ -526,6 +598,15 @@ TEST(dlfcn, dlopen_check_rtld_global) {
// RTLD_GLOBAL implies RTLD_NODELETE, let's check that
void* sym_after_dlclose = dlsym(RTLD_DEFAULT, "dlopen_testlib_simple_func");
ASSERT_EQ(sym, sym_after_dlclose);
+
+ // Check if dlsym() for main program's handle searches RTLD_GLOBAL
+ // shared libraries after symbol was not found in the main executable
+ // and dependent libraries.
+ void* handle_for_main_executable = dlopen(nullptr, RTLD_NOW);
+ sym = dlsym(handle_for_main_executable, "dlopen_testlib_simple_func");
+ ASSERT_TRUE(sym != nullptr) << dlerror();
+
+ dlclose(handle_for_main_executable);
}
// libtest_with_dependency_loop.so -> libtest_with_dependency_loop_a.so ->
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 692b7e8..5d25a4c 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -59,7 +59,7 @@ using testing::internal::COLOR_GREEN;
using testing::internal::COLOR_YELLOW;
using testing::internal::ColoredPrintf;
-constexpr int DEFAULT_GLOBAL_TEST_RUN_DEADLINE_MS = 60000;
+constexpr int DEFAULT_GLOBAL_TEST_RUN_DEADLINE_MS = 90000;
constexpr int DEFAULT_GLOBAL_TEST_RUN_WARNLINE_MS = 2000;
// The time each test can run before killed for the reason of timeout.
@@ -839,8 +839,12 @@ static bool RunTestInSeparateProc(int argc, char** argv, std::vector<TestCase>&
return all_tests_passed;
}
-static size_t GetProcessorCount() {
+static size_t GetDefaultJobCount() {
+#if defined(JOB_COUNT_FIXED)
+ return JOB_COUNT_FIXED;
+#else
return static_cast<size_t>(sysconf(_SC_NPROCESSORS_ONLN));
+#endif
}
static void AddPathSeparatorInTestProgramPath(std::vector<char*>& args) {
@@ -950,7 +954,7 @@ static bool PickOptions(std::vector<char*>& args, IsolationTestOptions& options)
}
// Init default isolation test options.
- options.job_count = GetProcessorCount();
+ options.job_count = GetDefaultJobCount();
options.test_deadline_ms = DEFAULT_GLOBAL_TEST_RUN_DEADLINE_MS;
options.test_warnline_ms = DEFAULT_GLOBAL_TEST_RUN_WARNLINE_MS;
options.gtest_color = testing::GTEST_FLAG(color);
diff --git a/tests/libdl_test.cpp b/tests/libdl_test.cpp
new file mode 100644
index 0000000..b162edc
--- /dev/null
+++ b/tests/libdl_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <android/api-level.h>
+
+extern "C" uint32_t android_get_application_target_sdk_version();
+extern "C" void android_set_application_target_sdk_version(uint32_t target);
+
+TEST(libdl, application_sdk_versions_smoke) {
+ // Check initial values
+ ASSERT_EQ(static_cast<uint32_t>(__ANDROID_API__), android_get_application_target_sdk_version());
+
+ android_set_application_target_sdk_version(20U);
+ ASSERT_EQ(20U, android_get_application_target_sdk_version());
+
+ android_set_application_target_sdk_version(22U);
+ ASSERT_EQ(22U, android_get_application_target_sdk_version());
+}
+
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index c432c2e..a5ef622 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -355,10 +355,7 @@ include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
libdl_test_df_1_global_src_files := dl_df_1_global.cpp
libdl_test_df_1_global_ldflags := -Wl,-z,global
-# TODO (dimitry): x86* toolchain does not support -z global - switch to bfd
-ifeq ($(filter $(TARGET_ARCH),x86 x86_64),$(TARGET_ARCH))
-libdl_test_df_1_global_ldflags_target := -fuse-ld=bfd
-endif
+
# TODO (dimitry): host ld.gold does not yet support -z global
# remove this line once it is updated.
libdl_test_df_1_global_ldflags_host := -fuse-ld=bfd
@@ -385,11 +382,34 @@ include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
# Library to check RTLD_LOCAL with dlsym in 'this'
# -----------------------------------------------------------------------------
-libtest_dlsym_from_this_src_files := dlsym_from_this.cpp
+libtest_dlsym_from_this_src_files := dlsym_from_this_symbol.cpp
-module := libtest_dlsym_from_this
libtest_dlsym_from_this_shared_libraries_target := libdl
+libtest_dlsym_from_this_shared_libraries := libtest_dlsym_from_this_child
+
+module := libtest_dlsym_from_this
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# -----------------------------------------------------------------------------
+libtest_dlsym_from_this_child_src_files := dlsym_from_this_functions.cpp
+
+libtest_dlsym_from_this_child_shared_libraries := libtest_dlsym_from_this_grandchild
+
+module := libtest_dlsym_from_this_child
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# -----------------------------------------------------------------------------
+libtest_dlsym_from_this_grandchild_src_files := dlsym_from_this_symbol2.cpp
+
+module := libtest_dlsym_from_this_grandchild
+include $(LOCAL_PATH)/Android.build.testlib.mk
+
+# -----------------------------------------------------------------------------
+# Empty library
+# -----------------------------------------------------------------------------
+libtest_empty_src_files := empty.cpp
+module := libtest_empty
include $(LOCAL_PATH)/Android.build.testlib.mk
# -----------------------------------------------------------------------------
diff --git a/tests/libs/dlsym_from_this_functions.cpp b/tests/libs/dlsym_from_this_functions.cpp
new file mode 100644
index 0000000..1f357e0
--- /dev/null
+++ b/tests/libs/dlsym_from_this_functions.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <dlfcn.h>
+#include <stdio.h>
+
+extern int test_dlsym_symbol;
+
+int test_dlsym_symbol = -1;
+
+extern "C" int* lookup_dlsym_symbol_using_RTLD_DEFAULT() {
+ dlerror();
+ int* result = static_cast<int*>(dlsym(RTLD_DEFAULT, "test_dlsym_symbol"));
+ // TODO: remove this once b/20049306 is fixed
+ if (result == nullptr) {
+ printf("Cannot find the answer\n");
+ }
+ return result;
+}
+
+extern "C" int* lookup_dlsym_symbol2_using_RTLD_DEFAULT() {
+ dlerror();
+ int* result = static_cast<int*>(dlsym(RTLD_DEFAULT, "test_dlsym_symbol2"));
+ // TODO: remove this once b/20049306 is fixed
+ if (result == nullptr) {
+ printf("Cannot find the answer\n");
+ }
+ return result;
+}
+
+extern "C" int* lookup_dlsym_symbol_using_RTLD_NEXT() {
+ dlerror();
+ int* result = static_cast<int*>(dlsym(RTLD_NEXT, "test_dlsym_symbol"));
+ // TODO: remove this once b/20049306 is fixed
+ if (result == nullptr) {
+ printf("Cannot find the answer\n");
+ }
+ return result;
+}
+
diff --git a/tests/libs/dlsym_from_this.cpp b/tests/libs/dlsym_from_this_symbol.cpp
index b5215c9..c3ec255 100644
--- a/tests/libs/dlsym_from_this.cpp
+++ b/tests/libs/dlsym_from_this_symbol.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,18 +13,5 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <dlfcn.h>
-#include <stdio.h>
int test_dlsym_symbol = 42;
-
-extern "C" int* lookup_dlsym_symbol_using_RTLD_DEFAULT() {
- dlerror();
- int* result = static_cast<int*>(dlsym(RTLD_DEFAULT, "test_dlsym_symbol"));
- // TODO: remove this once b/20049306 is fixed
- if (result == nullptr) {
- printf("Cannot find the answer\n");
- }
- return result;
-}
-
diff --git a/tests/libs/dlsym_from_this_symbol2.cpp b/tests/libs/dlsym_from_this_symbol2.cpp
new file mode 100644
index 0000000..20da1d5
--- /dev/null
+++ b/tests/libs/dlsym_from_this_symbol2.cpp
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+int test_dlsym_symbol = 43;
+int test_dlsym_symbol2 = 44;
diff --git a/tests/pthread_dlfcn_test.cpp b/tests/pthread_dlfcn_test.cpp
new file mode 100644
index 0000000..5e8b206
--- /dev/null
+++ b/tests/pthread_dlfcn_test.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <gtest/gtest.h>
+
+#include <dlfcn.h>
+
+static int g_atfork_prepare_calls = 0;
+static void AtForkPrepare1() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 1; }
+static void AtForkPrepare2() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 2; }
+static void AtForkPrepare3() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 3; }
+static void AtForkPrepare4() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 4; }
+
+static int g_atfork_parent_calls = 0;
+static void AtForkParent1() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 1; }
+static void AtForkParent2() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 2; }
+static void AtForkParent3() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 3; }
+static void AtForkParent4() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 4; }
+
+static int g_atfork_child_calls = 0;
+static void AtForkChild1() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 1; }
+static void AtForkChild2() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 2; }
+static void AtForkChild3() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 3; }
+static void AtForkChild4() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 4; }
+
+TEST(pthread, pthread_atfork_with_dlclose) {
+ ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
+
+ void* handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+ typedef int (*fn_t)(void (*)(void), void (*)(void), void (*)(void));
+ fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "proxy_pthread_atfork"));
+ ASSERT_TRUE(fn != nullptr) << dlerror();
+ // the library registers 2 additional atfork handlers in a constructor
+ ASSERT_EQ(0, fn(AtForkPrepare2, AtForkParent2, AtForkChild2));
+ ASSERT_EQ(0, fn(AtForkPrepare3, AtForkParent3, AtForkChild3));
+
+ ASSERT_EQ(0, pthread_atfork(AtForkPrepare4, AtForkParent4, AtForkChild4));
+
+ int pid = fork();
+
+ ASSERT_NE(-1, pid) << strerror(errno);
+
+ if (pid == 0) {
+ ASSERT_EQ(1234, g_atfork_child_calls);
+ _exit(0);
+ }
+
+ ASSERT_EQ(1234, g_atfork_parent_calls);
+ ASSERT_EQ(4321, g_atfork_prepare_calls);
+
+ EXPECT_EQ(0, dlclose(handle));
+ g_atfork_prepare_calls = g_atfork_parent_calls = g_atfork_child_calls = 0;
+
+ int status;
+ ASSERT_EQ(pid, waitpid(pid, &status, 0));
+
+ pid = fork();
+
+ ASSERT_NE(-1, pid) << strerror(errno);
+
+ if (pid == 0) {
+ ASSERT_EQ(14, g_atfork_child_calls);
+ _exit(0);
+ }
+
+ ASSERT_EQ(14, g_atfork_parent_calls);
+ ASSERT_EQ(41, g_atfork_prepare_calls);
+
+ ASSERT_EQ(pid, waitpid(pid, &status, 0));
+}
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index cb5e818..8ae28d8 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -16,7 +16,6 @@
#include <gtest/gtest.h>
-#include <dlfcn.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
@@ -459,42 +458,6 @@ TEST(pthread, pthread_detach__no_such_thread) {
ASSERT_EQ(ESRCH, pthread_detach(dead_thread));
}
-TEST(pthread, pthread_detach_no_leak) {
- size_t initial_bytes = 0;
- // Run this loop more than once since the first loop causes some memory
- // to be allocated permenantly. Run an extra loop to help catch any subtle
- // memory leaks.
- for (size_t loop = 0; loop < 3; loop++) {
- // Set the initial bytes on the second loop since the memory in use
- // should have stabilized.
- if (loop == 1) {
- initial_bytes = mallinfo().uordblks;
- }
-
- pthread_attr_t attr;
- ASSERT_EQ(0, pthread_attr_init(&attr));
- ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE));
-
- std::vector<pthread_t> threads;
- for (size_t i = 0; i < 32; ++i) {
- pthread_t t;
- ASSERT_EQ(0, pthread_create(&t, &attr, IdFn, NULL));
- threads.push_back(t);
- }
-
- sleep(1);
-
- for (size_t i = 0; i < 32; ++i) {
- ASSERT_EQ(0, pthread_detach(threads[i])) << i;
- }
- }
-
- size_t final_bytes = mallinfo().uordblks;
- int leaked_bytes = (final_bytes - initial_bytes);
-
- ASSERT_EQ(0, leaked_bytes);
-}
-
TEST(pthread, pthread_getcpuclockid__clock_gettime) {
SpinFunctionHelper spinhelper;
@@ -1019,62 +982,6 @@ TEST(pthread, pthread_atfork_smoke) {
ASSERT_EQ(pid, waitpid(pid, &status, 0));
}
-static void AtForkPrepare3() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 3; }
-static void AtForkPrepare4() { g_atfork_prepare_calls = (g_atfork_prepare_calls * 10) + 4; }
-
-static void AtForkParent3() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 3; }
-static void AtForkParent4() { g_atfork_parent_calls = (g_atfork_parent_calls * 10) + 4; }
-
-static void AtForkChild3() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 3; }
-static void AtForkChild4() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 4; }
-
-TEST(pthread, pthread_atfork_with_dlclose) {
- ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1));
-
- void* handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL);
- ASSERT_TRUE(handle != nullptr) << dlerror();
- typedef int (*fn_t)(void (*)(void), void (*)(void), void (*)(void));
- fn_t fn = reinterpret_cast<fn_t>(dlsym(handle, "proxy_pthread_atfork"));
- ASSERT_TRUE(fn != nullptr) << dlerror();
- // the library registers 2 additional atfork handlers in a constructor
- ASSERT_EQ(0, fn(AtForkPrepare2, AtForkParent2, AtForkChild2));
- ASSERT_EQ(0, fn(AtForkPrepare3, AtForkParent3, AtForkChild3));
-
- ASSERT_EQ(0, pthread_atfork(AtForkPrepare4, AtForkParent4, AtForkChild4));
-
- int pid = fork();
-
- ASSERT_NE(-1, pid) << strerror(errno);
-
- if (pid == 0) {
- ASSERT_EQ(1234, g_atfork_child_calls);
- _exit(0);
- }
-
- ASSERT_EQ(1234, g_atfork_parent_calls);
- ASSERT_EQ(4321, g_atfork_prepare_calls);
-
- EXPECT_EQ(0, dlclose(handle));
- g_atfork_prepare_calls = g_atfork_parent_calls = g_atfork_child_calls = 0;
-
- int status;
- ASSERT_EQ(pid, waitpid(pid, &status, 0));
-
- pid = fork();
-
- ASSERT_NE(-1, pid) << strerror(errno);
-
- if (pid == 0) {
- ASSERT_EQ(14, g_atfork_child_calls);
- _exit(0);
- }
-
- ASSERT_EQ(14, g_atfork_parent_calls);
- ASSERT_EQ(41, g_atfork_prepare_calls);
-
- ASSERT_EQ(pid, waitpid(pid, &status, 0));
-}
-
TEST(pthread, pthread_attr_getscope) {
pthread_attr_t attr;
ASSERT_EQ(0, pthread_attr_init(&attr));
@@ -1630,3 +1537,37 @@ TEST(pthread, pthread_types_allow_four_bytes_alignment) {
GTEST_LOG_(INFO) << "This test tests bionic implementation details.";
#endif
}
+
+TEST(pthread, pthread_mutex_lock_null_32) {
+#if defined(__BIONIC__) && !defined(__LP64__)
+ ASSERT_EQ(EINVAL, pthread_mutex_lock(NULL));
+#else
+ GTEST_LOG_(INFO) << "This test tests bionic implementation details on 32 bit devices.";
+#endif
+}
+
+TEST(pthread, pthread_mutex_unlock_null_32) {
+#if defined(__BIONIC__) && !defined(__LP64__)
+ ASSERT_EQ(EINVAL, pthread_mutex_unlock(NULL));
+#else
+ GTEST_LOG_(INFO) << "This test tests bionic implementation details on 32 bit devices.";
+#endif
+}
+
+TEST_F(pthread_DeathTest, pthread_mutex_lock_null_64) {
+#if defined(__BIONIC__) && defined(__LP64__)
+ pthread_mutex_t* null_value = nullptr;
+ ASSERT_EXIT(pthread_mutex_lock(null_value), testing::KilledBySignal(SIGSEGV), "");
+#else
+ GTEST_LOG_(INFO) << "This test tests bionic implementation details on 64 bit devices.";
+#endif
+}
+
+TEST_F(pthread_DeathTest, pthread_mutex_unlock_null_64) {
+#if defined(__BIONIC__) && defined(__LP64__)
+ pthread_mutex_t* null_value = nullptr;
+ ASSERT_EXIT(pthread_mutex_unlock(null_value), testing::KilledBySignal(SIGSEGV), "");
+#else
+ GTEST_LOG_(INFO) << "This test tests bionic implementation details on 64 bit devices.";
+#endif
+}
diff --git a/tests/sys_personality_test.cpp b/tests/sys_personality_test.cpp
index 55a023d..2dfaa65 100644
--- a/tests/sys_personality_test.cpp
+++ b/tests/sys_personality_test.cpp
@@ -19,7 +19,7 @@
#include <sys/personality.h>
TEST(sys_personality, current_persona) {
- int persona = personality(0xffffffff);
+ int persona = personality(0xffffffff) & PER_MASK;
#if defined(__BIONIC__)
#if defined(__LP64__)
ASSERT_EQ(PER_LINUX, persona);
diff --git a/tests/sys_procfs_test.cpp b/tests/sys_procfs_test.cpp
new file mode 100644
index 0000000..8054869
--- /dev/null
+++ b/tests/sys_procfs_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/procfs.h>
+
+TEST(sys_procfs, smoke) {
+ elf_greg_t reg;
+ memset(&reg, 0, sizeof(reg));
+
+ elf_gregset_t regs;
+ memset(&regs, 0, sizeof(regs));
+
+ elf_fpregset_t fp_regs;
+ memset(&fp_regs, 0, sizeof(fp_regs));
+
+ prgregset_t pr_g_regs;
+ memset(&pr_g_regs, 0, sizeof(pr_g_regs));
+
+ prfpregset_t pr_fp_regs;
+ memset(&pr_fp_regs, 0, sizeof(pr_fp_regs));
+
+ static_assert(sizeof(prgregset_t) == sizeof(elf_gregset_t), "");
+ static_assert(sizeof(prfpregset_t) == sizeof(elf_fpregset_t), "");
+}
diff --git a/tests/sys_uio_test.cpp b/tests/sys_uio_test.cpp
new file mode 100644
index 0000000..c7af8a7
--- /dev/null
+++ b/tests/sys_uio_test.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/uio.h>
+
+TEST(sys_uio, process_vm_readv_ESRCH) {
+ ASSERT_EQ(0, process_vm_readv(0, nullptr, 0, nullptr, 0, 0));
+}
+
+TEST(sys_uio, process_vm_writev_ESRCH) {
+ ASSERT_EQ(0, process_vm_writev(0, nullptr, 0, nullptr, 0, 0));
+}
diff --git a/tests/sys_xattr_test.cpp b/tests/sys_xattr_test.cpp
new file mode 100644
index 0000000..1842682
--- /dev/null
+++ b/tests/sys_xattr_test.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <sys/types.h>
+#include <sys/xattr.h>
+
+#include "TemporaryFile.h"
+
+TEST(sys_xattr, setxattr) {
+ TemporaryFile tf;
+ char buf[10];
+ ASSERT_EQ(0, setxattr(tf.filename, "user.foo", "bar", 4, 0));
+ ASSERT_EQ(4, getxattr(tf.filename, "user.foo", buf, sizeof(buf)));
+ ASSERT_STREQ("bar", buf);
+ buf[0] = '\0';
+ ASSERT_EQ(4, lgetxattr(tf.filename, "user.foo", buf, sizeof(buf)));
+ ASSERT_STREQ("bar", buf);
+}
+
+TEST(sys_xattr, fsetxattr) {
+ TemporaryFile tf;
+ char buf[10];
+ ASSERT_EQ(0, fsetxattr(tf.fd, "user.foo", "bar", 4, 0));
+ ASSERT_EQ(4, fgetxattr(tf.fd, "user.foo", buf, sizeof(buf)));
+ ASSERT_STREQ("bar", buf);
+}
+
+TEST(sys_xattr, fsetxattr_zerobuf) {
+ TemporaryFile tf;
+ char buf[10];
+ ASSERT_EQ(0, fsetxattr(tf.fd, "user.foo", "", 0, 0));
+ ASSERT_EQ(0, fgetxattr(tf.fd, "user.foo", buf, sizeof(buf)));
+}
+
+TEST(sys_xattr, fsetxattr_toosmallbuf) {
+ TemporaryFile tf;
+ char buf[10];
+ ASSERT_EQ(0, fsetxattr(tf.fd, "user.foo", "01234567890123456789", 21, 0));
+ ASSERT_EQ(-1, fgetxattr(tf.fd, "user.foo", buf, sizeof(buf)));
+ ASSERT_EQ(ERANGE, errno);
+}
+
+TEST(sys_xattr, fsetxattr_invalidfd) {
+ char buf[10];
+ errno = 0;
+ ASSERT_EQ(-1, fsetxattr(65535, "user.foo", "0123", 5, 0));
+ ASSERT_EQ(EBADF, errno);
+ errno = 0;
+ ASSERT_EQ(-1, fgetxattr(65535, "user.foo", buf, sizeof(buf)));
+ ASSERT_EQ(EBADF, errno);
+}
+
+TEST(sys_xattr, fsetxattr_with_opath) {
+ TemporaryFile tf;
+ int fd = open(tf.filename, O_PATH);
+ ASSERT_NE(-1, fd);
+
+ int res = fsetxattr(fd, "user.foo", "bar", 4, 0);
+#if defined(__BIONIC__)
+ char buf[10];
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(4, fgetxattr(fd, "user.foo", buf, sizeof(buf)));
+ ASSERT_STREQ("bar", buf);
+#else
+ ASSERT_EQ(-1, res);
+ ASSERT_EQ(EBADF, errno);
+#endif
+}
+
+TEST(sys_xattr, fsetxattr_with_opath_toosmall) {
+ TemporaryFile tf;
+ int fd = open(tf.filename, O_PATH);
+ ASSERT_NE(-1, fd);
+
+ int res = fsetxattr(fd, "user.foo", "01234567890123456789", 21, 0);
+#if defined(__BIONIC__)
+ char buf[10];
+ ASSERT_EQ(0, res);
+ ASSERT_EQ(-1, fgetxattr(fd, "user.foo", buf, sizeof(buf)));
+ ASSERT_EQ(ERANGE, errno);
+#else
+ ASSERT_EQ(-1, res);
+ ASSERT_EQ(EBADF, errno);
+#endif
+}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index f54a461..79c16d7 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -176,6 +176,13 @@ TEST(unistd, ftruncate64) {
ASSERT_EQ(123, sb.st_size);
}
+TEST(unistd, ftruncate_negative) {
+ TemporaryFile tf;
+ errno = 0;
+ ASSERT_EQ(-1, ftruncate(tf.fd, -123));
+ ASSERT_EQ(EINVAL, errno);
+}
+
static bool g_pause_test_flag = false;
static void PauseTestSignalHandler(int) {
g_pause_test_flag = true;
diff --git a/tools/relocation_packer/Android.mk b/tools/relocation_packer/Android.mk
index 75dba71..4e2fd97 100644
--- a/tools/relocation_packer/Android.mk
+++ b/tools/relocation_packer/Android.mk
@@ -14,6 +14,7 @@
# limitations under the License.
#
+ifeq ($(HOST_OS),linux)
common_cppflags := -Wall -Wextra -Wunused -Werror -Wold-style-cast
LOCAL_PATH := $(call my-dir)
@@ -95,3 +96,5 @@ $(eval $(call copy-test-library,elf_file_unittest_relocs_arm32.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_arm32_packed.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_arm64.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_arm64_packed.so))
+
+endif
diff --git a/tools/relocation_packer/src/elf_file.cc b/tools/relocation_packer/src/elf_file.cc
index c8ddde6..102d614 100644
--- a/tools/relocation_packer/src/elf_file.cc
+++ b/tools/relocation_packer/src/elf_file.cc
@@ -37,11 +37,13 @@ static constexpr int32_t DT_ANDROID_RELASZ = DT_LOOS + 5;
static constexpr uint32_t SHT_ANDROID_REL = SHT_LOOS + 1;
static constexpr uint32_t SHT_ANDROID_RELA = SHT_LOOS + 2;
+static const size_t kPageSize = 4096;
+
// Alignment to preserve, in bytes. This must be at least as large as the
// largest d_align and sh_addralign values found in the loaded file.
// Out of caution for RELRO page alignment, we preserve to a complete target
// page. See http://www.airs.com/blog/archives/189.
-static constexpr size_t kPreserveAlignment = 4096;
+static const size_t kPreserveAlignment = kPageSize;
// Get section data. Checks that the section has exactly one data entry,
// so that the section size and the data size are the same. True in
@@ -310,6 +312,13 @@ static void AdjustProgramHeaderOffsets(typename ELF::Phdr* program_headers,
for (size_t i = 0; i < count; ++i) {
typename ELF::Phdr* program_header = &program_headers[i];
+ // Do not adjust PT_GNU_STACK - it confuses gdb and results
+ // in incorrect unwinding if the executable is stripped after
+ // packing.
+ if (program_header->p_type == PT_GNU_STACK) {
+ continue;
+ }
+
if (program_header->p_offset > hole_start) {
// The hole start is past this segment, so adjust offset.
program_header->p_offset += hole_size;
@@ -318,9 +327,13 @@ static void AdjustProgramHeaderOffsets(typename ELF::Phdr* program_headers,
} else {
program_header->p_vaddr -= hole_size;
program_header->p_paddr -= hole_size;
+ if (program_header->p_align > kPageSize) {
+ program_header->p_align = kPageSize;
+ }
VLOG(1) << "phdr[" << i
<< "] p_vaddr adjusted to "<< program_header->p_vaddr
- << "; p_paddr adjusted to "<< program_header->p_paddr;
+ << "; p_paddr adjusted to "<< program_header->p_paddr
+ << "; p_align adjusted to "<< program_header->p_align;
}
}
}
@@ -466,6 +479,16 @@ void ElfFile<ELF>::AdjustDynamicSectionForHole(Elf_Scn* dynamic_section,
<< " d_val adjusted to " << dynamic->d_un.d_val;
}
+ // Special case: DT_MIPS_RLD_MAP2 stores the difference between dynamic
+ // entry address and the address of the _r_debug (used by GDB)
+ // since the dynamic section and target address are on the
+ // different sides of the hole it needs to be adjusted accordingly
+ if (tag == DT_MIPS_RLD_MAP2) {
+ dynamic->d_un.d_val += hole_size;
+ VLOG(1) << "dynamic[" << i << "] " << dynamic->d_tag
+ << " d_val adjusted to " << dynamic->d_un.d_val;
+ }
+
// Ignore DT_RELCOUNT and DT_RELACOUNT: (1) nobody uses them and
// technically (2) the relative relocation count is not changed.
diff --git a/tools/relocation_packer/src/elf_traits.h b/tools/relocation_packer/src/elf_traits.h
index 41b06c8..1c938fa 100644
--- a/tools/relocation_packer/src/elf_traits.h
+++ b/tools/relocation_packer/src/elf_traits.h
@@ -10,6 +10,10 @@
#include "elf.h"
#include "libelf.h"
+#if !defined(DT_MIPS_RLD_MAP2)
+#define DT_MIPS_RLD_MAP2 0x70000035
+#endif
+
// ELF is a traits structure used to provide convenient aliases for
// 32/64 bit Elf types and functions, depending on the target file.
diff --git a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so
index a2b0039..ed85ce1 100755
--- a/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so
+++ b/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so
Binary files differ