1/* strcpy -- copy 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/* Endian independent macros for shifting bytes within registers. */ 22#ifdef __ARMEB__ 23#define lsh_gt lsr 24#define lsh_ls lsl 25#else 26#define lsh_gt lsl 27#define lsh_ls lsr 28#endif 29 30 .syntax unified 31 .text 32 33ENTRY (__stpcpy) 34 @ Signal stpcpy with NULL in IP. 35 mov ip, #0 36 b 0f 37END (__stpcpy) 38 39weak_alias (__stpcpy, stpcpy) 40libc_hidden_def (__stpcpy) 41libc_hidden_builtin_def (stpcpy) 42 43ENTRY (strcpy) 44 @ Signal strcpy with DEST in IP. 45 mov ip, r0 460: 47 pld [r0, #0] 48 pld [r1, #0] 49 50 @ To cater to long strings, we want 8 byte alignment in the source. 51 @ To cater to small strings, we don't want to start that right away. 52 @ Loop up to 16 times, less whatever it takes to reach alignment. 53 and r3, r1, #7 54 rsb r3, r3, #16 55 56 @ Loop until we find ... 571: ldrb r2, [r1], #1 58 subs r3, r3, #1 @ ... the alignment point 59 strb r2, [r0], #1 60 it ne 61 cmpne r2, #0 @ ... or EOS 62 bne 1b 63 64 @ Disambiguate the exit possibilites above 65 cmp r2, #0 @ Found EOS 66 beq .Lreturn 67 68 @ Load the next two words asap 69 ldrd r2, r3, [r1], #8 70 pld [r0, #64] 71 pld [r1, #64] 72 73 @ For longer strings, we actaully need a stack frame. 74 push { r4, r5, r6, r7 } 75 cfi_adjust_cfa_offset (16) 76 cfi_rel_offset (r4, 0) 77 cfi_rel_offset (r5, 4) 78 cfi_rel_offset (r6, 8) 79 cfi_rel_offset (r7, 12) 80 81 @ Subtracting (unsigned saturating) from 1 for any byte means result 82 @ of 1 for any byte that was originally zero and 0 otherwise. 83 @ Therefore we consider the lsb of each byte the "found" bit. 84#ifdef ARCH_HAS_T2 85 movw r7, #0x0101 86 tst r0, #3 @ Test alignment of DEST 87 movt r7, #0x0101 88#else 89 ldr r7, =0x01010101 90 tst r0, #3 91#endif 92 bne .Lunaligned 93 94 @ So now source (r1) is aligned to 8, and dest (r0) is aligned to 4. 95 @ Loop, reading 8 bytes at a time, searching for EOS. 96 .balign 16 972: uqsub8 r4, r7, r2 @ Find EOS 98 uqsub8 r5, r7, r3 99 pld [r1, #128] 100 cmp r4, #0 @ EOS in first word? 101 pld [r0, #128] 102 bne 3f 103 str r2, [r0], #4 104 cmp r5, #0 @ EOS in second word? 105 bne 4f 106 str r3, [r0], #4 107 ldrd r2, r3, [r1], #8 108 b 2b 109 1103: sub r1, r1, #4 @ backup to first word 1114: sub r1, r1, #4 @ backup to second word 112 113 @ ... then finish up any tail a byte at a time. 114 @ Note that we generally back up and re-read source bytes, 115 @ but we'll not re-write dest bytes. 116.Lbyte_loop: 117 ldrb r2, [r1], #1 118 cmp r2, #0 119 strb r2, [r0], #1 120 bne .Lbyte_loop 121 122 pop { r4, r5, r6, r7 } 123 cfi_remember_state 124 cfi_adjust_cfa_offset (-16) 125 cfi_restore (r4) 126 cfi_restore (r5) 127 cfi_restore (r6) 128 cfi_restore (r7) 129 130.Lreturn: 131 cmp ip, #0 @ Was this strcpy or stpcpy? 132 ite eq 133 subeq r0, r0, #1 @ stpcpy: undo post-inc from store 134 movne r0, ip @ strcpy: return original dest 135 bx lr 136 137.Lunaligned: 138 cfi_restore_state 139 @ Here, source is aligned to 8, but the destination is not word 140 @ aligned. Therefore we have to shift the data in order to be 141 @ able to perform aligned word stores. 142 143 @ Find out which misalignment we're dealing with. 144 tst r0, #1 145 beq .Lunaligned2 146 tst r0, #2 147 bne .Lunaligned3 148 @ Fallthru to .Lunaligned1. 149 150.macro unaligned_copy unalign 151 @ Prologue to unaligned loop. Seed shifted non-zero bytes. 152 uqsub8 r4, r7, r2 @ Find EOS 153 uqsub8 r5, r7, r3 154 cmp r4, #0 @ EOS in first word? 155 it ne 156 subne r1, r1, #8 157 bne .Lbyte_loop 158#ifdef __ARMEB__ 159 rev r2, r2 @ Byte stores below need LE data 160#endif 161 @ Store a few bytes from the first word. 162 @ At the same time we align r0 and shift out bytes from r2. 163.rept 4-\unalign 164 strb r2, [r0], #1 165 lsr r2, r2, #8 166.endr 167#ifdef __ARMEB__ 168 rev r2, r2 @ Undo previous rev 169#endif 170 @ Rotated unaligned copy loop. The tail of the prologue is 171 @ shared with the loop itself. 172 .balign 8 1731: cmp r5, #0 @ EOS in second word? 174 bne 4f 175 @ Combine first and second words 176 orr r2, r2, r3, lsh_gt #(\unalign*8) 177 @ Save leftover bytes from the two words 178 lsh_ls r6, r3, #((4-\unalign)*8) 179 str r2, [r0], #4 180 @ The "real" start of the unaligned copy loop. 181 ldrd r2, r3, [r1], #8 @ Load 8 more bytes 182 uqsub8 r4, r7, r2 @ Find EOS 183 pld [r1, #128] 184 uqsub8 r5, r7, r3 185 pld [r0, #128] 186 cmp r4, #0 @ EOS in first word? 187 bne 3f 188 @ Combine the leftover and the first word 189 orr r6, r6, r2, lsh_gt #(\unalign*8) 190 @ Discard used bytes from the first word. 191 lsh_ls r2, r2, #((4-\unalign)*8) 192 str r6, [r0], #4 193 b 1b 194 @ Found EOS in one of the words; adjust backward 1953: sub r1, r1, #4 196 mov r2, r6 1974: sub r1, r1, #4 198 @ And store the remaining bytes from the leftover 199#ifdef __ARMEB__ 200 rev r2, r2 201#endif 202.rept \unalign 203 strb r2, [r0], #1 204 lsr r2, r2, #8 205.endr 206 b .Lbyte_loop 207.endm 208 209.Lunaligned1: 210 unaligned_copy 1 211.Lunaligned2: 212 unaligned_copy 2 213.Lunaligned3: 214 unaligned_copy 3 215 216END (strcpy) 217 218libc_hidden_builtin_def (strcpy) 219