Update copyright notices with scripts/update-copyrights
[glibc.git] / sysdeps / i386 / i486 / strcat.S
blobaa8539d95a4fbcac9f96dcc3057876ddfe4a0b55
1 /* strcat(dest, src) -- Append SRC on the end of DEST.
2    For Intel 80x86, x>=4.
3    Copyright (C) 1994-2014 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/>.  */
22 #include <sysdep.h>
23 #include "asm-syntax.h"
25 #define PARMS   4+4     /* space for 1 saved reg */
26 #define RTN     PARMS
27 #define DEST    RTN
28 #define SRC     DEST+4
30         .text
31 ENTRY (strcat)
33         pushl %edi              /* Save callee-safe register.  */
34         cfi_adjust_cfa_offset (4)
36         movl DEST(%esp), %edx
37         movl SRC(%esp), %ecx
39         testb $0xff, (%ecx)     /* Is source string empty? */
40         jz L(8)                 /* yes => return */
42         /* Test the first bytes separately until destination is aligned.  */
43         testl $3, %edx          /* destination pointer aligned? */
44         jz L(1)                 /* yes => begin scan loop */
45         testb $0xff, (%edx)     /* is end of string? */
46         jz L(2)                 /* yes => start appending */
47         incl %edx               /* increment source pointer */
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         /* Now we are aligned.  Begin scan loop.  */
62         jmp L(1)
64         cfi_rel_offset (edi, 0)
65         ALIGN(4)
67 L(4):   addl $16,%edx           /* increment destination pointer for round */
69 L(1):   movl (%edx), %eax       /* get word (= 4 bytes) in question */
70         movl $0xfefefeff, %edi  /* magic value */
72         /* If you compare this with the algorithm in memchr.S you will
73            notice that here is an `xorl' statement missing.  But you must
74            not forget that we are looking for C == 0 and `xorl $0, %eax'
75            is a no-op.  */
77         addl %eax, %edi         /* add the magic value to the word.  We get
78                                    carry bits reported for each byte which
79                                    is *not* 0 */
81         /* According to the algorithm we had to reverse the effect of the
82            XOR first and then test the overflow bits.  But because the
83            following XOR would destroy the carry flag and it would (in a
84            representation with more than 32 bits) not alter then last
85            overflow, we can now test this condition.  If no carry is signaled
86            no overflow must have occurred in the last byte => it was 0. */
87         jnc L(3)
89         /* We are only interested in carry bits that change due to the
90            previous add, so remove original bits */
91         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
93         /* Now test for the other three overflow bits.  */
94         orl $0xfefefeff, %edi   /* set all non-carry bits */
95         incl %edi               /* add 1: if one carry bit was *not* set
96                                    the addition will not result in 0.  */
98         /* If at least one byte of the word is C we don't get 0 in %ecx.  */
99         jnz L(3)
101         movl 4(%edx), %eax      /* get word from source */
102         movl $0xfefefeff, %edi  /* magic value */
103         addl %eax, %edi         /* add the magic value to the word.  We get
104                                    carry bits reported for each byte which
105                                    is *not* 0 */
106         jnc L(5)                /* highest byte is C => stop copying */
107         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
108         orl $0xfefefeff, %edi   /* set all non-carry bits */
109         incl %edi               /* add 1: if one carry bit was *not* set
110                                    the addition will not result in 0.  */
111         jnz L(5)                /* one byte is NUL => stop copying */
113         movl 8(%edx), %eax      /* get word from source */
114         movl $0xfefefeff, %edi  /* magic value */
115         addl %eax, %edi         /* add the magic value to the word.  We get
116                                    carry bits reported for each byte which
117                                    is *not* 0 */
118         jnc L(6)                /* highest byte is C => stop copying */
119         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
120         orl $0xfefefeff, %edi   /* set all non-carry bits */
121         incl %edi               /* add 1: if one carry bit was *not* set
122                                    the addition will not result in 0.  */
123         jnz L(6)                /* one byte is NUL => stop copying */
125         movl 12(%edx), %eax     /* get word from source */
126         movl $0xfefefeff, %edi  /* magic value */
127         addl %eax, %edi         /* add the magic value to the word.  We get
128                                    carry bits reported for each byte which
129                                    is *not* 0 */
130         jnc L(7)                /* highest byte is C => stop copying */
131         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
132         orl $0xfefefeff, %edi   /* set all non-carry bits */
133         incl %edi               /* add 1: if one carry bit was *not* set
134                                    the addition will not result in 0.  */
135         jz L(4)                 /* no byte is NUL => carry on copying */
137 L(7):   addl $4, %edx           /* adjust source pointer */
138 L(6):   addl $4, %edx
139 L(5):   addl $4, %edx
141 L(3):   testb %al, %al          /* is first byte NUL? */
142         jz L(2)                 /* yes => start copying */
143         incl %edx               /* increment source pointer */
145         testb %ah, %ah          /* is second byte NUL? */
146         jz L(2)                 /* yes => start copying */
147         incl %edx               /* increment source pointer */
149         testl $0xff0000, %eax   /* is third byte NUL? */
150         jz L(2)                 /* yes => start copying */
151         incl %edx               /* increment source pointer */
153 L(2):   subl %ecx, %edx         /* reduce number of loop variants */
155         /* Now we have to align the source pointer.  */
156         testl $3, %ecx          /* pointer correctly aligned? */
157         jz L(29)                /* yes => start copy loop */
158         movb (%ecx), %al        /* get first byte */
159         movb %al, (%ecx,%edx)   /* and store it */
160         andb %al, %al           /* is byte NUL? */
161         jz L(8)                 /* yes => return */
162         incl %ecx               /* increment pointer */
164         testl $3, %ecx          /* pointer correctly aligned? */
165         jz L(29)                /* yes => start copy loop */
166         movb (%ecx), %al        /* get first byte */
167         movb %al, (%ecx,%edx)   /* and store it */
168         andb %al, %al           /* is byte NUL? */
169         jz L(8)                 /* yes => return */
170         incl %ecx               /* increment pointer */
172         testl $3, %ecx          /* pointer correctly aligned? */
173         jz L(29)                /* yes => start copy loop */
174         movb (%ecx), %al        /* get first byte */
175         movb %al, (%ecx,%edx)   /* and store it */
176         andb %al, %al           /* is byte NUL? */
177         jz L(8)                 /* yes => return */
178         incl %ecx               /* increment pointer */
180         /* Now we are aligned.  */
181         jmp L(29)               /* start copy loop */
183         ALIGN(4)
185 L(28):  movl %eax, 12(%ecx,%edx)/* store word at destination */
186         addl $16, %ecx          /* adjust pointer for full round */
188 L(29):  movl (%ecx), %eax       /* get word from source */
189         movl $0xfefefeff, %edi  /* magic value */
190         addl %eax, %edi         /* add the magic value to the word.  We get
191                                    carry bits reported for each byte which
192                                    is *not* 0 */
193         jnc L(9)                /* highest byte is C => stop copying */
194         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
195         orl $0xfefefeff, %edi   /* set all non-carry bits */
196         incl %edi               /* add 1: if one carry bit was *not* set
197                                    the addition will not result in 0.  */
198         jnz L(9)                /* one byte is NUL => stop copying */
199         movl %eax, (%ecx,%edx)  /* store word to destination */
201         movl 4(%ecx), %eax      /* get word from source */
202         movl $0xfefefeff, %edi  /* magic value */
203         addl %eax, %edi         /* add the magic value to the word.  We get
204                                    carry bits reported for each byte which
205                                    is *not* 0 */
206         jnc L(91)               /* highest byte is C => stop copying */
207         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
208         orl $0xfefefeff, %edi   /* set all non-carry bits */
209         incl %edi               /* add 1: if one carry bit was *not* set
210                                    the addition will not result in 0.  */
211         jnz L(91)               /* one byte is NUL => stop copying */
212         movl %eax, 4(%ecx,%edx) /* store word to destination */
214         movl 8(%ecx), %eax      /* get word from source */
215         movl $0xfefefeff, %edi  /* magic value */
216         addl %eax, %edi         /* add the magic value to the word.  We get
217                                    carry bits reported for each byte which
218                                    is *not* 0 */
219         jnc L(92)               /* highest byte is C => stop copying */
220         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
221         orl $0xfefefeff, %edi   /* set all non-carry bits */
222         incl %edi               /* add 1: if one carry bit was *not* set
223                                    the addition will not result in 0.  */
224         jnz L(92)               /* one byte is NUL => stop copying */
225         movl %eax, 8(%ecx,%edx) /* store word to destination */
227         movl 12(%ecx), %eax     /* get word from source */
228         movl $0xfefefeff, %edi  /* magic value */
229         addl %eax, %edi         /* add the magic value to the word.  We get
230                                    carry bits reported for each byte which
231                                    is *not* 0 */
232         jnc L(93)               /* highest byte is C => stop copying */
233         xorl %eax, %edi         /* ((word^charmask)+magic)^(word^charmask) */
234         orl $0xfefefeff, %edi   /* set all non-carry bits */
235         incl %edi               /* add 1: if one carry bit was *not* set
236                                    the addition will not result in 0.  */
237         jz L(28)                /* no is NUL => carry on copying */
239 L(93):  addl $4, %ecx           /* adjust pointer */
240 L(92):  addl $4, %ecx
241 L(91):  addl $4, %ecx
243 L(9):   movb %al, (%ecx,%edx)   /* store first byte of last word */
244         orb %al, %al            /* is it NUL? */
245         jz L(8)                 /* yes => return */
247         movb %ah, 1(%ecx,%edx)  /* store second byte of last word */
248         orb %ah, %ah            /* is it NUL? */
249         jz L(8)                 /* yes => return */
251         shrl $16, %eax          /* make upper bytes accessible */
252         movb %al, 2(%ecx,%edx)  /* store third byte of last word */
253         orb %al, %al            /* is it NUL? */
254         jz L(8)                 /* yes => return */
256         movb %ah, 3(%ecx,%edx)  /* store fourth byte of last word */
258 L(8):   movl DEST(%esp), %eax   /* start address of destination is result */
259         popl %edi               /* restore saved register */
260         cfi_adjust_cfa_offset (-4)
261         cfi_restore (edi)
263         ret
264 END (strcat)
265 libc_hidden_builtin_def (strcat)