1 /* strcat(dest, src) -- Append SRC on the end of DEST.
3 Copyright (C) 1994,1995,1996,1997,2000,2003 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, write to the Free
20 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 #include "asm-syntax.h"
28 #define PARMS LINKAGE+4 /* space for 1 saved reg */
30 #define DEST RTN+RTN_SIZE
31 #define SRC DEST+PTR_SIZE
34 ENTRY (BP_SYM (strcat))
37 pushl %edi /* Save callee-safe register. */
41 CHECK_BOUNDS_LOW (%edx, DEST(%esp))
42 CHECK_BOUNDS_LOW (%ecx, SRC(%esp))
44 testb $0xff, (%ecx) /* Is source string empty? */
45 jz L(8) /* yes => return */
47 /* Test the first bytes separately until destination is aligned. */
48 testl $3, %edx /* destination pointer aligned? */
49 jz L(1) /* yes => begin scan loop */
50 testb $0xff, (%edx) /* is end of string? */
51 jz L(2) /* yes => start appending */
52 incl %edx /* increment source pointer */
54 testl $3, %edx /* destination pointer aligned? */
55 jz L(1) /* yes => begin scan loop */
56 testb $0xff, (%edx) /* is end of string? */
57 jz L(2) /* yes => start appending */
58 incl %edx /* increment source pointer */
60 testl $3, %edx /* destination pointer aligned? */
61 jz L(1) /* yes => begin scan loop */
62 testb $0xff, (%edx) /* is end of string? */
63 jz L(2) /* yes => start appending */
64 incl %edx /* increment source pointer */
66 /* Now we are aligned. Begin scan loop. */
71 L(4): addl $16,%edx /* increment destination pointer for round */
73 L(1): movl (%edx), %eax /* get word (= 4 bytes) in question */
74 movl $0xfefefeff, %edi /* magic value */
76 /* If you compare this with the algorithm in memchr.S you will
77 notice that here is an `xorl' statement missing. But you must
78 not forget that we are looking for C == 0 and `xorl $0, %eax'
81 addl %eax, %edi /* add the magic value to the word. We get
82 carry bits reported for each byte which
85 /* According to the algorithm we had to reverse the effect of the
86 XOR first and then test the overflow bits. But because the
87 following XOR would destroy the carry flag and it would (in a
88 representation with more than 32 bits) not alter then last
89 overflow, we can now test this condition. If no carry is signaled
90 no overflow must have occurred in the last byte => it was 0. */
93 /* We are only interested in carry bits that change due to the
94 previous add, so remove original bits */
95 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
97 /* Now test for the other three overflow bits. */
98 orl $0xfefefeff, %edi /* set all non-carry bits */
99 incl %edi /* add 1: if one carry bit was *not* set
100 the addition will not result in 0. */
102 /* If at least one byte of the word is C we don't get 0 in %ecx. */
105 movl 4(%edx), %eax /* get word from source */
106 movl $0xfefefeff, %edi /* magic value */
107 addl %eax, %edi /* add the magic value to the word. We get
108 carry bits reported for each byte which
110 jnc L(5) /* highest byte is C => stop copying */
111 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
112 orl $0xfefefeff, %edi /* set all non-carry bits */
113 incl %edi /* add 1: if one carry bit was *not* set
114 the addition will not result in 0. */
115 jnz L(5) /* one byte is NUL => stop copying */
117 movl 8(%edx), %eax /* get word from source */
118 movl $0xfefefeff, %edi /* magic value */
119 addl %eax, %edi /* add the magic value to the word. We get
120 carry bits reported for each byte which
122 jnc L(6) /* highest byte is C => stop copying */
123 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
124 orl $0xfefefeff, %edi /* set all non-carry bits */
125 incl %edi /* add 1: if one carry bit was *not* set
126 the addition will not result in 0. */
127 jnz L(6) /* one byte is NUL => stop copying */
129 movl 12(%edx), %eax /* get word from source */
130 movl $0xfefefeff, %edi /* magic value */
131 addl %eax, %edi /* add the magic value to the word. We get
132 carry bits reported for each byte which
134 jnc L(7) /* highest byte is C => stop copying */
135 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
136 orl $0xfefefeff, %edi /* set all non-carry bits */
137 incl %edi /* add 1: if one carry bit was *not* set
138 the addition will not result in 0. */
139 jz L(4) /* no byte is NUL => carry on copying */
141 L(7): addl $4, %edx /* adjust source pointer */
145 L(3): testb %al, %al /* is first byte NUL? */
146 jz L(2) /* yes => start copying */
147 incl %edx /* increment source pointer */
149 testb %ah, %ah /* is second byte NUL? */
150 jz L(2) /* yes => start copying */
151 incl %edx /* increment source pointer */
153 testl $0xff0000, %eax /* is third byte NUL? */
154 jz L(2) /* yes => start copying */
155 incl %edx /* increment source pointer */
157 L(2): subl %ecx, %edx /* reduce number of loop variants */
159 /* Now we have to align the source pointer. */
160 testl $3, %ecx /* pointer correctly aligned? */
161 jz L(29) /* yes => start copy loop */
162 movb (%ecx), %al /* get first byte */
163 movb %al, (%ecx,%edx) /* and store it */
164 andb %al, %al /* is byte NUL? */
165 jz L(8) /* yes => return */
166 incl %ecx /* increment pointer */
168 testl $3, %ecx /* pointer correctly aligned? */
169 jz L(29) /* yes => start copy loop */
170 movb (%ecx), %al /* get first byte */
171 movb %al, (%ecx,%edx) /* and store it */
172 andb %al, %al /* is byte NUL? */
173 jz L(8) /* yes => return */
174 incl %ecx /* increment pointer */
176 testl $3, %ecx /* pointer correctly aligned? */
177 jz L(29) /* yes => start copy loop */
178 movb (%ecx), %al /* get first byte */
179 movb %al, (%ecx,%edx) /* and store it */
180 andb %al, %al /* is byte NUL? */
181 jz L(8) /* yes => return */
182 incl %ecx /* increment pointer */
184 /* Now we are aligned. */
185 jmp L(29) /* start copy loop */
189 L(28): movl %eax, 12(%ecx,%edx)/* store word at destination */
190 addl $16, %ecx /* adjust pointer for full round */
192 L(29): movl (%ecx), %eax /* get word from source */
193 movl $0xfefefeff, %edi /* magic value */
194 addl %eax, %edi /* add the magic value to the word. We get
195 carry bits reported for each byte which
197 jnc L(9) /* highest byte is C => stop copying */
198 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
199 orl $0xfefefeff, %edi /* set all non-carry bits */
200 incl %edi /* add 1: if one carry bit was *not* set
201 the addition will not result in 0. */
202 jnz L(9) /* one byte is NUL => stop copying */
203 movl %eax, (%ecx,%edx) /* store word to destination */
205 movl 4(%ecx), %eax /* get word from source */
206 movl $0xfefefeff, %edi /* magic value */
207 addl %eax, %edi /* add the magic value to the word. We get
208 carry bits reported for each byte which
210 jnc L(91) /* highest byte is C => stop copying */
211 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
212 orl $0xfefefeff, %edi /* set all non-carry bits */
213 incl %edi /* add 1: if one carry bit was *not* set
214 the addition will not result in 0. */
215 jnz L(91) /* one byte is NUL => stop copying */
216 movl %eax, 4(%ecx,%edx) /* store word to destination */
218 movl 8(%ecx), %eax /* get word from source */
219 movl $0xfefefeff, %edi /* magic value */
220 addl %eax, %edi /* add the magic value to the word. We get
221 carry bits reported for each byte which
223 jnc L(92) /* highest byte is C => stop copying */
224 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
225 orl $0xfefefeff, %edi /* set all non-carry bits */
226 incl %edi /* add 1: if one carry bit was *not* set
227 the addition will not result in 0. */
228 jnz L(92) /* one byte is NUL => stop copying */
229 movl %eax, 8(%ecx,%edx) /* store word to destination */
231 movl 12(%ecx), %eax /* get word from source */
232 movl $0xfefefeff, %edi /* magic value */
233 addl %eax, %edi /* add the magic value to the word. We get
234 carry bits reported for each byte which
236 jnc L(93) /* highest byte is C => stop copying */
237 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
238 orl $0xfefefeff, %edi /* set all non-carry bits */
239 incl %edi /* add 1: if one carry bit was *not* set
240 the addition will not result in 0. */
241 jz L(28) /* no is NUL => carry on copying */
243 L(93): addl $4, %ecx /* adjust pointer */
247 L(9): movb %al, (%ecx,%edx) /* store first byte of last word */
248 orb %al, %al /* is it NUL? */
249 jz L(8) /* yes => return */
251 movb %ah, 1(%ecx,%edx) /* store second byte of last word */
252 orb %ah, %ah /* is it NUL? */
253 jz L(8) /* yes => return */
255 shrl $16, %eax /* make upper bytes accessible */
256 movb %al, 2(%ecx,%edx) /* store third byte of last word */
257 orb %al, %al /* is it NUL? */
258 jz L(8) /* yes => return */
260 movb %ah, 3(%ecx,%edx) /* store fourth byte of last word */
262 L(8): /* GKM FIXME: check high bounds */
263 movl DEST(%esp), %eax /* start address of destination is result */
264 RETURN_BOUNDED_POINTER (DEST(%esp))
265 popl %edi /* restore saved register */
269 END (BP_SYM (strcat))
270 libc_hidden_builtin_def (strcat)