2020-01-01 00:14:33 +00:00
|
|
|
/* Copyright (C) 2012-2020 Free Software Foundation, Inc.
|
2013-01-16 13:57:42 +00:00
|
|
|
|
|
|
|
This file is part of the GNU C Library.
|
|
|
|
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with the GNU C Library. If not, see
|
Prefer https to http for gnu.org and fsf.org URLs
Also, change sources.redhat.com to sourceware.org.
This patch was automatically generated by running the following shell
script, which uses GNU sed, and which avoids modifying files imported
from upstream:
sed -ri '
s,(http|ftp)(://(.*\.)?(gnu|fsf|sourceware)\.org($|[^.]|\.[^a-z])),https\2,g
s,(http|ftp)(://(.*\.)?)sources\.redhat\.com($|[^.]|\.[^a-z]),https\2sourceware.org\4,g
' \
$(find $(git ls-files) -prune -type f \
! -name '*.po' \
! -name 'ChangeLog*' \
! -path COPYING ! -path COPYING.LIB \
! -path manual/fdl-1.3.texi ! -path manual/lgpl-2.1.texi \
! -path manual/texinfo.tex ! -path scripts/config.guess \
! -path scripts/config.sub ! -path scripts/install-sh \
! -path scripts/mkinstalldirs ! -path scripts/move-if-change \
! -path INSTALL ! -path locale/programs/charmap-kw.h \
! -path po/libc.pot ! -path sysdeps/gnu/errlist.c \
! '(' -name configure \
-execdir test -f configure.ac -o -f configure.in ';' ')' \
! '(' -name preconfigure \
-execdir test -f preconfigure.ac ';' ')' \
-print)
and then by running 'make dist-prepare' to regenerate files built
from the altered files, and then executing the following to cleanup:
chmod a+x sysdeps/unix/sysv/linux/riscv/configure
# Omit irrelevant whitespace and comment-only changes,
# perhaps from a slightly-different Autoconf version.
git checkout -f \
sysdeps/csky/configure \
sysdeps/hppa/configure \
sysdeps/riscv/configure \
sysdeps/unix/sysv/linux/csky/configure
# Omit changes that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/powerpc/powerpc64/ppc-mcount.S: trailing lines
git checkout -f \
sysdeps/powerpc/powerpc64/ppc-mcount.S \
sysdeps/unix/sysv/linux/s390/s390-64/syscall.S
# Omit change that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S: last line does not end in newline
git checkout -f sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S
2019-09-07 05:40:42 +00:00
|
|
|
<https://www.gnu.org/licenses/>. */
|
2013-01-16 13:57:42 +00:00
|
|
|
|
|
|
|
#include <sysdep.h>
|
|
|
|
|
|
|
|
/* Assumptions:
|
|
|
|
*
|
2015-07-13 11:38:12 +00:00
|
|
|
* ARMv8-a, AArch64, unaligned accesses, min page size 4k.
|
2013-01-16 13:57:42 +00:00
|
|
|
*/
|
|
|
|
|
2018-08-15 17:31:33 +00:00
|
|
|
#ifndef STRLEN
|
|
|
|
# define STRLEN __strlen
|
|
|
|
#endif
|
|
|
|
|
2015-07-13 11:38:12 +00:00
|
|
|
/* To test the page crossing code path more thoroughly, compile with
|
|
|
|
-DTEST_PAGE_CROSS - this will force all calls through the slower
|
|
|
|
entry path. This option is not intended for production use. */
|
|
|
|
|
2013-01-16 13:57:42 +00:00
|
|
|
/* Arguments and results. */
|
|
|
|
#define srcin x0
|
|
|
|
#define len x0
|
|
|
|
|
|
|
|
/* Locals and temporaries. */
|
|
|
|
#define src x1
|
|
|
|
#define data1 x2
|
|
|
|
#define data2 x3
|
2015-07-13 11:38:12 +00:00
|
|
|
#define has_nul1 x4
|
|
|
|
#define has_nul2 x5
|
|
|
|
#define tmp1 x4
|
|
|
|
#define tmp2 x5
|
|
|
|
#define tmp3 x6
|
|
|
|
#define tmp4 x7
|
|
|
|
#define zeroones x8
|
|
|
|
|
|
|
|
/* NUL detection works on the principle that (X - 1) & (~X) & 0x80
|
|
|
|
(=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
|
|
|
|
can be done in parallel across the entire word. A faster check
|
|
|
|
(X - 1) & 0x80 is zero for non-NUL ASCII characters, but gives
|
|
|
|
false hits for characters 129..255. */
|
2013-01-16 13:57:42 +00:00
|
|
|
|
|
|
|
#define REP8_01 0x0101010101010101
|
|
|
|
#define REP8_7f 0x7f7f7f7f7f7f7f7f
|
|
|
|
#define REP8_80 0x8080808080808080
|
|
|
|
|
2015-07-13 11:38:12 +00:00
|
|
|
#ifdef TEST_PAGE_CROSS
|
2018-08-08 15:46:07 +00:00
|
|
|
# define MIN_PAGE_SIZE 16
|
2015-07-13 11:38:12 +00:00
|
|
|
#else
|
|
|
|
# define MIN_PAGE_SIZE 4096
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Since strings are short on average, we check the first 16 bytes
|
|
|
|
of the string for a NUL character. In order to do an unaligned ldp
|
|
|
|
safely we have to do a page cross check first. If there is a NUL
|
|
|
|
byte we calculate the length from the 2 8-byte words using
|
|
|
|
conditional select to reduce branch mispredictions (it is unlikely
|
|
|
|
strlen will be repeatedly called on strings with the same length).
|
|
|
|
|
|
|
|
If the string is longer than 16 bytes, we align src so don't need
|
|
|
|
further page cross checks, and process 32 bytes per iteration
|
|
|
|
using the fast NUL check. If we encounter non-ASCII characters,
|
|
|
|
fallback to a second loop using the full NUL check.
|
|
|
|
|
|
|
|
If the page cross check fails, we read 16 bytes from an aligned
|
|
|
|
address, remove any characters before the string, and continue
|
|
|
|
in the main loop using aligned loads. Since strings crossing a
|
|
|
|
page in the first 16 bytes are rare (probability of
|
|
|
|
16/MIN_PAGE_SIZE ~= 0.4%), this case does not need to be optimized.
|
|
|
|
|
|
|
|
AArch64 systems have a minimum page size of 4k. We don't bother
|
|
|
|
checking for larger page sizes - the cost of setting up the correct
|
|
|
|
page size is just not worth the extra gain from a small reduction in
|
|
|
|
the cases taking the slow path. Note that we only care about
|
|
|
|
whether the first fetch, which may be misaligned, crosses a page
|
|
|
|
boundary. */
|
|
|
|
|
2018-08-15 17:31:33 +00:00
|
|
|
ENTRY_ALIGN (STRLEN, 6)
|
Partial ILP32 support for aarch64.
* sysdeps/aarch64/crti.S: Add include of sysdep.h.
(call_weak_fn): Use PTR_REG to get correct reg name in ILP32.
* sysdeps/aarch64/dl-irel.h: Add include of sysdep.h.
(elf_irela): Use AARCH64_R macro to get correct relocation in ILP32.
* sysdeps/aarch64/dl-machine.h: Add include of sysdep.h.
(elf_machine_load_address, RTLD_START, RTLD_START_1, RTLD_START,
elf_machine_type_class, ELF_MACHINE_JMP_SLOT, elf_machine_rela,
elf_machine_lazy_rel): Add ifdef's for ILP32 support.
* sysdeps/aarch64/dl-tlsdesc.S (_dl_tlsdesc_return,
_dl_tlsdesc_return_lazy, _dl_tlsdesc_dynamic,
_dl_tlsdesc_resolve_hold): Extend pointers in ILP32, use PTR_REG
to get correct reg name for ILP32.
* sysdeps/aarch64/dl-trampoline.S (ip01): New Macro.
(RELA_SIZE): New Macro.
(_dl_runtime_resolve, _dl_runtime_profile): Use new macros and PTR_REG
to support ILP32.
* sysdeps/aarch64/jmpbuf-unwind.h (_JMPBUF_CFA_UNWINDS_ADJ): Add
cast for ILP32 mode.
* sysdeps/aarch64/memcmp.S (memcmp): Extend arg pointers for ILP32 mode.
* sysdeps/aarch64/memcpy.S (memmove, memcpy): Ditto.
* sysdeps/aarch64/memset.S (__memset): Ditto.
* sysdeps/aarch64/strchr.S (strchr): Ditto.
* sysdeps/aarch64/strchrnul.S (__strchrnul): Ditto.
* sysdeps/aarch64/strcmp.S (strcmp): Ditto.
* sysdeps/aarch64/strcpy.S (strcpy): Ditto.
* sysdeps/aarch64/strlen.S (__strlen): Ditto.
* sysdeps/aarch64/strncmp.S (strncmp): Ditto.
* sysdeps/aarch64/strnlen.S (strnlen): Ditto.
* sysdeps/aarch64/strrchr.S (strrchr): Ditto.
* sysdeps/unix/sysv/linux/aarch64/clone.S: Ditto.
* sysdeps/unix/sysv/linux/aarch64/setcontext.S (__setcontext): Ditto.
* sysdeps/unix/sysv/linux/aarch64/swapcontext.S (__swapcontext): Ditto.
* sysdeps/aarch64/__longjmp.S (__longjmp): Extend pointers in ILP32,
change PTR_MANGLE call to use register numbers instead of names.
* sysdeps/unix/sysv/linux/aarch64/getcontext.S (__getcontext): Ditto.
* sysdeps/aarch64/setjmp.S (__sigsetjmp): Extend arg pointers for
ILP32 mode, change PTR_MANGLE calls to use register numbers.
* sysdeps/aarch64/start.S (_start): Ditto.
* sysdeps/aarch64/nptl/bits/pthreadtypes.h
(__PTHREAD_RWLOCK_INT_FLAGS_SHARED): New define.
(__SIZEOF_PTHREAD_ATTR_T, __SIZEOF_PTHREAD_MUTEX_T,
__SIZEOF_PTHREAD_MUTEXATTR_T, __SIZEOF_PTHREAD_COND_T,
__SIZEOF_PTHREAD_COND_COMPAT_T, __SIZEOF_PTHREAD_CONDATTR_T,
__SIZEOF_PTHREAD_RWLOCK_T, __SIZEOF_PTHREAD_RWLOCKATTR_T,
__SIZEOF_PTHREAD_BARRIER_T, __SIZEOF_PTHREAD_BARRIERATTR_T):
Make defined values dependent on __ILP32__.
* sysdeps/aarch64/nptl/bits/semaphore.h (__SIZEOF_SEM_T): Change define.
(sem_t): Change __align type.
* sysdeps/aarch64/sysdep.h (AARCH64_R, PTR_REG, PTR_LOG_SIZE, DELOUSE,
PTR_SIZE): New Macros.
(LDST_PCREL, LDST_GLOBAL) Update to use PTR_REG.
* sysdeps/unix/sysv/linux/aarch64/bits/fcntl.h (O_LARGEFILE):
Set when in ILP32 mode.
(F_GETLK64, F_SETLK64, F_SETLKW64): Only set in LP64 mode.
* sysdeps/unix/sysv/linux/aarch64/dl-cache.h (DL_CACHE_DEFAULT_ID):
Set elf flags for ILP32.
(add_system_dir): Set ILP32 library directories.
* sysdeps/unix/sysv/linux/aarch64/init-first.c
(_libc_vdso_platform_setup): Set minimum kernel version for ILP32.
* sysdeps/unix/sysv/linux/aarch64/ldconfig.h
(SYSDEP_KNOWN_INTERPRETER_NAMES): Add ILP32 names.
* sysdeps/unix/sysv/linux/aarch64/sigcontextinfo.h (GET_PC, SET_PC):
New Macros.
* sysdeps/unix/sysv/linux/aarch64/sysdep.h: Handle ILP32 pointers.
2016-11-28 17:01:23 +00:00
|
|
|
DELOUSE (0)
|
|
|
|
DELOUSE (1)
|
2015-07-13 11:38:12 +00:00
|
|
|
and tmp1, srcin, MIN_PAGE_SIZE - 1
|
|
|
|
mov zeroones, REP8_01
|
|
|
|
cmp tmp1, MIN_PAGE_SIZE - 16
|
|
|
|
b.gt L(page_cross)
|
|
|
|
ldp data1, data2, [srcin]
|
|
|
|
#ifdef __AARCH64EB__
|
|
|
|
/* For big-endian, carry propagation (if the final byte in the
|
|
|
|
string is 0x01) means we cannot use has_nul1/2 directly.
|
|
|
|
Since we expect strings to be small and early-exit,
|
|
|
|
byte-swap the data now so has_null1/2 will be correct. */
|
|
|
|
rev data1, data1
|
|
|
|
rev data2, data2
|
|
|
|
#endif
|
2013-01-16 13:57:42 +00:00
|
|
|
sub tmp1, data1, zeroones
|
2015-07-13 11:38:12 +00:00
|
|
|
orr tmp2, data1, REP8_7f
|
2013-01-16 13:57:42 +00:00
|
|
|
sub tmp3, data2, zeroones
|
2015-07-13 11:38:12 +00:00
|
|
|
orr tmp4, data2, REP8_7f
|
|
|
|
bics has_nul1, tmp1, tmp2
|
|
|
|
bic has_nul2, tmp3, tmp4
|
|
|
|
ccmp has_nul2, 0, 0, eq
|
|
|
|
beq L(main_loop_entry)
|
2013-01-16 13:57:42 +00:00
|
|
|
|
2015-07-13 11:38:12 +00:00
|
|
|
/* Enter with C = has_nul1 == 0. */
|
|
|
|
csel has_nul1, has_nul1, has_nul2, cc
|
|
|
|
mov len, 8
|
|
|
|
rev has_nul1, has_nul1
|
|
|
|
clz tmp1, has_nul1
|
|
|
|
csel len, xzr, len, cc
|
|
|
|
add len, len, tmp1, lsr 3
|
|
|
|
ret
|
|
|
|
|
|
|
|
/* The inner loop processes 32 bytes per iteration and uses the fast
|
|
|
|
NUL check. If we encounter non-ASCII characters, use a second
|
|
|
|
loop with the accurate NUL check. */
|
|
|
|
.p2align 4
|
|
|
|
L(main_loop_entry):
|
|
|
|
bic src, srcin, 15
|
|
|
|
sub src, src, 16
|
|
|
|
L(main_loop):
|
|
|
|
ldp data1, data2, [src, 32]!
|
|
|
|
L(page_cross_entry):
|
|
|
|
sub tmp1, data1, zeroones
|
|
|
|
sub tmp3, data2, zeroones
|
|
|
|
orr tmp2, tmp1, tmp3
|
|
|
|
tst tmp2, zeroones, lsl 7
|
|
|
|
bne 1f
|
|
|
|
ldp data1, data2, [src, 16]
|
|
|
|
sub tmp1, data1, zeroones
|
|
|
|
sub tmp3, data2, zeroones
|
|
|
|
orr tmp2, tmp1, tmp3
|
|
|
|
tst tmp2, zeroones, lsl 7
|
|
|
|
beq L(main_loop)
|
|
|
|
add src, src, 16
|
|
|
|
1:
|
|
|
|
/* The fast check failed, so do the slower, accurate NUL check. */
|
|
|
|
orr tmp2, data1, REP8_7f
|
|
|
|
orr tmp4, data2, REP8_7f
|
|
|
|
bics has_nul1, tmp1, tmp2
|
|
|
|
bic has_nul2, tmp3, tmp4
|
|
|
|
ccmp has_nul2, 0, 0, eq
|
|
|
|
beq L(nonascii_loop)
|
|
|
|
|
|
|
|
/* Enter with C = has_nul1 == 0. */
|
|
|
|
L(tail):
|
2013-01-16 13:57:42 +00:00
|
|
|
#ifdef __AARCH64EB__
|
|
|
|
/* For big-endian, carry propagation (if the final byte in the
|
2015-07-13 11:38:12 +00:00
|
|
|
string is 0x01) means we cannot use has_nul1/2 directly. The
|
2013-01-16 13:57:42 +00:00
|
|
|
easiest way to get the correct byte is to byte-swap the data
|
|
|
|
and calculate the syndrome a second time. */
|
2015-07-13 11:38:12 +00:00
|
|
|
csel data1, data1, data2, cc
|
|
|
|
rev data1, data1
|
|
|
|
sub tmp1, data1, zeroones
|
|
|
|
orr tmp2, data1, REP8_7f
|
|
|
|
bic has_nul1, tmp1, tmp2
|
|
|
|
#else
|
|
|
|
csel has_nul1, has_nul1, has_nul2, cc
|
2013-01-16 13:57:42 +00:00
|
|
|
#endif
|
2015-07-13 11:38:12 +00:00
|
|
|
sub len, src, srcin
|
|
|
|
rev has_nul1, has_nul1
|
|
|
|
add tmp2, len, 8
|
|
|
|
clz tmp1, has_nul1
|
|
|
|
csel len, len, tmp2, cc
|
|
|
|
add len, len, tmp1, lsr 3
|
|
|
|
ret
|
|
|
|
|
|
|
|
L(nonascii_loop):
|
|
|
|
ldp data1, data2, [src, 16]!
|
|
|
|
sub tmp1, data1, zeroones
|
|
|
|
orr tmp2, data1, REP8_7f
|
|
|
|
sub tmp3, data2, zeroones
|
|
|
|
orr tmp4, data2, REP8_7f
|
|
|
|
bics has_nul1, tmp1, tmp2
|
|
|
|
bic has_nul2, tmp3, tmp4
|
|
|
|
ccmp has_nul2, 0, 0, eq
|
|
|
|
bne L(tail)
|
|
|
|
ldp data1, data2, [src, 16]!
|
|
|
|
sub tmp1, data1, zeroones
|
|
|
|
orr tmp2, data1, REP8_7f
|
|
|
|
sub tmp3, data2, zeroones
|
|
|
|
orr tmp4, data2, REP8_7f
|
|
|
|
bics has_nul1, tmp1, tmp2
|
|
|
|
bic has_nul2, tmp3, tmp4
|
|
|
|
ccmp has_nul2, 0, 0, eq
|
|
|
|
beq L(nonascii_loop)
|
|
|
|
b L(tail)
|
|
|
|
|
|
|
|
/* Load 16 bytes from [srcin & ~15] and force the bytes that precede
|
|
|
|
srcin to 0x7f, so we ignore any NUL bytes before the string.
|
|
|
|
Then continue in the aligned loop. */
|
|
|
|
L(page_cross):
|
|
|
|
bic src, srcin, 15
|
|
|
|
ldp data1, data2, [src]
|
|
|
|
lsl tmp1, srcin, 3
|
|
|
|
mov tmp4, -1
|
2013-01-16 13:57:42 +00:00
|
|
|
#ifdef __AARCH64EB__
|
2015-07-13 11:38:12 +00:00
|
|
|
/* Big-endian. Early bytes are at MSB. */
|
|
|
|
lsr tmp1, tmp4, tmp1 /* Shift (tmp1 & 63). */
|
2013-01-16 13:57:42 +00:00
|
|
|
#else
|
|
|
|
/* Little-endian. Early bytes are at LSB. */
|
2015-07-13 11:38:12 +00:00
|
|
|
lsl tmp1, tmp4, tmp1 /* Shift (tmp1 & 63). */
|
2013-01-16 13:57:42 +00:00
|
|
|
#endif
|
2015-07-13 11:38:12 +00:00
|
|
|
orr tmp1, tmp1, REP8_80
|
|
|
|
orn data1, data1, tmp1
|
|
|
|
orn tmp2, data2, tmp1
|
|
|
|
tst srcin, 8
|
|
|
|
csel data1, data1, tmp4, eq
|
|
|
|
csel data2, data2, tmp2, eq
|
|
|
|
b L(page_cross_entry)
|
2018-08-15 17:31:33 +00:00
|
|
|
END (STRLEN)
|
|
|
|
weak_alias (STRLEN, strlen)
|
2013-01-16 13:57:42 +00:00
|
|
|
libc_hidden_builtin_def (strlen)
|