Compare commits
120 Commits
android-m-
...
android-m-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a9732d663 | ||
|
|
7ea817d39e | ||
|
|
89bbb846b9 | ||
|
|
dbb17b2831 | ||
|
|
f542b30970 | ||
|
|
eeb6b57e75 | ||
|
|
77455f85ab | ||
|
|
86061f39c2 | ||
|
|
416695a75c | ||
|
|
c2247478d5 | ||
|
|
b9f76dc829 | ||
|
|
7f46cf9a5f | ||
|
|
83474cd387 | ||
|
|
7271caf93d | ||
|
|
46d24d12e1 | ||
|
|
25da2d7ca2 | ||
|
|
59d5854d14 | ||
|
|
71107cdd02 | ||
|
|
a05bee544a | ||
|
|
01e37c9665 | ||
|
|
eeb9f5e416 | ||
|
|
3f987f5b3e | ||
|
|
56f40fbb82 | ||
|
|
d19c271599 | ||
|
|
6589febec2 | ||
|
|
fef58353f4 | ||
|
|
bc425c73e0 | ||
|
|
c666838ad6 | ||
|
|
cc83890464 | ||
|
|
d807b9a12d | ||
|
|
e79d06b0e8 | ||
|
|
af6ee5b5bc | ||
|
|
aff18fd608 | ||
|
|
7d09a8cd11 | ||
|
|
a8993c994e | ||
|
|
e4ad91f86a | ||
|
|
13cee57dee | ||
|
|
de4e27e231 | ||
|
|
6a5ead6990 | ||
|
|
d02ec08427 | ||
|
|
6cc98af72b | ||
|
|
d1ade7ce02 | ||
|
|
547fa54e6d | ||
|
|
a9703332f6 | ||
|
|
bfa601a999 | ||
|
|
9ae6f794ca | ||
|
|
d2c81ed000 | ||
|
|
f448ef491c | ||
|
|
61cbd02f10 | ||
|
|
455c145e3c | ||
|
|
3b5a4b0c33 | ||
|
|
dee130f598 | ||
|
|
38f2eaa07b | ||
|
|
81b2382df6 | ||
|
|
895241efbb | ||
|
|
b628b7db39 | ||
|
|
11ea08c5cb | ||
|
|
9876aa273d | ||
|
|
48fa28bacd | ||
|
|
cd1be3b69e | ||
|
|
665607a6b7 | ||
|
|
a73b2c961f | ||
|
|
b1304935b6 | ||
|
|
636f5ddddc | ||
|
|
df11f340ca | ||
|
|
0577733c2e | ||
|
|
27f5c37b12 | ||
|
|
333bdad361 | ||
|
|
469b418784 | ||
|
|
bf18c61798 | ||
|
|
713ae464ab | ||
|
|
402a75060d | ||
|
|
9ef26a3c4c | ||
|
|
173ad0a53e | ||
|
|
b90e9b7183 | ||
|
|
175dae92d7 | ||
|
|
c910de9d5e | ||
|
|
be57a40d29 | ||
|
|
db68b4600d | ||
|
|
bd3b961186 | ||
|
|
72af1235e4 | ||
|
|
6865082ca6 | ||
|
|
ba1d40a3f1 | ||
|
|
f3463db7eb | ||
|
|
6a494915d7 | ||
|
|
60907c7f4e | ||
|
|
1801db3d3f | ||
|
|
1cfbd94a2f | ||
|
|
8a11628355 | ||
|
|
866d6fb090 | ||
|
|
4900f1c4cd | ||
|
|
624b8f17a1 | ||
|
|
12fb28bbd8 | ||
|
|
d9dc13d417 | ||
|
|
e1d0810cd7 | ||
|
|
f9554a1776 | ||
|
|
966f84b11d | ||
|
|
19fee2ca8b | ||
|
|
12ca831b0e | ||
|
|
9cf6fc304b | ||
|
|
b68b8b4b95 | ||
|
|
c062218a9b | ||
|
|
5cce2e7205 | ||
|
|
6cda074289 | ||
|
|
3931b6d9b3 | ||
|
|
1913352c6b | ||
|
|
11b15b23aa | ||
|
|
75108f4f83 | ||
|
|
ef55f96723 | ||
|
|
e7deb145c6 | ||
|
|
2825f10b7f | ||
|
|
f439b5a318 | ||
|
|
ef607cdae2 | ||
|
|
9d476a02e9 | ||
|
|
d70891687d | ||
|
|
5511551009 | ||
|
|
6c2dba8651 | ||
|
|
d974e88046 | ||
|
|
087005f37e | ||
|
|
3cec6eca92 |
@@ -129,8 +129,11 @@ libc_bionic_ndk_src_files := \
|
||||
bionic/fchmod.cpp \
|
||||
bionic/fchmodat.cpp \
|
||||
bionic/ffs.cpp \
|
||||
bionic/fgetxattr.cpp \
|
||||
bionic/flistxattr.cpp \
|
||||
bionic/flockfile.cpp \
|
||||
bionic/fpclassify.cpp \
|
||||
bionic/fsetxattr.cpp \
|
||||
bionic/ftruncate.cpp \
|
||||
bionic/futimens.cpp \
|
||||
bionic/getcwd.cpp \
|
||||
@@ -547,14 +550,16 @@ libc_thread_atexit_impl_src_files := \
|
||||
libc_arch_static_src_files := \
|
||||
bionic/dl_iterate_phdr_static.cpp \
|
||||
|
||||
# Various kinds of LP32 cruft.
|
||||
# Various kinds of cruft.
|
||||
# ========================================================
|
||||
libc_bionic_src_files_32 += \
|
||||
libc_common_src_files += \
|
||||
bionic/ndk_cruft.cpp \
|
||||
|
||||
libc_bionic_ndk_src_files_32 += \
|
||||
bionic/mmap.cpp \
|
||||
|
||||
libc_common_src_files_32 += \
|
||||
bionic/legacy_32_bit_support.cpp \
|
||||
bionic/ndk_cruft.cpp \
|
||||
bionic/time64.c \
|
||||
|
||||
libc_netbsd_src_files_32 += \
|
||||
@@ -575,6 +580,13 @@ libc_common_cflags += -DTARGET_USES_LOGD
|
||||
endif
|
||||
|
||||
use_clang := $(USE_CLANG_PLATFORM_BUILD)
|
||||
|
||||
# Clang/llvm has incompatible long double (fp128) for x86_64.
|
||||
# https://llvm.org/bugs/show_bug.cgi?id=23897
|
||||
ifeq ($(TARGET_ARCH),x86_64)
|
||||
use_clang := false
|
||||
endif
|
||||
|
||||
ifeq ($(use_clang),)
|
||||
use_clang := false
|
||||
endif
|
||||
@@ -653,7 +665,7 @@ LOCAL_CLANG := $(use_clang)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -694,7 +706,7 @@ LOCAL_CLANG := $(use_clang)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -740,7 +752,7 @@ LOCAL_CLANG := $(use_clang)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -773,7 +785,7 @@ LOCAL_CLANG := $(use_clang)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -808,7 +820,7 @@ LOCAL_CLANG := $(use_clang)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -849,7 +861,7 @@ LOCAL_MODULE := libc_openbsd_ndk
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -887,7 +899,7 @@ LOCAL_MODULE := libc_openbsd
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -925,7 +937,7 @@ LOCAL_MODULE := libc_gdtoa
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -950,10 +962,11 @@ LOCAL_CLANG := $(use_clang)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
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)
|
||||
|
||||
|
||||
@@ -977,11 +990,11 @@ LOCAL_CLANG := $(use_clang)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
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)
|
||||
@@ -998,7 +1011,7 @@ LOCAL_CLANG := false
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -1025,7 +1038,7 @@ LOCAL_CLANG := $(use_clang)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -1049,7 +1062,7 @@ LOCAL_CLANG := true # GCC refuses to hide new/delete
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
# b/17574078: Need to disable coverage until we have a prebuilt libprofile_rt.
|
||||
# Since this is a static library built with clang, it needs to link
|
||||
# libprofile_rt when it is linked into the final binary. Since the final binary
|
||||
@@ -1077,7 +1090,7 @@ LOCAL_CLANG := $(use_clang)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -1099,7 +1112,7 @@ LOCAL_CFLAGS := $(libc_common_cflags) -fno-builtin
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -1125,7 +1138,7 @@ LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
|
||||
LOCAL_CFLAGS := $(libc_common_cflags) -fvisibility=hidden -O0
|
||||
LOCAL_CPPFLAGS := $(libc_common_cppflags)
|
||||
LOCAL_C_INCLUDES := $(libc_common_c_includes)
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
|
||||
@@ -1209,7 +1222,7 @@ LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
|
||||
# TODO: split out the asflags.
|
||||
LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -1247,7 +1260,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := libc_common
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -1270,7 +1283,7 @@ LOCAL_C_INCLUDES := $(libc_common_c_includes)
|
||||
LOCAL_MODULE := libc_malloc
|
||||
LOCAL_CLANG := $(use_clang)
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -1303,7 +1316,7 @@ endif
|
||||
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -1335,7 +1348,7 @@ 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.
|
||||
@@ -1363,7 +1376,7 @@ 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
|
||||
@@ -1385,7 +1398,7 @@ LOCAL_CFLAGS_arm += -DCRT_LEGACY_WORKAROUND
|
||||
LOCAL_SRC_FILES_arm += \
|
||||
arch-arm/bionic/atexit_legacy.c
|
||||
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
@@ -1439,7 +1452,7 @@ LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
|
||||
|
||||
# Don't install on release build
|
||||
LOCAL_MODULE_TAGS := eng debug
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -1479,7 +1492,7 @@ LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/version_script.txt
|
||||
|
||||
# Don't install on release build
|
||||
LOCAL_MODULE_TAGS := eng debug
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
|
||||
$(eval $(call patch-up-arch-specific-flags,LOCAL_CFLAGS,libc_common_cflags))
|
||||
@@ -1510,7 +1523,7 @@ LOCAL_MODULE:= libstdc++
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES := libc
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
@@ -1526,7 +1539,7 @@ LOCAL_MODULE:= libstdc++
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||
LOCAL_CXX_STL := none
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES := libc
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
|
||||
@@ -122,9 +122,9 @@ 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
|
||||
ssize_t flistxattr(int, char*, 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:flistxattr(int, char*, size_t) all
|
||||
int fremovexattr(int, const char*) all
|
||||
|
||||
int __getdents64:getdents64(unsigned int, struct dirent*, unsigned int) arm,arm64,mips,mips64,x86,x86_64
|
||||
@@ -203,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
|
||||
@@ -308,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
|
||||
|
||||
1
libc/arch-arm/cortex-a53/cortex-a53.mk
Normal file
1
libc/arch-arm/cortex-a53/cortex-a53.mk
Normal file
@@ -0,0 +1 @@
|
||||
include bionic/libc/arch-arm/cortex-a7/cortex-a7.mk
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(flistxattr)
|
||||
ENTRY(___flistxattr)
|
||||
mov ip, r7
|
||||
ldr r7, =__NR_flistxattr
|
||||
swi #0
|
||||
@@ -11,4 +11,5 @@ ENTRY(flistxattr)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(flistxattr)
|
||||
END(___flistxattr)
|
||||
.hidden ___flistxattr
|
||||
@@ -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
|
||||
22
libc/arch-arm/syscalls/process_vm_readv.S
Normal file
22
libc/arch-arm/syscalls/process_vm_readv.S
Normal file
@@ -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)
|
||||
22
libc/arch-arm/syscalls/process_vm_writev.S
Normal file
22
libc/arch-arm/syscalls/process_vm_writev.S
Normal file
@@ -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)
|
||||
1
libc/arch-arm64/cortex-a53/cortex-a53.mk
Normal file
1
libc/arch-arm64/cortex-a53/cortex-a53.mk
Normal file
@@ -0,0 +1 @@
|
||||
include bionic/libc/arch-arm64/generic/generic.mk
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(flistxattr)
|
||||
ENTRY(___flistxattr)
|
||||
mov x8, __NR_flistxattr
|
||||
svc #0
|
||||
|
||||
@@ -11,4 +11,5 @@ ENTRY(flistxattr)
|
||||
b.hi __set_errno_internal
|
||||
|
||||
ret
|
||||
END(flistxattr)
|
||||
END(___flistxattr)
|
||||
.hidden ___flistxattr
|
||||
@@ -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
|
||||
14
libc/arch-arm64/syscalls/process_vm_readv.S
Normal file
14
libc/arch-arm64/syscalls/process_vm_readv.S
Normal file
@@ -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)
|
||||
14
libc/arch-arm64/syscalls/process_vm_writev.S
Normal file
14
libc/arch-arm64/syscalls/process_vm_writev.S
Normal file
@@ -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)
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
@@ -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"
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* 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 #
|
||||
#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
|
||||
#define DBG
|
||||
# include <regdef.h>
|
||||
# include <sys/asm.h>
|
||||
#endif
|
||||
|
||||
LEAF(memset,0)
|
||||
/* 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
|
||||
|
||||
#ifndef USE_DOUBLE
|
||||
# ifndef DISABLE_DOUBLE_ALIGN
|
||||
# define DOUBLE_ALIGN
|
||||
# endif
|
||||
#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
|
||||
|
||||
/* 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
|
||||
|
||||
/* 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
|
||||
|
||||
#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
|
||||
|
||||
/* 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. */
|
||||
|
||||
#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
|
||||
|
||||
/* 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(MEMSET_NAME,0)
|
||||
#else
|
||||
LEAF(MEMSET_NAME)
|
||||
#endif
|
||||
|
||||
.set nomips16
|
||||
.set noreorder
|
||||
.set noat
|
||||
/* 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
|
||||
|
||||
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
|
||||
/* 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
|
||||
|
||||
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.
|
||||
/* 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
|
||||
and a1,0xff
|
||||
sll AT,a1,8
|
||||
or a1,AT
|
||||
sll AT,a1,16
|
||||
or a1,AT
|
||||
# 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
|
||||
|
||||
.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
|
||||
/* 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)
|
||||
|
||||
# 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
|
||||
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)
|
||||
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
|
||||
PTR_ADDU a0,a0,t2
|
||||
L(double_aligned):
|
||||
#endif
|
||||
|
||||
.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
|
||||
/* 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 */
|
||||
|
||||
# copying in words (4-byte chunks)
|
||||
.LwordCopy_loop:
|
||||
addiu a0,a0,4
|
||||
bne a0,a3,.LwordCopy_loop
|
||||
sw a1,-4(a0)
|
||||
/* 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
|
||||
|
||||
# store last 0-3 bytes
|
||||
# this will repeat the last store if the memset finishes on a word boundary
|
||||
.Llast4aligned:
|
||||
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
|
||||
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
|
||||
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)
|
||||
|
||||
/* 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
|
||||
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
|
||||
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
|
||||
|
||||
260
libc/arch-mips/string/strcmp.S
Normal file
260
libc/arch-mips/string/strcmp.S
Normal file
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(flistxattr)
|
||||
ENTRY(___flistxattr)
|
||||
.set noreorder
|
||||
.cpload t9
|
||||
li v0, __NR_flistxattr
|
||||
@@ -16,4 +16,5 @@ ENTRY(flistxattr)
|
||||
j t9
|
||||
nop
|
||||
.set reorder
|
||||
END(flistxattr)
|
||||
END(___flistxattr)
|
||||
.hidden ___flistxattr
|
||||
@@ -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
|
||||
19
libc/arch-mips/syscalls/process_vm_readv.S
Normal file
19
libc/arch-mips/syscalls/process_vm_readv.S
Normal file
@@ -0,0 +1,19 @@
|
||||
/* Generated by gensyscalls.py. Do not edit. */
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(process_vm_readv)
|
||||
.set noreorder
|
||||
.cpload t9
|
||||
li v0, __NR_process_vm_readv
|
||||
syscall
|
||||
bnez a3, 1f
|
||||
move a0, v0
|
||||
j ra
|
||||
nop
|
||||
1:
|
||||
la t9,__set_errno_internal
|
||||
j t9
|
||||
nop
|
||||
.set reorder
|
||||
END(process_vm_readv)
|
||||
19
libc/arch-mips/syscalls/process_vm_writev.S
Normal file
19
libc/arch-mips/syscalls/process_vm_writev.S
Normal file
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
************************************************************************/
|
||||
@@ -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
|
||||
************************************************************************/
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(flistxattr)
|
||||
ENTRY(___flistxattr)
|
||||
.set push
|
||||
.set noreorder
|
||||
li v0, __NR_flistxattr
|
||||
@@ -22,4 +22,5 @@ ENTRY(flistxattr)
|
||||
j t9
|
||||
move ra, t0
|
||||
.set pop
|
||||
END(flistxattr)
|
||||
END(___flistxattr)
|
||||
.hidden ___flistxattr
|
||||
@@ -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
|
||||
25
libc/arch-mips64/syscalls/process_vm_readv.S
Normal file
25
libc/arch-mips64/syscalls/process_vm_readv.S
Normal file
@@ -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)
|
||||
25
libc/arch-mips64/syscalls/process_vm_writev.S
Normal file
25
libc/arch-mips64/syscalls/process_vm_writev.S
Normal file
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(flistxattr)
|
||||
ENTRY(___flistxattr)
|
||||
pushl %ebx
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_rel_offset ebx, 0
|
||||
@@ -28,4 +28,5 @@ ENTRY(flistxattr)
|
||||
popl %ecx
|
||||
popl %ebx
|
||||
ret
|
||||
END(flistxattr)
|
||||
END(___flistxattr)
|
||||
.hidden ___flistxattr
|
||||
@@ -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
|
||||
46
libc/arch-x86/syscalls/process_vm_readv.S
Normal file
46
libc/arch-x86/syscalls/process_vm_readv.S
Normal file
@@ -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)
|
||||
46
libc/arch-x86/syscalls/process_vm_writev.S
Normal file
46
libc/arch-x86/syscalls/process_vm_writev.S
Normal file
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <private/bionic_asm.h>
|
||||
|
||||
ENTRY(flistxattr)
|
||||
ENTRY(___flistxattr)
|
||||
movl $__NR_flistxattr, %eax
|
||||
syscall
|
||||
cmpq $-MAX_ERRNO, %rax
|
||||
@@ -12,4 +12,5 @@ ENTRY(flistxattr)
|
||||
call __set_errno_internal
|
||||
1:
|
||||
ret
|
||||
END(flistxattr)
|
||||
END(___flistxattr)
|
||||
.hidden ___flistxattr
|
||||
@@ -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
|
||||
16
libc/arch-x86_64/syscalls/process_vm_readv.S
Normal file
16
libc/arch-x86_64/syscalls/process_vm_readv.S
Normal file
@@ -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)
|
||||
16
libc/arch-x86_64/syscalls/process_vm_writev.S
Normal file
16
libc/arch-x86_64/syscalls/process_vm_writev.S
Normal file
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
59
libc/bionic/fgetxattr.cpp
Normal file
59
libc/bionic/fgetxattr.cpp
Normal file
@@ -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" ssize_t ___fgetxattr(int, const char*, void*, size_t);
|
||||
|
||||
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);
|
||||
|
||||
if ((result != -1) || (errno != EBADF)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
char buf[40];
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
||||
errno = saved_errno;
|
||||
return getxattr(buf, name, value, size);
|
||||
}
|
||||
@@ -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 ___flistxattr(int, char*, size_t);
|
||||
|
||||
// Call this function before any of the other functions in this header file.
|
||||
extern void linker_env_init(KernelArgumentBlock& args);
|
||||
ssize_t flistxattr(int fd, char *list, size_t size) {
|
||||
int saved_errno = errno;
|
||||
ssize_t result = ___flistxattr(fd, list, 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 listxattr(buf, list, size);
|
||||
}
|
||||
59
libc/bionic/fsetxattr.cpp
Normal file
59
libc/bionic/fsetxattr.cpp
Normal file
@@ -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);
|
||||
}
|
||||
@@ -18,11 +18,14 @@
|
||||
#include <sys/cdefs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(__USE_FILE_OFFSET64) && !defined(__LP64__)
|
||||
#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
|
||||
#endif // !defined(__LP64__)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -87,6 +87,7 @@ void __init_alternate_signal_stack(pthread_internal_t* thread) {
|
||||
// We can only use const static allocated string for mapped region name, as Android kernel
|
||||
// uses the string pointer directly when dumping /proc/pid/maps.
|
||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ss.ss_sp, ss.ss_size, "thread signal stack");
|
||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, stack_base, PAGE_SIZE, "thread signal stack guard page");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +141,7 @@ static void* __create_thread_mapped_space(size_t mmap_size, size_t stack_guard_s
|
||||
munmap(space, mmap_size);
|
||||
return NULL;
|
||||
}
|
||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, space, stack_guard_size, "thread stack guard page");
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
@@ -359,29 +360,6 @@ str2number(const char *p)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -588,6 +566,21 @@ getaddrinfo(const char *hostname, const char *servname,
|
||||
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;
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -176,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));
|
||||
|
||||
|
||||
@@ -520,6 +520,11 @@
|
||||
#include <android/api-level.h>
|
||||
|
||||
/* glibc compatibility. */
|
||||
#if __POSIX_VISIBLE >= 200809
|
||||
#define __USE_ISOC99 1
|
||||
#define __USE_XOPEN2K 1
|
||||
#define __USE_XOPEN2K8 1
|
||||
#endif
|
||||
#if __LP64__
|
||||
#define __WORDSIZE 64
|
||||
#else
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern int personality (unsigned long persona);
|
||||
extern int personality (unsigned int persona);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
||||
@@ -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,30 @@
|
||||
* 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;
|
||||
#ifndef _SYS_PROCFS_H_
|
||||
#define _SYS_PROCFS_H_
|
||||
|
||||
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;
|
||||
}
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
return dst;
|
||||
}
|
||||
__BEGIN_DECLS
|
||||
|
||||
typedef unsigned long elf_greg_t;
|
||||
typedef elf_greg_t elf_gregset_t[NGREG];
|
||||
|
||||
typedef fpregset_t elf_fpregset_t;
|
||||
|
||||
#if defined(__i386__)
|
||||
typedef struct user_fpxregs_struct elf_fpxregset_t;
|
||||
#endif
|
||||
|
||||
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_ */
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ struct user_fpregs_struct {
|
||||
long fos;
|
||||
long st_space[20];
|
||||
};
|
||||
struct user_fxsr_struct {
|
||||
struct user_fpxregs_struct {
|
||||
unsigned short cwd;
|
||||
unsigned short swd;
|
||||
unsigned short twd;
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
119
libc/include/sysexits.h
Normal file
119
libc/include/sysexits.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/* $OpenBSD: sysexits.h,v 1.5 2003/06/02 19:34:12 millert Exp $ */
|
||||
/* $NetBSD: sysexits.h,v 1.4 1994/10/26 00:56:33 cgd Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1987 Regents of the University of California.
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* @(#)sysexits.h 4.8 (Berkeley) 4/3/91
|
||||
*/
|
||||
|
||||
#ifndef _SYSEXITS_H_
|
||||
#define _SYSEXITS_H_
|
||||
|
||||
/*
|
||||
* SYSEXITS.H -- Exit status codes for system programs.
|
||||
*
|
||||
* This include file attempts to categorize possible error
|
||||
* exit statuses for system programs, notably delivermail
|
||||
* and the Berkeley network.
|
||||
*
|
||||
* Error numbers begin at EX__BASE to reduce the possibility of
|
||||
* clashing with other exit statuses that random programs may
|
||||
* already return. The meaning of the codes is approximately
|
||||
* as follows:
|
||||
*
|
||||
* EX_USAGE -- The command was used incorrectly, e.g., with
|
||||
* the wrong number of arguments, a bad flag, a bad
|
||||
* syntax in a parameter, or whatever.
|
||||
* EX_DATAERR -- The input data was incorrect in some way.
|
||||
* This should only be used for user's data & not
|
||||
* system files.
|
||||
* EX_NOINPUT -- An input file (not a system file) did not
|
||||
* exist or was not readable. This could also include
|
||||
* errors like "No message" to a mailer (if it cared
|
||||
* to catch it).
|
||||
* EX_NOUSER -- The user specified did not exist. This might
|
||||
* be used for mail addresses or remote logins.
|
||||
* EX_NOHOST -- The host specified did not exist. This is used
|
||||
* in mail addresses or network requests.
|
||||
* EX_UNAVAILABLE -- A service is unavailable. This can occur
|
||||
* if a support program or file does not exist. This
|
||||
* can also be used as a catchall message when something
|
||||
* you wanted to do doesn't work, but you don't know
|
||||
* why.
|
||||
* EX_SOFTWARE -- An internal software error has been detected.
|
||||
* This should be limited to non-operating system related
|
||||
* errors as possible.
|
||||
* EX_OSERR -- An operating system error has been detected.
|
||||
* This is intended to be used for such things as "cannot
|
||||
* fork", "cannot create pipe", or the like. It includes
|
||||
* things like getuid returning a user that does not
|
||||
* exist in the passwd file.
|
||||
* EX_OSFILE -- Some system file (e.g., /etc/passwd, /var/run/utmp,
|
||||
* etc.) does not exist, cannot be opened, or has some
|
||||
* sort of error (e.g., syntax error).
|
||||
* EX_CANTCREAT -- A (user specified) output file cannot be
|
||||
* created.
|
||||
* EX_IOERR -- An error occurred while doing I/O on some file.
|
||||
* EX_TEMPFAIL -- temporary failure, indicating something that
|
||||
* is not really an error. In sendmail, this means
|
||||
* that a mailer (e.g.) could not create a connection,
|
||||
* and the request should be reattempted later.
|
||||
* EX_PROTOCOL -- the remote system returned something that
|
||||
* was "not possible" during a protocol exchange.
|
||||
* EX_NOPERM -- You did not have sufficient permission to
|
||||
* perform the operation. This is not intended for
|
||||
* file system problems, which should use EX_NOINPUT or
|
||||
* EX_CANTCREAT, but rather for higher level permissions.
|
||||
* EX_CONFIG -- Something was found in an unconfigured or
|
||||
* misconfigured state.
|
||||
*/
|
||||
|
||||
#define EX_OK 0 /* successful termination */
|
||||
|
||||
#define EX__BASE 64 /* base value for error messages */
|
||||
|
||||
#define EX_USAGE 64 /* command line usage error */
|
||||
#define EX_DATAERR 65 /* data format error */
|
||||
#define EX_NOINPUT 66 /* cannot open input */
|
||||
#define EX_NOUSER 67 /* addressee unknown */
|
||||
#define EX_NOHOST 68 /* host name unknown */
|
||||
#define EX_UNAVAILABLE 69 /* service unavailable */
|
||||
#define EX_SOFTWARE 70 /* internal software error */
|
||||
#define EX_OSERR 71 /* system error (e.g., can't fork) */
|
||||
#define EX_OSFILE 72 /* critical OS file missing */
|
||||
#define EX_CANTCREAT 73 /* can't create (user) output file */
|
||||
#define EX_IOERR 74 /* input/output error */
|
||||
#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
|
||||
#define EX_PROTOCOL 76 /* remote error in protocol */
|
||||
#define EX_NOPERM 77 /* permission denied */
|
||||
#define EX_CONFIG 78 /* configuration error */
|
||||
|
||||
#define EX__MAX 78 /* maximum listed value */
|
||||
|
||||
#endif /* !_SYSEXITS_H_ */
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 5 && !defined(__cplusplus)
|
||||
#if __STDC_VERSION__ >= 201112L && !defined(__cplusplus)
|
||||
typedef __CHAR16_TYPE__ char16_t;
|
||||
typedef __CHAR32_TYPE__ char32_t;
|
||||
#endif
|
||||
|
||||
1456
libc/libc.map
Normal file
1456
libc/libc.map
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
@@ -57,10 +57,11 @@ def CheckSymbols(library, functions_or_variables):
|
||||
for line in subprocess.check_output(['readelf', '-W', '--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
|
||||
|
||||
|
||||
@@ -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_[];
|
||||
|
||||
Binary file not shown.
@@ -36,7 +36,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# A dummy libdl.a. Need for static executables using the LLVM unwinder. Most
|
||||
@@ -49,5 +49,5 @@ LOCAL_CXX_STL := none
|
||||
|
||||
LOCAL_MODULE := libdl
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
@@ -3,8 +3,9 @@ LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
bionic_coverage := false
|
||||
|
||||
ifneq (,$(filter $(TARGET_ARCH),x86 x86_64))
|
||||
# Clang has wrong long double sizes for x86.
|
||||
# Clang/llvm has incompatible long double (fp128) for x86_64.
|
||||
# https://llvm.org/bugs/show_bug.cgi?id=23897
|
||||
ifeq ($(TARGET_ARCH),x86_64)
|
||||
libm_clang := false
|
||||
endif
|
||||
|
||||
@@ -502,7 +503,7 @@ LOCAL_CFLAGS += \
|
||||
-fno-builtin-rintl \
|
||||
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -510,17 +511,21 @@ 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=both
|
||||
LOCAL_LDFLAGS_x86 := -Wl,--hash-style=both
|
||||
|
||||
LOCAL_LDFLAGS := -Wl,--version-script,$(LOCAL_PATH)/libm.map
|
||||
|
||||
LOCAL_MODULE := libm
|
||||
LOCAL_CLANG := $(libm_clang)
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES := libc
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := libm
|
||||
|
||||
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
|
||||
LOCAL_CXX_STL := none
|
||||
|
||||
|
||||
378
libm/libm.map
Normal file
378
libm/libm.map
Normal file
@@ -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;
|
||||
@@ -9,7 +9,6 @@ LOCAL_SRC_FILES:= \
|
||||
linker_allocator.cpp \
|
||||
linker_sdk_versions.cpp \
|
||||
linker_block_allocator.cpp \
|
||||
linker_environ.cpp \
|
||||
linker_libc_support.c \
|
||||
linker_memory.cpp \
|
||||
linker_phdr.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,7 +158,14 @@ 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);
|
||||
}
|
||||
|
||||
@@ -258,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
|
||||
|
||||
@@ -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>
|
||||
@@ -53,14 +53,15 @@
|
||||
#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"
|
||||
|
||||
// Override macros to use C++ style casts
|
||||
extern void __libc_init_AT_SECURE(KernelArgumentBlock&);
|
||||
|
||||
// Override macros to use C++ style casts.
|
||||
#undef ELF_ST_TYPE
|
||||
#define ELF_ST_TYPE(x) (static_cast<uint32_t>(x) & 0xf)
|
||||
|
||||
@@ -96,6 +97,14 @@ __LIBC_HIDDEN__ int g_ld_debug_verbosity;
|
||||
|
||||
__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
|
||||
|
||||
static std::string dirname(const char *path) {
|
||||
const char* last_slash = strrchr(path, '/');
|
||||
if (last_slash == path) return "/";
|
||||
else if (last_slash == nullptr) return ".";
|
||||
else
|
||||
return std::string(path, last_slash - path);
|
||||
}
|
||||
|
||||
#if STATS
|
||||
struct linker_stats_t {
|
||||
int count[kRelocMax];
|
||||
@@ -307,6 +316,38 @@ static void parse_LD_LIBRARY_PATH(const char* path) {
|
||||
parse_path(path, ":", &g_ld_library_paths);
|
||||
}
|
||||
|
||||
void soinfo::set_dt_runpath(const char* path) {
|
||||
if (!has_min_version(2)) return;
|
||||
parse_path(path, ":", &dt_runpath_);
|
||||
|
||||
std::string origin = dirname(get_realpath());
|
||||
// FIXME: add $LIB and $PLATFORM.
|
||||
std::pair<std::string, std::string> substs[] = {{"ORIGIN", origin}};
|
||||
for (std::string& s : dt_runpath_) {
|
||||
size_t pos = 0;
|
||||
while (pos < s.size()) {
|
||||
pos = s.find("$", pos);
|
||||
if (pos == std::string::npos) break;
|
||||
for (const auto& subst : substs) {
|
||||
const std::string& token = subst.first;
|
||||
const std::string& replacement = subst.second;
|
||||
if (s.substr(pos + 1, token.size()) == token) {
|
||||
s.replace(pos, token.size() + 1, replacement);
|
||||
// -1 to compensate for the ++pos below.
|
||||
pos += replacement.size() - 1;
|
||||
break;
|
||||
} else if (s.substr(pos + 1, token.size() + 2) == "{" + token + "}") {
|
||||
s.replace(pos, token.size() + 3, replacement);
|
||||
pos += replacement.size() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Skip $ in case it did not match any of the known substitutions.
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_LD_PRELOAD(const char* path) {
|
||||
// We have historically supported ':' as well as ' ' in LD_PRELOAD.
|
||||
parse_path(path, " :", &g_ld_preload_names);
|
||||
@@ -316,6 +357,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;
|
||||
}
|
||||
|
||||
@@ -350,7 +392,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;
|
||||
@@ -947,6 +989,17 @@ static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
|
||||
// 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);
|
||||
}
|
||||
@@ -974,7 +1027,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;
|
||||
}
|
||||
|
||||
@@ -1065,11 +1121,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;
|
||||
}
|
||||
@@ -1083,7 +1139,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;
|
||||
@@ -1102,7 +1158,7 @@ static int open_library_in_zipfile(const char* const path,
|
||||
|
||||
ZipEntry entry;
|
||||
|
||||
if (FindEntry(handle, ZipEntryName(file_path), &entry) != 0) {
|
||||
if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
|
||||
// Entry was not found.
|
||||
close(fd);
|
||||
return -1;
|
||||
@@ -1145,8 +1201,9 @@ static int open_library_on_default_path(const char* name, off64_t* file_offset)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int open_library_on_ld_library_path(const char* name, off64_t* file_offset) {
|
||||
for (const auto& path_str : g_ld_library_paths) {
|
||||
static int open_library_on_paths(const char* name, off64_t* file_offset,
|
||||
const std::vector<std::string>& paths) {
|
||||
for (const auto& path_str : paths) {
|
||||
char buf[512];
|
||||
const char* const path = path_str.c_str();
|
||||
if (!format_path(buf, sizeof(buf), path, name)) {
|
||||
@@ -1173,7 +1230,7 @@ static int open_library_on_ld_library_path(const char* name, off64_t* file_offse
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int open_library(const char* name, off64_t* file_offset) {
|
||||
static int open_library(const char* name, soinfo *needed_by, off64_t* file_offset) {
|
||||
TRACE("[ opening %s ]", name);
|
||||
|
||||
// If the name contains a slash, we should attempt to open it directly and not search the paths.
|
||||
@@ -1193,18 +1250,36 @@ static int open_library(const char* name, off64_t* file_offset) {
|
||||
}
|
||||
|
||||
// Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
|
||||
int fd = open_library_on_ld_library_path(name, file_offset);
|
||||
int fd = open_library_on_paths(name, file_offset, g_ld_library_paths);
|
||||
if (fd == -1 && needed_by) {
|
||||
fd = open_library_on_paths(name, file_offset, needed_by->get_dt_runpath());
|
||||
}
|
||||
if (fd == -1) {
|
||||
fd = open_library_on_default_path(name, 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1256,12 +1331,12 @@ static soinfo* load_library(int fd, off64_t file_offset,
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1288,8 +1363,8 @@ static soinfo* load_library(int fd, off64_t file_offset,
|
||||
return si;
|
||||
}
|
||||
|
||||
static soinfo* load_library(LoadTaskList& load_tasks,
|
||||
const char* name, int rtld_flags,
|
||||
static soinfo* load_library(LoadTaskList& load_tasks, const char* name,
|
||||
soinfo* needed_by, int rtld_flags,
|
||||
const android_dlextinfo* extinfo) {
|
||||
if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
|
||||
off64_t file_offset = 0;
|
||||
@@ -1301,7 +1376,7 @@ static soinfo* load_library(LoadTaskList& load_tasks,
|
||||
|
||||
// Open the file.
|
||||
off64_t file_offset;
|
||||
int fd = open_library(name, &file_offset);
|
||||
int fd = open_library(name, needed_by, &file_offset);
|
||||
if (fd == -1) {
|
||||
DL_ERR("library \"%s\" not found", name);
|
||||
return nullptr;
|
||||
@@ -1311,30 +1386,64 @@ static soinfo* load_library(LoadTaskList& load_tasks,
|
||||
return result;
|
||||
}
|
||||
|
||||
static soinfo *find_loaded_library_by_soname(const char* name) {
|
||||
// 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* needed_by, int rtld_flags,
|
||||
const android_dlextinfo* extinfo) {
|
||||
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, needed_by, 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;
|
||||
@@ -1403,13 +1512,13 @@ static bool find_libraries(soinfo* start_with, const char* const library_names[]
|
||||
// Step 1: load and pre-link all DT_NEEDED libraries in breadth first order.
|
||||
for (LoadTask::unique_ptr task(load_tasks.pop_front());
|
||||
task.get() != nullptr; task.reset(load_tasks.pop_front())) {
|
||||
soinfo* si = find_library_internal(load_tasks, task->get_name(), rtld_flags, extinfo);
|
||||
soinfo* needed_by = task->get_needed_by();
|
||||
soinfo* si = find_library_internal(load_tasks, task->get_name(), needed_by,
|
||||
rtld_flags, extinfo);
|
||||
if (si == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
soinfo* needed_by = task->get_needed_by();
|
||||
|
||||
if (needed_by != nullptr) {
|
||||
needed_by->add_child(si);
|
||||
}
|
||||
@@ -2306,6 +2415,16 @@ soinfo::soinfo_list_t& soinfo::get_parents() {
|
||||
return g_empty_list;
|
||||
}
|
||||
|
||||
static std::vector<std::string> g_empty_runpath;
|
||||
|
||||
const std::vector<std::string>& soinfo::get_dt_runpath() const {
|
||||
if (has_min_version(2)) {
|
||||
return dt_runpath_;
|
||||
}
|
||||
|
||||
return g_empty_runpath;
|
||||
}
|
||||
|
||||
ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
|
||||
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
|
||||
return call_ifunc_resolver(s->st_value + load_bias);
|
||||
@@ -2363,64 +2482,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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
// 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__;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (close(dev_null) == -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() {
|
||||
@@ -2730,7 +2800,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__)
|
||||
@@ -2791,6 +2861,10 @@ bool soinfo::prelink_image() {
|
||||
verneed_cnt_ = d->d_un.d_val;
|
||||
break;
|
||||
|
||||
case DT_RUNPATH:
|
||||
// this is parsed after we have strtab initialized (see below).
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!relocating_linker) {
|
||||
DL_WARN("%s: unused DT entry: type %p arg %p", get_realpath(),
|
||||
@@ -2800,16 +2874,11 @@ 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(__work_around_b_19059885__)
|
||||
strlcpy(old_name_, soname_, sizeof(old_name_));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#if defined(__mips__) && !defined(__LP64__)
|
||||
if (!mips_check_and_adjust_fp_modes()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p",
|
||||
reinterpret_cast<void*>(base), strtab_, symtab_);
|
||||
@@ -2832,6 +2901,35 @@ bool soinfo::prelink_image() {
|
||||
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) {
|
||||
switch (d->d_tag) {
|
||||
case 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;
|
||||
case DT_RUNPATH:
|
||||
// FIXME: $LIB, $PLATFORM unsupported.
|
||||
set_dt_runpath(get_string(d->d_un.d_val));
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2843,6 +2941,10 @@ 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)) {
|
||||
@@ -2851,6 +2953,13 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
|
||||
|
||||
#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 "
|
||||
@@ -3020,7 +3129,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
|
||||
@@ -3048,41 +3157,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);
|
||||
|
||||
// Initialize system properties
|
||||
__system_properties_init(); // may use 'environ'
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -250,7 +250,9 @@ struct soinfo {
|
||||
bool mips_relocate_got(const VersionTracker& version_tracker,
|
||||
const soinfo_list_t& global_group,
|
||||
const soinfo_list_t& local_group);
|
||||
|
||||
#if !defined(__LP64__)
|
||||
bool mips_check_and_adjust_fp_modes();
|
||||
#endif
|
||||
#endif
|
||||
size_t ref_count_;
|
||||
public:
|
||||
@@ -334,6 +336,10 @@ struct soinfo {
|
||||
|
||||
bool find_verdef_version_index(const version_info* vi, ElfW(Versym)* versym) const;
|
||||
|
||||
uint32_t get_target_sdk_version() const;
|
||||
|
||||
const std::vector<std::string>& get_dt_runpath() 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);
|
||||
@@ -393,6 +399,11 @@ struct soinfo {
|
||||
ElfW(Addr) verneed_ptr_;
|
||||
size_t verneed_cnt_;
|
||||
|
||||
uint32_t target_sdk_version_;
|
||||
|
||||
void set_dt_runpath(const char *);
|
||||
std::vector<std::string> dt_runpath_;
|
||||
|
||||
friend soinfo* get_libdl_info();
|
||||
};
|
||||
|
||||
@@ -417,6 +428,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);
|
||||
|
||||
|
||||
@@ -1,191 +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 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 = environ;
|
||||
char** dst = environ;
|
||||
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.
|
||||
environ = 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 = environ; 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;
|
||||
}
|
||||
@@ -26,8 +26,21 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if !defined(__LP64__) && __mips_isa_rev >= 5
|
||||
#include <sys/prctl.h>
|
||||
#if defined(PR_SET_FP_MODE)
|
||||
#error "remove following defs when avail in Android's kernel headers"
|
||||
#else
|
||||
#define PR_SET_FP_MODE 45
|
||||
#define PR_GET_FP_MODE 46
|
||||
#define PR_FP_MODE_FR (1 << 0)
|
||||
#define PR_FP_MODE_FRE (1 << 1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "linker.h"
|
||||
#include "linker_debug.h"
|
||||
#include "linker_phdr.h"
|
||||
#include "linker_relocs.h"
|
||||
#include "linker_reloc_iterators.h"
|
||||
#include "linker_sleb128.h"
|
||||
@@ -62,7 +75,7 @@ bool soinfo::relocate(const VersionTracker& version_tracker,
|
||||
ElfW(Addr) sym_addr = 0;
|
||||
const char* sym_name = nullptr;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -84,7 +97,8 @@ bool soinfo::relocate(const VersionTracker& version_tracker,
|
||||
|
||||
if (s == nullptr) {
|
||||
// mips does not support relocation with weak-undefined symbols
|
||||
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;
|
||||
} else {
|
||||
// We got a definition.
|
||||
@@ -171,20 +185,22 @@ bool soinfo::mips_relocate_got(const VersionTracker& version_tracker,
|
||||
}
|
||||
} else if (st_visibility == STV_PROTECTED) {
|
||||
if (local_sym->st_value == 0) {
|
||||
DL_ERR("%s: invalid symbol \"%s\" (PROTECTED/UNDEFINED) ", get_soname(), sym_name);
|
||||
DL_ERR("%s: invalid symbol \"%s\" (PROTECTED/UNDEFINED) ",
|
||||
get_realpath(), 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);
|
||||
DL_ERR("%s: invalid symbol \"%s\" visibility: 0x%x",
|
||||
get_realpath(), sym_name, st_visibility);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s == nullptr) {
|
||||
// We only allow an undefined symbol if this is a weak reference.
|
||||
if (ELF_ST_BIND(local_sym->st_info) != STB_WEAK) {
|
||||
DL_ERR("%s: cannot locate \"%s\"...", get_soname(), sym_name);
|
||||
DL_ERR("%s: cannot locate \"%s\"...", get_realpath(), sym_name);
|
||||
return false;
|
||||
}
|
||||
*got = 0;
|
||||
@@ -198,3 +214,126 @@ bool soinfo::mips_relocate_got(const VersionTracker& version_tracker,
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined(__LP64__)
|
||||
|
||||
// Checks for mips32's various floating point abis.
|
||||
// (Mips64 Android has a single floating point abi and doesn't need any checks)
|
||||
|
||||
// Linux kernel has declarations similar to the following
|
||||
// in <linux>/arch/mips/include/asm/elf.h,
|
||||
// but that non-uapi internal header file will never be imported
|
||||
// into bionic's kernel headers.
|
||||
|
||||
#define PT_MIPS_ABIFLAGS 0x70000003 // is .MIPS.abiflags segment
|
||||
|
||||
struct mips_elf_abiflags_v0 {
|
||||
uint16_t version; // version of this structure
|
||||
uint8_t isa_level, isa_rev, gpr_size, cpr1_size, cpr2_size;
|
||||
uint8_t fp_abi; // mips32 ABI variants for floating point
|
||||
uint16_t isa_ext, ases, flags1, flags2;
|
||||
};
|
||||
|
||||
// Bits of flags1:
|
||||
#define MIPS_AFL_FLAGS1_ODDSPREG 1 // Uses odd-numbered single-prec fp regs
|
||||
|
||||
// Some values of fp_abi: via compiler flag:
|
||||
#define MIPS_ABI_FP_DOUBLE 1 // -mdouble-float
|
||||
#define MIPS_ABI_FP_XX 5 // -mfpxx
|
||||
#define MIPS_ABI_FP_64A 7 // -mips32r* -mfp64 -mno-odd-spreg
|
||||
|
||||
#if __mips_isa_rev >= 5
|
||||
static bool mips_fre_mode_on = false; // have set FRE=1 mode for process
|
||||
#endif
|
||||
|
||||
bool soinfo::mips_check_and_adjust_fp_modes() {
|
||||
mips_elf_abiflags_v0* abiflags = nullptr;
|
||||
int mips_fpabi;
|
||||
|
||||
// Find soinfo's optional .MIPS.abiflags segment
|
||||
for (size_t i = 0; i<phnum; ++i) {
|
||||
const ElfW(Phdr)& ph = phdr[i];
|
||||
if (ph.p_type == PT_MIPS_ABIFLAGS) {
|
||||
if (ph.p_filesz < sizeof (mips_elf_abiflags_v0)) {
|
||||
DL_ERR("Corrupt PT_MIPS_ABIFLAGS header found \"%s\"", get_realpath());
|
||||
return false;
|
||||
}
|
||||
abiflags = reinterpret_cast<mips_elf_abiflags_v0*>(ph.p_vaddr + load_bias);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// FP ABI-variant compatibility checks for MIPS o32 ABI
|
||||
if (abiflags == nullptr) {
|
||||
// Old compiles lack the new abiflags section.
|
||||
// These compilers used -mfp32 -mdouble-float -modd-spreg defaults,
|
||||
// ie FP32 aka DOUBLE, using odd-numbered single-prec regs
|
||||
mips_fpabi = MIPS_ABI_FP_DOUBLE;
|
||||
} else {
|
||||
mips_fpabi = abiflags->fp_abi;
|
||||
if ( (abiflags->flags1 & MIPS_AFL_FLAGS1_ODDSPREG)
|
||||
&& (mips_fpabi == MIPS_ABI_FP_XX ||
|
||||
mips_fpabi == MIPS_ABI_FP_64A ) ) {
|
||||
// Android supports fewer cases than Linux
|
||||
DL_ERR("Unsupported odd-single-prec FloatPt reg uses in \"%s\"",
|
||||
get_realpath());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!(mips_fpabi == MIPS_ABI_FP_DOUBLE ||
|
||||
#if __mips_isa_rev >= 5
|
||||
mips_fpabi == MIPS_ABI_FP_64A ||
|
||||
#endif
|
||||
mips_fpabi == MIPS_ABI_FP_XX )) {
|
||||
DL_ERR("Unsupported MIPS32 FloatPt ABI %d found in \"%s\"",
|
||||
mips_fpabi, get_realpath());
|
||||
return false;
|
||||
}
|
||||
|
||||
#if __mips_isa_rev >= 5
|
||||
// Adjust process's FR Emulation mode, if needed
|
||||
//
|
||||
// On Mips R5 & R6, Android runs continuously in FR=1 64bit-fpreg mode.
|
||||
// NDK mips32 apps compiled with old compilers generate FP32 code
|
||||
// which expects FR=0 32-bit fp registers.
|
||||
// NDK mips32 apps compiled with newer compilers generate modeless
|
||||
// FPXX code which runs on both FR=0 and FR=1 modes.
|
||||
// Android itself is compiled in FP64A which requires FR=1 mode.
|
||||
// FP32, FPXX, and FP64A all interlink okay, without dynamic FR mode
|
||||
// changes during calls. For details, see
|
||||
// http://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
|
||||
// Processes containing FR32 FR=0 code are run via kernel software assist,
|
||||
// which maps all odd-numbered single-precision reg refs onto the
|
||||
// upper half of the paired even-numbered double-precision reg.
|
||||
// FRE=1 triggers traps to the kernel's emulator on every single-precision
|
||||
// fp op (for both odd and even-numbered registers).
|
||||
// Turning on FRE=1 traps is done at most once per process, simultanously
|
||||
// for all threads of that process, when dlopen discovers FP32 code.
|
||||
// The kernel repacks threads' registers when FRE mode is turn on or off.
|
||||
// These asynchronous adjustments are wrong if any thread was executing
|
||||
// FPXX code using odd-numbered single-precision regs.
|
||||
// Current Android compilers default to the -mno-oddspreg option,
|
||||
// and this requirement is checked by Android's dlopen.
|
||||
// So FRE can always be safely turned on for FP32, anytime.
|
||||
// Deferred enhancement: Allow loading of odd-spreg FPXX modules.
|
||||
|
||||
if (mips_fpabi == MIPS_ABI_FP_DOUBLE && !mips_fre_mode_on) {
|
||||
// Turn on FRE mode, which emulates mode-sensitive FR=0 code on FR=1
|
||||
// register files, by trapping to kernel on refs to single-precision regs
|
||||
if (prctl(PR_SET_FP_MODE, PR_FP_MODE_FR|PR_FP_MODE_FRE)) {
|
||||
DL_ERR("Kernel or cpu failed to set FRE mode required for running \"%s\"",
|
||||
get_realpath());
|
||||
return false;
|
||||
}
|
||||
DL_WARN("Using FRE=1 mode to run \"%s\"", get_realpath());
|
||||
mips_fre_mode_on = true; // Avoid future redundant mode-switch calls
|
||||
// FRE mode is never turned back off.
|
||||
// Deferred enhancement:
|
||||
// Reset FRE mode when dlclose() removes all FP32 modules
|
||||
}
|
||||
#else
|
||||
// Android runs continuously in FR=0 32bit-fpreg mode.
|
||||
#endif // __mips_isa_rev
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // __LP64___
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -15,11 +15,16 @@
|
||||
*/
|
||||
|
||||
#include "linker.h"
|
||||
#include <android/api-level.h>
|
||||
#include <atomic>
|
||||
|
||||
static std::atomic<uint32_t> g_target_sdk_version;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ endif
|
||||
LOCAL_CLANG := $($(module)_clang_$(build_type))
|
||||
|
||||
ifneq ($($(module)_allow_asan),true)
|
||||
LOCAL_ADDRESS_SANITIZER := false
|
||||
LOCAL_SANITIZE := never
|
||||
endif
|
||||
|
||||
LOCAL_FORCE_STATIC_EXECUTABLE := $($(module)_force_static_executable)
|
||||
@@ -48,6 +48,10 @@ ifneq ($($(module)_multilib),)
|
||||
LOCAL_MULTILIB := $($(module)_multilib)
|
||||
endif
|
||||
|
||||
ifneq ($($(module)_relative_path),)
|
||||
LOCAL_MODULE_RELATIVE_PATH := $($(module)_relative_path)
|
||||
endif
|
||||
|
||||
LOCAL_CFLAGS := \
|
||||
$(common_cflags) \
|
||||
$($(module)_cflags) \
|
||||
|
||||
@@ -49,9 +49,6 @@ endif
|
||||
test_cppflags = \
|
||||
-std=gnu++11 \
|
||||
|
||||
libBionicStandardTests_src_files_target := \
|
||||
libdl_test.cpp \
|
||||
|
||||
libBionicStandardTests_src_files := \
|
||||
arpa_inet_test.cpp \
|
||||
buffer_tests.cpp \
|
||||
@@ -96,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 \
|
||||
@@ -106,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 \
|
||||
@@ -137,6 +137,11 @@ libBionicStandardTests_static_libraries := \
|
||||
libBionicStandardTests_ldlibs_host := \
|
||||
-lrt \
|
||||
|
||||
# Clang/llvm has incompatible long double (fp128) for x86_64.
|
||||
# https://llvm.org/bugs/show_bug.cgi?id=23897
|
||||
# This affects most of math_test.cpp.
|
||||
libBionicStandardTests_clang_target := false
|
||||
|
||||
module := libBionicStandardTests
|
||||
module_tag := optional
|
||||
build_type := target
|
||||
@@ -272,6 +277,7 @@ 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)
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user