diff options
150 files changed, 5824 insertions, 3097 deletions
diff --git a/libc/Android.mk b/libc/Android.mk index 2c33a8f..b50717d 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 \ @@ -546,14 +549,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 += \ @@ -941,13 +946,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 @@ -960,6 +958,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) @@ -975,13 +974,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 @@ -994,7 +986,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) @@ -1030,13 +1022,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) @@ -1355,12 +1340,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 @@ -1380,16 +1368,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)) @@ -1519,7 +1507,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 Binary files differindex 3661b68..f22464e 100644 --- a/libc/zoneinfo/tzdata +++ b/libc/zoneinfo/tzdata 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(®, 0, sizeof(reg)); + + elf_gregset_t regs; + memset(®s, 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 Binary files differindex 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 |