1/* strcpy -- copy a nul-terminated string.
2 Copyright (C) 2013-2024 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 possibilities 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 actually 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

source code of glibc/sysdeps/arm/armv6/strcpy.S