1 /* strcat(dest, src) -- Append SRC on the end of DEST.
3 Copyright (C) 1994-2013 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5 Contributed by Ulrich Drepper <drepper@ipd.info.uni-karlsruhe.de>.
6 Optimised a little by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
8 The GNU C Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
13 The GNU C Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with the GNU C Library; if not, see
20 <http://www.gnu.org/licenses/>. */
23 #include "asm-syntax.h"
27 #define PARMS LINKAGE+4 /* space for 1 saved reg */
29 #define DEST RTN+RTN_SIZE
30 #define SRC DEST+PTR_SIZE
33 ENTRY (BP_SYM (strcat))
35 pushl %edi /* Save callee-safe register. */
36 cfi_adjust_cfa_offset (4)
41 testb $0xff, (%ecx) /* Is source string empty? */
42 jz L(8) /* yes => return */
44 /* Test the first bytes separately until destination is aligned. */
45 testl $3, %edx /* destination pointer aligned? */
46 jz L(1) /* yes => begin scan loop */
47 testb $0xff, (%edx) /* is end of string? */
48 jz L(2) /* yes => start appending */
49 incl %edx /* increment source pointer */
51 testl $3, %edx /* destination pointer aligned? */
52 jz L(1) /* yes => begin scan loop */
53 testb $0xff, (%edx) /* is end of string? */
54 jz L(2) /* yes => start appending */
55 incl %edx /* increment source pointer */
57 testl $3, %edx /* destination pointer aligned? */
58 jz L(1) /* yes => begin scan loop */
59 testb $0xff, (%edx) /* is end of string? */
60 jz L(2) /* yes => start appending */
61 incl %edx /* increment source pointer */
63 /* Now we are aligned. Begin scan loop. */
66 cfi_rel_offset (edi, 0)
69 L(4): addl $16,%edx /* increment destination pointer for round */
71 L(1): movl (%edx), %eax /* get word (= 4 bytes) in question */
72 movl $0xfefefeff, %edi /* magic value */
74 /* If you compare this with the algorithm in memchr.S you will
75 notice that here is an `xorl' statement missing. But you must
76 not forget that we are looking for C == 0 and `xorl $0, %eax'
79 addl %eax, %edi /* add the magic value to the word. We get
80 carry bits reported for each byte which
83 /* According to the algorithm we had to reverse the effect of the
84 XOR first and then test the overflow bits. But because the
85 following XOR would destroy the carry flag and it would (in a
86 representation with more than 32 bits) not alter then last
87 overflow, we can now test this condition. If no carry is signaled
88 no overflow must have occurred in the last byte => it was 0. */
91 /* We are only interested in carry bits that change due to the
92 previous add, so remove original bits */
93 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
95 /* Now test for the other three overflow bits. */
96 orl $0xfefefeff, %edi /* set all non-carry bits */
97 incl %edi /* add 1: if one carry bit was *not* set
98 the addition will not result in 0. */
100 /* If at least one byte of the word is C we don't get 0 in %ecx. */
103 movl 4(%edx), %eax /* get word from source */
104 movl $0xfefefeff, %edi /* magic value */
105 addl %eax, %edi /* add the magic value to the word. We get
106 carry bits reported for each byte which
108 jnc L(5) /* highest byte is C => stop copying */
109 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
110 orl $0xfefefeff, %edi /* set all non-carry bits */
111 incl %edi /* add 1: if one carry bit was *not* set
112 the addition will not result in 0. */
113 jnz L(5) /* one byte is NUL => stop copying */
115 movl 8(%edx), %eax /* get word from source */
116 movl $0xfefefeff, %edi /* magic value */
117 addl %eax, %edi /* add the magic value to the word. We get
118 carry bits reported for each byte which
120 jnc L(6) /* highest byte is C => stop copying */
121 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
122 orl $0xfefefeff, %edi /* set all non-carry bits */
123 incl %edi /* add 1: if one carry bit was *not* set
124 the addition will not result in 0. */
125 jnz L(6) /* one byte is NUL => stop copying */
127 movl 12(%edx), %eax /* get word from source */
128 movl $0xfefefeff, %edi /* magic value */
129 addl %eax, %edi /* add the magic value to the word. We get
130 carry bits reported for each byte which
132 jnc L(7) /* highest byte is C => stop copying */
133 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
134 orl $0xfefefeff, %edi /* set all non-carry bits */
135 incl %edi /* add 1: if one carry bit was *not* set
136 the addition will not result in 0. */
137 jz L(4) /* no byte is NUL => carry on copying */
139 L(7): addl $4, %edx /* adjust source pointer */
143 L(3): testb %al, %al /* is first byte NUL? */
144 jz L(2) /* yes => start copying */
145 incl %edx /* increment source pointer */
147 testb %ah, %ah /* is second byte NUL? */
148 jz L(2) /* yes => start copying */
149 incl %edx /* increment source pointer */
151 testl $0xff0000, %eax /* is third byte NUL? */
152 jz L(2) /* yes => start copying */
153 incl %edx /* increment source pointer */
155 L(2): subl %ecx, %edx /* reduce number of loop variants */
157 /* Now we have to align the source pointer. */
158 testl $3, %ecx /* pointer correctly aligned? */
159 jz L(29) /* yes => start copy loop */
160 movb (%ecx), %al /* get first byte */
161 movb %al, (%ecx,%edx) /* and store it */
162 andb %al, %al /* is byte NUL? */
163 jz L(8) /* yes => return */
164 incl %ecx /* increment pointer */
166 testl $3, %ecx /* pointer correctly aligned? */
167 jz L(29) /* yes => start copy loop */
168 movb (%ecx), %al /* get first byte */
169 movb %al, (%ecx,%edx) /* and store it */
170 andb %al, %al /* is byte NUL? */
171 jz L(8) /* yes => return */
172 incl %ecx /* increment pointer */
174 testl $3, %ecx /* pointer correctly aligned? */
175 jz L(29) /* yes => start copy loop */
176 movb (%ecx), %al /* get first byte */
177 movb %al, (%ecx,%edx) /* and store it */
178 andb %al, %al /* is byte NUL? */
179 jz L(8) /* yes => return */
180 incl %ecx /* increment pointer */
182 /* Now we are aligned. */
183 jmp L(29) /* start copy loop */
187 L(28): movl %eax, 12(%ecx,%edx)/* store word at destination */
188 addl $16, %ecx /* adjust pointer for full round */
190 L(29): movl (%ecx), %eax /* get word from source */
191 movl $0xfefefeff, %edi /* magic value */
192 addl %eax, %edi /* add the magic value to the word. We get
193 carry bits reported for each byte which
195 jnc L(9) /* highest byte is C => stop copying */
196 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
197 orl $0xfefefeff, %edi /* set all non-carry bits */
198 incl %edi /* add 1: if one carry bit was *not* set
199 the addition will not result in 0. */
200 jnz L(9) /* one byte is NUL => stop copying */
201 movl %eax, (%ecx,%edx) /* store word to destination */
203 movl 4(%ecx), %eax /* get word from source */
204 movl $0xfefefeff, %edi /* magic value */
205 addl %eax, %edi /* add the magic value to the word. We get
206 carry bits reported for each byte which
208 jnc L(91) /* highest byte is C => stop copying */
209 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
210 orl $0xfefefeff, %edi /* set all non-carry bits */
211 incl %edi /* add 1: if one carry bit was *not* set
212 the addition will not result in 0. */
213 jnz L(91) /* one byte is NUL => stop copying */
214 movl %eax, 4(%ecx,%edx) /* store word to destination */
216 movl 8(%ecx), %eax /* get word from source */
217 movl $0xfefefeff, %edi /* magic value */
218 addl %eax, %edi /* add the magic value to the word. We get
219 carry bits reported for each byte which
221 jnc L(92) /* highest byte is C => stop copying */
222 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
223 orl $0xfefefeff, %edi /* set all non-carry bits */
224 incl %edi /* add 1: if one carry bit was *not* set
225 the addition will not result in 0. */
226 jnz L(92) /* one byte is NUL => stop copying */
227 movl %eax, 8(%ecx,%edx) /* store word to destination */
229 movl 12(%ecx), %eax /* get word from source */
230 movl $0xfefefeff, %edi /* magic value */
231 addl %eax, %edi /* add the magic value to the word. We get
232 carry bits reported for each byte which
234 jnc L(93) /* highest byte is C => stop copying */
235 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
236 orl $0xfefefeff, %edi /* set all non-carry bits */
237 incl %edi /* add 1: if one carry bit was *not* set
238 the addition will not result in 0. */
239 jz L(28) /* no is NUL => carry on copying */
241 L(93): addl $4, %ecx /* adjust pointer */
245 L(9): movb %al, (%ecx,%edx) /* store first byte of last word */
246 orb %al, %al /* is it NUL? */
247 jz L(8) /* yes => return */
249 movb %ah, 1(%ecx,%edx) /* store second byte of last word */
250 orb %ah, %ah /* is it NUL? */
251 jz L(8) /* yes => return */
253 shrl $16, %eax /* make upper bytes accessible */
254 movb %al, 2(%ecx,%edx) /* store third byte of last word */
255 orb %al, %al /* is it NUL? */
256 jz L(8) /* yes => return */
258 movb %ah, 3(%ecx,%edx) /* store fourth byte of last word */
260 L(8): /* GKM FIXME: check high bounds */
261 movl DEST(%esp), %eax /* start address of destination is result */
262 popl %edi /* restore saved register */
263 cfi_adjust_cfa_offset (-4)
267 END (BP_SYM (strcat))
268 libc_hidden_builtin_def (strcat)