1/* strrchr -- find the last occurence of C in a nul-terminated string 2 Copyright (C) 2013-2022 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 (strrchr) 25 @ r0 = start of string 26 @ r1 = character to match 27 @ returns NULL for no match, or a pointer to the match 28 29 mov r3, r0 30 mov r0, #0 31 uxtb r1, r1 32 33 @ Loop a few times until we're aligned. 34 tst r3, #7 35 beq 2f 361: ldrb r2, [r3], #1 37 cmp r2, r1 @ Find the character 38 it eq 39 subeq r0, r3, #1 40 cmp r2, #0 @ Find EOS 41 it eq 42 bxeq lr 43 tst r3, #7 @ Find the aligment point 44 bne 1b 45 46 @ So now we're aligned. Now we actually need a stack frame. 472: push { r4, r5, r6, r7 } 48 cfi_adjust_cfa_offset (16) 49 cfi_rel_offset (r4, 0) 50 cfi_rel_offset (r5, 4) 51 cfi_rel_offset (r6, 8) 52 cfi_rel_offset (r7, 12) 53 54 orr r1, r1, r1, lsl #8 @ Replicate C to all bytes 55#ifdef ARCH_HAS_T2 56 movw ip, #0x0101 57 movt ip, #0x0101 58#else 59 ldr ip, =0x01010101 60#endif 61 orr r1, r1, r1, lsl #16 62 mov r2, #0 @ No found bits yet 63 64 @ Loop searching for EOS and C, 8 bytes at a time. 65 @ Any time we find a match in a word, we copy the address of 66 @ the word to r0, and the found bits to r2. 673: ldrd r4, r5, [r3], #8 68 @ Subtracting (unsigned saturating) from 1 means result of 1 for 69 @ any byte that was originally zero and 0 otherwise. Therefore 70 @ we consider the lsb of each byte the "found" bit. 71 uqsub8 r6, ip, r4 @ Find EOS 72 uqsub8 r7, ip, r5 73 eor r4, r4, r1 @ Convert C bytes to 0 74 eor r5, r5, r1 75 uqsub8 r4, ip, r4 @ Find C 76 uqsub8 r5, ip, r5 77 cmp r6, #0 @ Found EOS, first word 78 bne 4f 79 cmp r4, #0 @ Handle C, first word 80 itt ne 81 subne r0, r3, #8 82 movne r2, r4 83 cmp r7, #0 @ Found EOS, second word 84 bne 5f 85 cmp r5, #0 @ Handle C, second word 86 itt ne 87 subne r0, r3, #4 88 movne r2, r5 89 b 3b 90 91 @ Found EOS in second word; fold to first word. 925: add r3, r3, #4 @ Dec pointer to 2nd word, with below 93 mov r4, r5 @ Overwrite first word C found 94 mov r6, r7 @ Overwrite first word EOS found 95 96 @ Found EOS. Zap found C after EOS. 974: sub r3, r3, #8 @ Decrement pointer to first word 98#ifdef __ARMEB__ 99 @ Byte swap to be congruent with LE, which is easier from here on. 100 rev r6, r6 @ Byte swap found EOS, 101 rev r4, r4 @ ... this found C 102 rev r2, r2 @ ... prev found C 103#endif 104 sub r7, r6, #1 @ Toggle EOS lsb and below 105 eor r6, r6, r7 @ All bits below and including lsb 106 ands r4, r4, r6 @ Zap C above EOS 107 itt ne 108 movne r2, r4 @ Copy to result, if still non-zero 109 movne r0, r3 110 111 pop { r4, r5, r6, r7 } 112 cfi_adjust_cfa_offset (-16) 113 cfi_restore (r4) 114 cfi_restore (r5) 115 cfi_restore (r6) 116 cfi_restore (r7) 117 118 @ Adjust the result pointer if we found a word containing C. 119 cmp r2, #0 120 clz r2, r2 @ Find the bit offset of the last C 121 itt ne 122 rsbne r2, r2, #32 @ Convert to a count from the right 123 addne r0, r0, r2, lsr #3 @ Convert to byte offset and add. 124 bx lr 125 126END (strrchr) 127 128weak_alias (strrchr, rindex) 129libc_hidden_builtin_def (strrchr) 130