(CFLAGS-tst-align.c): Add -mpreferred-stack-boundary=4.
[glibc.git] / sysdeps / i386 / i486 / strcat.S
blob7d8279fe1439064733463cc61c5c26d509157812
1 /* strcat(dest, src) -- Append SRC on the end of DEST.
2    For Intel 80x86, x>=4.
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
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.  */
39         movl DEST(%esp), %edx
40         movl SRC(%esp), %ecx
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.  */
67         jmp L(1)
69         ALIGN(4)
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'
79            is a no-op.  */
81         addl %eax, %edi         /* add the magic value to the word.  We get
82                                    carry bits reported for each byte which
83                                    is *not* 0 */
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. */
91         jnc L(3)
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.  */
103         jnz L(3)
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
109                                    is *not* 0 */
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
121                                    is *not* 0 */
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
133                                    is *not* 0 */
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 */
142 L(6):   addl $4, %edx
143 L(5):   addl $4, %edx
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 */
187         ALIGN(4)
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
196                                    is *not* 0 */
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
209                                    is *not* 0 */
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
222                                    is *not* 0 */
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
235                                    is *not* 0 */
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 */
244 L(92):  addl $4, %ecx
245 L(91):  addl $4, %ecx
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 */
267         LEAVE
268         RET_PTR
269 END (BP_SYM (strcat))
270 libc_hidden_builtin_def (strcat)