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