1 /* strcat(dest, src) -- Append SRC on the end of DEST.
3 Copyright (C) 1994-1997,2000,2003,2005 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. */
38 cfi_adjust_cfa_offset (4)
42 CHECK_BOUNDS_LOW (%edx, DEST(%esp))
43 CHECK_BOUNDS_LOW (%ecx, SRC(%esp))
45 testb $0xff, (%ecx) /* Is source string empty? */
46 jz L(8) /* yes => return */
48 /* Test the first bytes separately until destination is aligned. */
49 testl $3, %edx /* destination pointer aligned? */
50 jz L(1) /* yes => begin scan loop */
51 testb $0xff, (%edx) /* is end of string? */
52 jz L(2) /* yes => start appending */
53 incl %edx /* increment source pointer */
55 testl $3, %edx /* destination pointer aligned? */
56 jz L(1) /* yes => begin scan loop */
57 testb $0xff, (%edx) /* is end of string? */
58 jz L(2) /* yes => start appending */
59 incl %edx /* increment source pointer */
61 testl $3, %edx /* destination pointer aligned? */
62 jz L(1) /* yes => begin scan loop */
63 testb $0xff, (%edx) /* is end of string? */
64 jz L(2) /* yes => start appending */
65 incl %edx /* increment source pointer */
67 /* Now we are aligned. Begin scan loop. */
70 cfi_rel_offset (edi, 0)
73 L(4): addl $16,%edx /* increment destination pointer for round */
75 L(1): movl (%edx), %eax /* get word (= 4 bytes) in question */
76 movl $0xfefefeff, %edi /* magic value */
78 /* If you compare this with the algorithm in memchr.S you will
79 notice that here is an `xorl' statement missing. But you must
80 not forget that we are looking for C == 0 and `xorl $0, %eax'
83 addl %eax, %edi /* add the magic value to the word. We get
84 carry bits reported for each byte which
87 /* According to the algorithm we had to reverse the effect of the
88 XOR first and then test the overflow bits. But because the
89 following XOR would destroy the carry flag and it would (in a
90 representation with more than 32 bits) not alter then last
91 overflow, we can now test this condition. If no carry is signaled
92 no overflow must have occurred in the last byte => it was 0. */
95 /* We are only interested in carry bits that change due to the
96 previous add, so remove original bits */
97 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
99 /* Now test for the other three overflow bits. */
100 orl $0xfefefeff, %edi /* set all non-carry bits */
101 incl %edi /* add 1: if one carry bit was *not* set
102 the addition will not result in 0. */
104 /* If at least one byte of the word is C we don't get 0 in %ecx. */
107 movl 4(%edx), %eax /* get word from source */
108 movl $0xfefefeff, %edi /* magic value */
109 addl %eax, %edi /* add the magic value to the word. We get
110 carry bits reported for each byte which
112 jnc L(5) /* highest byte is C => stop copying */
113 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
114 orl $0xfefefeff, %edi /* set all non-carry bits */
115 incl %edi /* add 1: if one carry bit was *not* set
116 the addition will not result in 0. */
117 jnz L(5) /* one byte is NUL => stop copying */
119 movl 8(%edx), %eax /* get word from source */
120 movl $0xfefefeff, %edi /* magic value */
121 addl %eax, %edi /* add the magic value to the word. We get
122 carry bits reported for each byte which
124 jnc L(6) /* highest byte is C => stop copying */
125 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
126 orl $0xfefefeff, %edi /* set all non-carry bits */
127 incl %edi /* add 1: if one carry bit was *not* set
128 the addition will not result in 0. */
129 jnz L(6) /* one byte is NUL => stop copying */
131 movl 12(%edx), %eax /* get word from source */
132 movl $0xfefefeff, %edi /* magic value */
133 addl %eax, %edi /* add the magic value to the word. We get
134 carry bits reported for each byte which
136 jnc L(7) /* highest byte is C => stop copying */
137 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
138 orl $0xfefefeff, %edi /* set all non-carry bits */
139 incl %edi /* add 1: if one carry bit was *not* set
140 the addition will not result in 0. */
141 jz L(4) /* no byte is NUL => carry on copying */
143 L(7): addl $4, %edx /* adjust source pointer */
147 L(3): testb %al, %al /* is first byte NUL? */
148 jz L(2) /* yes => start copying */
149 incl %edx /* increment source pointer */
151 testb %ah, %ah /* is second byte NUL? */
152 jz L(2) /* yes => start copying */
153 incl %edx /* increment source pointer */
155 testl $0xff0000, %eax /* is third byte NUL? */
156 jz L(2) /* yes => start copying */
157 incl %edx /* increment source pointer */
159 L(2): subl %ecx, %edx /* reduce number of loop variants */
161 /* Now we have to align the source pointer. */
162 testl $3, %ecx /* pointer correctly aligned? */
163 jz L(29) /* yes => start copy loop */
164 movb (%ecx), %al /* get first byte */
165 movb %al, (%ecx,%edx) /* and store it */
166 andb %al, %al /* is byte NUL? */
167 jz L(8) /* yes => return */
168 incl %ecx /* increment pointer */
170 testl $3, %ecx /* pointer correctly aligned? */
171 jz L(29) /* yes => start copy loop */
172 movb (%ecx), %al /* get first byte */
173 movb %al, (%ecx,%edx) /* and store it */
174 andb %al, %al /* is byte NUL? */
175 jz L(8) /* yes => return */
176 incl %ecx /* increment pointer */
178 testl $3, %ecx /* pointer correctly aligned? */
179 jz L(29) /* yes => start copy loop */
180 movb (%ecx), %al /* get first byte */
181 movb %al, (%ecx,%edx) /* and store it */
182 andb %al, %al /* is byte NUL? */
183 jz L(8) /* yes => return */
184 incl %ecx /* increment pointer */
186 /* Now we are aligned. */
187 jmp L(29) /* start copy loop */
191 L(28): movl %eax, 12(%ecx,%edx)/* store word at destination */
192 addl $16, %ecx /* adjust pointer for full round */
194 L(29): movl (%ecx), %eax /* get word from source */
195 movl $0xfefefeff, %edi /* magic value */
196 addl %eax, %edi /* add the magic value to the word. We get
197 carry bits reported for each byte which
199 jnc L(9) /* highest byte is C => stop copying */
200 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
201 orl $0xfefefeff, %edi /* set all non-carry bits */
202 incl %edi /* add 1: if one carry bit was *not* set
203 the addition will not result in 0. */
204 jnz L(9) /* one byte is NUL => stop copying */
205 movl %eax, (%ecx,%edx) /* store word to destination */
207 movl 4(%ecx), %eax /* get word from source */
208 movl $0xfefefeff, %edi /* magic value */
209 addl %eax, %edi /* add the magic value to the word. We get
210 carry bits reported for each byte which
212 jnc L(91) /* highest byte is C => stop copying */
213 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
214 orl $0xfefefeff, %edi /* set all non-carry bits */
215 incl %edi /* add 1: if one carry bit was *not* set
216 the addition will not result in 0. */
217 jnz L(91) /* one byte is NUL => stop copying */
218 movl %eax, 4(%ecx,%edx) /* store word to destination */
220 movl 8(%ecx), %eax /* get word from source */
221 movl $0xfefefeff, %edi /* magic value */
222 addl %eax, %edi /* add the magic value to the word. We get
223 carry bits reported for each byte which
225 jnc L(92) /* highest byte is C => stop copying */
226 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
227 orl $0xfefefeff, %edi /* set all non-carry bits */
228 incl %edi /* add 1: if one carry bit was *not* set
229 the addition will not result in 0. */
230 jnz L(92) /* one byte is NUL => stop copying */
231 movl %eax, 8(%ecx,%edx) /* store word to destination */
233 movl 12(%ecx), %eax /* get word from source */
234 movl $0xfefefeff, %edi /* magic value */
235 addl %eax, %edi /* add the magic value to the word. We get
236 carry bits reported for each byte which
238 jnc L(93) /* highest byte is C => stop copying */
239 xorl %eax, %edi /* ((word^charmask)+magic)^(word^charmask) */
240 orl $0xfefefeff, %edi /* set all non-carry bits */
241 incl %edi /* add 1: if one carry bit was *not* set
242 the addition will not result in 0. */
243 jz L(28) /* no is NUL => carry on copying */
245 L(93): addl $4, %ecx /* adjust pointer */
249 L(9): movb %al, (%ecx,%edx) /* store first byte of last word */
250 orb %al, %al /* is it NUL? */
251 jz L(8) /* yes => return */
253 movb %ah, 1(%ecx,%edx) /* store second byte of last word */
254 orb %ah, %ah /* is it NUL? */
255 jz L(8) /* yes => return */
257 shrl $16, %eax /* make upper bytes accessible */
258 movb %al, 2(%ecx,%edx) /* store third byte of last word */
259 orb %al, %al /* is it NUL? */
260 jz L(8) /* yes => return */
262 movb %ah, 3(%ecx,%edx) /* store fourth byte of last word */
264 L(8): /* GKM FIXME: check high bounds */
265 movl DEST(%esp), %eax /* start address of destination is result */
266 RETURN_BOUNDED_POINTER (DEST(%esp))
267 popl %edi /* restore saved register */
268 cfi_adjust_cfa_offset (-4)
273 END (BP_SYM (strcat))
274 libc_hidden_builtin_def (strcat)