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