]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/i386/strcat.S
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / i386 / strcat.S
CommitLineData
8f5ca04b 1/* strcat(dest, src) -- Append SRC on the end of DEST.
6d52618b 2 For Intel 80x86, x>=4.
2b778ceb 3 Copyright (C) 1994-2021 Free Software Foundation, Inc.
6d52618b
UD
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
41bdb6e2
AJ
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.
6d52618b
UD
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
41bdb6e2 16 Lesser General Public License for more details.
6d52618b 17
41bdb6e2 18 You should have received a copy of the GNU Lesser General Public
59ba27a6 19 License along with the GNU C Library; if not, see
5a82c748 20 <https://www.gnu.org/licenses/>. */
8f5ca04b
RM
21
22#include <sysdep.h>
23#include "asm-syntax.h"
24
2366713d 25#define PARMS 4+4 /* space for 1 saved reg */
3f02f778 26#define RTN PARMS
2366713d
JM
27#define DEST RTN
28#define SRC DEST+4
8f5ca04b
RM
29
30 .text
2366713d 31ENTRY (strcat)
3f02f778 32
8f5ca04b 33 pushl %edi /* Save callee-safe register. */
1ad9da69 34 cfi_adjust_cfa_offset (4)
8f5ca04b 35
3f02f778
GM
36 movl DEST(%esp), %edx
37 movl SRC(%esp), %ecx
8f5ca04b
RM
38
39 testb $0xff, (%ecx) /* Is source string empty? */
5929563f 40 jz L(8) /* yes => return */
8f5ca04b
RM
41
42 /* Test the first bytes separately until destination is aligned. */
59dd8641 43 testl $3, %edx /* destination pointer aligned? */
5929563f 44 jz L(1) /* yes => begin scan loop */
8f5ca04b 45 testb $0xff, (%edx) /* is end of string? */
5929563f 46 jz L(2) /* yes => start appending */
8f5ca04b
RM
47 incl %edx /* increment source pointer */
48
59dd8641 49 testl $3, %edx /* destination pointer aligned? */
5929563f 50 jz L(1) /* yes => begin scan loop */
8f5ca04b 51 testb $0xff, (%edx) /* is end of string? */
5929563f 52 jz L(2) /* yes => start appending */
8f5ca04b
RM
53 incl %edx /* increment source pointer */
54
59dd8641 55 testl $3, %edx /* destination pointer aligned? */
5929563f 56 jz L(1) /* yes => begin scan loop */
8f5ca04b 57 testb $0xff, (%edx) /* is end of string? */
5929563f 58 jz L(2) /* yes => start appending */
8f5ca04b
RM
59 incl %edx /* increment source pointer */
60
61 /* Now we are aligned. Begin scan loop. */
5929563f 62 jmp L(1)
8f5ca04b 63
1ad9da69 64 cfi_rel_offset (edi, 0)
8f5ca04b
RM
65 ALIGN(4)
66
5929563f 67L(4): addl $16,%edx /* increment destination pointer for round */
8f5ca04b 68
5929563f 69L(1): movl (%edx), %eax /* get word (= 4 bytes) in question */
8f5ca04b
RM
70 movl $0xfefefeff, %edi /* magic value */
71
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. */
76
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 */
80
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
6d52618b 86 no overflow must have occurred in the last byte => it was 0. */
5929563f 87 jnc L(3)
8f5ca04b
RM
88
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) */
92
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. */
97
98 /* If at least one byte of the word is C we don't get 0 in %ecx. */
5929563f 99 jnz L(3)
8f5ca04b
RM
100
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 */
5929563f 106 jnc L(5) /* highest byte is C => stop copying */
8f5ca04b
RM
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. */
5929563f 111 jnz L(5) /* one byte is NUL => stop copying */
8f5ca04b
RM
112
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 */
5929563f 118 jnc L(6) /* highest byte is C => stop copying */
8f5ca04b
RM
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. */
5929563f 123 jnz L(6) /* one byte is NUL => stop copying */
8f5ca04b
RM
124
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 */
5929563f 130 jnc L(7) /* highest byte is C => stop copying */
8f5ca04b
RM
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. */
5929563f 135 jz L(4) /* no byte is NUL => carry on copying */
8f5ca04b 136
5929563f
UD
137L(7): addl $4, %edx /* adjust source pointer */
138L(6): addl $4, %edx
139L(5): addl $4, %edx
8f5ca04b 140
5929563f
UD
141L(3): testb %al, %al /* is first byte NUL? */
142 jz L(2) /* yes => start copying */
8f5ca04b
RM
143 incl %edx /* increment source pointer */
144
145 testb %ah, %ah /* is second byte NUL? */
5929563f 146 jz L(2) /* yes => start copying */
8f5ca04b
RM
147 incl %edx /* increment source pointer */
148
149 testl $0xff0000, %eax /* is third byte NUL? */
5929563f 150 jz L(2) /* yes => start copying */
8f5ca04b
RM
151 incl %edx /* increment source pointer */
152
5929563f 153L(2): subl %ecx, %edx /* reduce number of loop variants */
8f5ca04b
RM
154
155 /* Now we have to align the source pointer. */
59dd8641 156 testl $3, %ecx /* pointer correctly aligned? */
5929563f 157 jz L(29) /* yes => start copy loop */
8f5ca04b
RM
158 movb (%ecx), %al /* get first byte */
159 movb %al, (%ecx,%edx) /* and store it */
59dd8641 160 andb %al, %al /* is byte NUL? */
5929563f 161 jz L(8) /* yes => return */
8f5ca04b
RM
162 incl %ecx /* increment pointer */
163
59dd8641 164 testl $3, %ecx /* pointer correctly aligned? */
5929563f 165 jz L(29) /* yes => start copy loop */
8f5ca04b
RM
166 movb (%ecx), %al /* get first byte */
167 movb %al, (%ecx,%edx) /* and store it */
59dd8641 168 andb %al, %al /* is byte NUL? */
5929563f 169 jz L(8) /* yes => return */
8f5ca04b
RM
170 incl %ecx /* increment pointer */
171
59dd8641 172 testl $3, %ecx /* pointer correctly aligned? */
5929563f 173 jz L(29) /* yes => start copy loop */
8f5ca04b
RM
174 movb (%ecx), %al /* get first byte */
175 movb %al, (%ecx,%edx) /* and store it */
59dd8641 176 andb %al, %al /* is byte NUL? */
5929563f 177 jz L(8) /* yes => return */
8f5ca04b
RM
178 incl %ecx /* increment pointer */
179
180 /* Now we are aligned. */
5929563f 181 jmp L(29) /* start copy loop */
8f5ca04b
RM
182
183 ALIGN(4)
184
5929563f 185L(28): movl %eax, 12(%ecx,%edx)/* store word at destination */
8f5ca04b
RM
186 addl $16, %ecx /* adjust pointer for full round */
187
5929563f 188L(29): movl (%ecx), %eax /* get word from source */
8f5ca04b
RM
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 */
5929563f 193 jnc L(9) /* highest byte is C => stop copying */
8f5ca04b
RM
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. */
5929563f 198 jnz L(9) /* one byte is NUL => stop copying */
8f5ca04b
RM
199 movl %eax, (%ecx,%edx) /* store word to destination */
200
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 */
5929563f 206 jnc L(91) /* highest byte is C => stop copying */
8f5ca04b
RM
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. */
5929563f 211 jnz L(91) /* one byte is NUL => stop copying */
8f5ca04b
RM
212 movl %eax, 4(%ecx,%edx) /* store word to destination */
213
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 */
5929563f 219 jnc L(92) /* highest byte is C => stop copying */
8f5ca04b
RM
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. */
5929563f 224 jnz L(92) /* one byte is NUL => stop copying */
8f5ca04b
RM
225 movl %eax, 8(%ecx,%edx) /* store word to destination */
226
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 */
5929563f 232 jnc L(93) /* highest byte is C => stop copying */
8f5ca04b
RM
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. */
5929563f 237 jz L(28) /* no is NUL => carry on copying */
8f5ca04b 238
5929563f
UD
239L(93): addl $4, %ecx /* adjust pointer */
240L(92): addl $4, %ecx
241L(91): addl $4, %ecx
8f5ca04b 242
5929563f 243L(9): movb %al, (%ecx,%edx) /* store first byte of last word */
8f5ca04b 244 orb %al, %al /* is it NUL? */
5929563f 245 jz L(8) /* yes => return */
8f5ca04b
RM
246
247 movb %ah, 1(%ecx,%edx) /* store second byte of last word */
248 orb %ah, %ah /* is it NUL? */
5929563f 249 jz L(8) /* yes => return */
8f5ca04b
RM
250
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? */
5929563f 254 jz L(8) /* yes => return */
8f5ca04b
RM
255
256 movb %ah, 3(%ecx,%edx) /* store fourth byte of last word */
257
2366713d 258L(8): movl DEST(%esp), %eax /* start address of destination is result */
8f5ca04b 259 popl %edi /* restore saved register */
1ad9da69
UD
260 cfi_adjust_cfa_offset (-4)
261 cfi_restore (edi)
8f5ca04b 262
2366713d
JM
263 ret
264END (strcat)
85dd1003 265libc_hidden_builtin_def (strcat)