1/* strlen -- find the length of a nul-terminated string. 2 Copyright (C) 2013-2021 Free Software Foundation, Inc. 3 This file is part of the GNU C Library. 4 5 The GNU C Library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 The GNU C Library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with the GNU C Library. If not, see 17 <https://www.gnu.org/licenses/>. */ 18 19#include <sysdep.h> 20 21 .syntax unified 22 .text 23 24ENTRY (strlen) 25 @ r0 = start of string 26 ldrb r2, [r0] @ load the first byte asap 27 28 @ To cater to long strings, we want to search through a few 29 @ characters until we reach an aligned pointer. To cater to 30 @ small strings, we don't want to start doing word operations 31 @ immediately. The compromise is a maximum of 16 bytes less 32 @ whatever is required to end with an aligned pointer. 33 @ r3 = number of characters to search in alignment loop 34 and r3, r0, #7 35 mov r1, r0 @ Save the input pointer 36 rsb r3, r3, #15 @ 16 - 1 peeled loop iteration 37 cmp r2, #0 38 beq 99f 39 40 @ Loop until we find ... 411: ldrb r2, [r0, #1]! 42 subs r3, r3, #1 @ ... the aligment point 43 it ne 44 cmpne r2, #0 @ ... or EOS 45 bne 1b 46 47 @ Disambiguate the exit possibilites above 48 cmp r2, #0 @ Found EOS 49 beq 99f 50 add r0, r0, #1 51 52 @ So now we're aligned. 53 ldrd r2, r3, [r0], #8 54#ifdef ARCH_HAS_T2 55 movw ip, #0x0101 56 pld [r0, #64] 57 movt ip, #0x0101 58#else 59 ldr ip, =0x01010101 60 pld [r0, #64] 61#endif 62 63 @ Loop searching for EOS, 8 bytes at a time. 64 @ Subtracting (unsigned saturating) from 1 for any byte means that 65 @ we get 1 for any byte that was originally zero and 0 otherwise. 66 @ Therefore we consider the lsb of each byte the "found" bit. 67 .balign 16 682: uqsub8 r2, ip, r2 @ Find EOS 69 uqsub8 r3, ip, r3 70 pld [r0, #128] @ Prefetch 2 lines ahead 71 orrs r3, r3, r2 @ Combine the two words 72 it eq 73 ldrdeq r2, r3, [r0], #8 74 beq 2b 75 76 @ Found something. Disambiguate between first and second words. 77 @ Adjust r0 to point to the word containing the match. 78 @ Adjust r2 to the found bits for the word containing the match. 79 cmp r2, #0 80 sub r0, r0, #4 81 ite eq 82 moveq r2, r3 83 subne r0, r0, #4 84 85 @ Find the bit-offset of the match within the word. Note that the 86 @ bit result from clz will be 7 higher than "true", but we'll 87 @ immediately discard those bits converting to a byte offset. 88#ifdef __ARMEL__ 89 rev r2, r2 @ For LE, count from the little end 90#endif 91 clz r2, r2 92 add r0, r0, r2, lsr #3 @ Adjust the pointer to the found byte 9399: 94 sub r0, r0, r1 @ Subtract input to compute length 95 bx lr 96 97END (strlen) 98 99libc_hidden_builtin_def (strlen) 100