2.9
[glibc/nacl-glibc.git] / sysdeps / i386 / i486 / strcat.S
blobec7d4c80b691e097dfdb0056a3af3b492ac98fb5
1 /* strcat(dest, src) -- Append SRC on the end of DEST.
2    For Intel 80x86, x>=4.
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
21    02111-1307 USA.  */
23 #include <sysdep.h>
24 #include "asm-syntax.h"
25 #include "bp-sym.h"
26 #include "bp-asm.h"
28 #define PARMS   LINKAGE+4       /* space for 1 saved reg */
29 #define RTN     PARMS
30 #define DEST    RTN+RTN_SIZE
31 #define SRC     DEST+PTR_SIZE
33         .text
34 ENTRY (BP_SYM (strcat))
35         ENTER
37         pushl %edi              /* Save callee-safe register.  */
38         cfi_adjust_cfa_offset (4)
40         movl DEST(%esp), %edx
41         movl SRC(%esp), %ecx
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.  */
68         jmp L(1)
70         cfi_rel_offset (edi, 0)
71         ALIGN(4)
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'
81            is a no-op.  */
83         addl %eax, %edi         /* add the magic value to the word.  We get
84                                    carry bits reported for each byte which
85                                    is *not* 0 */
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. */
93         jnc L(3)
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.  */
105         jnz L(3)
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
111                                    is *not* 0 */
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
123                                    is *not* 0 */
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
135                                    is *not* 0 */
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 */
144 L(6):   addl $4, %edx
145 L(5):   addl $4, %edx
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 */
189         ALIGN(4)
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
198                                    is *not* 0 */
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
211                                    is *not* 0 */
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
224                                    is *not* 0 */
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
237                                    is *not* 0 */
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 */
246 L(92):  addl $4, %ecx
247 L(91):  addl $4, %ecx
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)
269         cfi_restore (edi)
271         LEAVE
272         RET_PTR
273 END (BP_SYM (strcat))
274 libc_hidden_builtin_def (strcat)