Blame sysdeps/i386/strcat.S

Packit 6c4009
/* strcat(dest, src) -- Append SRC on the end of DEST.
Packit 6c4009
   For Intel 80x86, x>=4.
Packit 6c4009
   Copyright (C) 1994-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@ipd.info.uni-karlsruhe.de>.
Packit 6c4009
   Optimised a little by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
#include "asm-syntax.h"
Packit 6c4009
Packit 6c4009
#define PARMS	4+4	/* space for 1 saved reg */
Packit 6c4009
#define RTN	PARMS
Packit 6c4009
#define DEST	RTN
Packit 6c4009
#define SRC	DEST+4
Packit 6c4009
Packit 6c4009
	.text
Packit 6c4009
ENTRY (strcat)
Packit 6c4009
Packit 6c4009
	pushl %edi		/* Save callee-safe register.  */
Packit 6c4009
	cfi_adjust_cfa_offset (4)
Packit 6c4009
Packit 6c4009
	movl DEST(%esp), %edx
Packit 6c4009
	movl SRC(%esp), %ecx
Packit 6c4009
Packit 6c4009
	testb $0xff, (%ecx)	/* Is source string empty? */
Packit 6c4009
	jz L(8)			/* yes => return */
Packit 6c4009
Packit 6c4009
	/* Test the first bytes separately until destination is aligned.  */
Packit 6c4009
	testl $3, %edx		/* destination pointer aligned? */
Packit 6c4009
	jz L(1)			/* yes => begin scan loop */
Packit 6c4009
	testb $0xff, (%edx)	/* is end of string? */
Packit 6c4009
	jz L(2)			/* yes => start appending */
Packit 6c4009
	incl %edx		/* increment source pointer */
Packit 6c4009
Packit 6c4009
	testl $3, %edx		/* destination pointer aligned? */
Packit 6c4009
	jz L(1)			/* yes => begin scan loop */
Packit 6c4009
	testb $0xff, (%edx)	/* is end of string? */
Packit 6c4009
	jz L(2)			/* yes => start appending */
Packit 6c4009
	incl %edx		/* increment source pointer */
Packit 6c4009
Packit 6c4009
	testl $3, %edx		/* destination pointer aligned? */
Packit 6c4009
	jz L(1)			/* yes => begin scan loop */
Packit 6c4009
	testb $0xff, (%edx)	/* is end of string? */
Packit 6c4009
	jz L(2)			/* yes => start appending */
Packit 6c4009
	incl %edx		/* increment source pointer */
Packit 6c4009
Packit 6c4009
	/* Now we are aligned.  Begin scan loop.  */
Packit 6c4009
	jmp L(1)
Packit 6c4009
Packit 6c4009
	cfi_rel_offset (edi, 0)
Packit 6c4009
	ALIGN(4)
Packit 6c4009
Packit 6c4009
L(4):	addl $16,%edx		/* increment destination pointer for round */
Packit 6c4009
Packit 6c4009
L(1):	movl (%edx), %eax	/* get word (= 4 bytes) in question */
Packit 6c4009
	movl $0xfefefeff, %edi	/* magic value */
Packit 6c4009
Packit 6c4009
	/* If you compare this with the algorithm in memchr.S you will
Packit 6c4009
	   notice that here is an `xorl' statement missing.  But you must
Packit 6c4009
	   not forget that we are looking for C == 0 and `xorl $0, %eax'
Packit 6c4009
	   is a no-op.  */
Packit 6c4009
Packit 6c4009
	addl %eax, %edi		/* add the magic value to the word.  We get
Packit 6c4009
				   carry bits reported for each byte which
Packit 6c4009
				   is *not* 0 */
Packit 6c4009
Packit 6c4009
	/* According to the algorithm we had to reverse the effect of the
Packit 6c4009
	   XOR first and then test the overflow bits.  But because the
Packit 6c4009
	   following XOR would destroy the carry flag and it would (in a
Packit 6c4009
	   representation with more than 32 bits) not alter then last
Packit 6c4009
	   overflow, we can now test this condition.  If no carry is signaled
Packit 6c4009
	   no overflow must have occurred in the last byte => it was 0.	*/
Packit 6c4009
	jnc L(3)
Packit 6c4009
Packit 6c4009
	/* We are only interested in carry bits that change due to the
Packit 6c4009
	   previous add, so remove original bits */
Packit 6c4009
	xorl %eax, %edi		/* ((word^charmask)+magic)^(word^charmask) */
Packit 6c4009
Packit 6c4009
	/* Now test for the other three overflow bits.  */
Packit 6c4009
	orl $0xfefefeff, %edi	/* set all non-carry bits */
Packit 6c4009
	incl %edi		/* add 1: if one carry bit was *not* set
Packit 6c4009
				   the addition will not result in 0.  */
Packit 6c4009
Packit 6c4009
	/* If at least one byte of the word is C we don't get 0 in %ecx.  */
Packit 6c4009
	jnz L(3)
Packit 6c4009
Packit 6c4009
	movl 4(%edx), %eax	/* get word from source */
Packit 6c4009
	movl $0xfefefeff, %edi	/* magic value */
Packit 6c4009
	addl %eax, %edi		/* add the magic value to the word.  We get
Packit 6c4009
				   carry bits reported for each byte which
Packit 6c4009
				   is *not* 0 */
Packit 6c4009
	jnc L(5)		/* highest byte is C => stop copying */
Packit 6c4009
	xorl %eax, %edi		/* ((word^charmask)+magic)^(word^charmask) */
Packit 6c4009
	orl $0xfefefeff, %edi	/* set all non-carry bits */
Packit 6c4009
	incl %edi		/* add 1: if one carry bit was *not* set
Packit 6c4009
				   the addition will not result in 0.  */
Packit 6c4009
	jnz L(5)		/* one byte is NUL => stop copying */
Packit 6c4009
Packit 6c4009
	movl 8(%edx), %eax	/* get word from source */
Packit 6c4009
	movl $0xfefefeff, %edi	/* magic value */
Packit 6c4009
	addl %eax, %edi		/* add the magic value to the word.  We get
Packit 6c4009
				   carry bits reported for each byte which
Packit 6c4009
				   is *not* 0 */
Packit 6c4009
	jnc L(6)		/* highest byte is C => stop copying */
Packit 6c4009
	xorl %eax, %edi		/* ((word^charmask)+magic)^(word^charmask) */
Packit 6c4009
	orl $0xfefefeff, %edi	/* set all non-carry bits */
Packit 6c4009
	incl %edi		/* add 1: if one carry bit was *not* set
Packit 6c4009
				   the addition will not result in 0.  */
Packit 6c4009
	jnz L(6)		/* one byte is NUL => stop copying */
Packit 6c4009
Packit 6c4009
	movl 12(%edx), %eax	/* get word from source */
Packit 6c4009
	movl $0xfefefeff, %edi	/* magic value */
Packit 6c4009
	addl %eax, %edi		/* add the magic value to the word.  We get
Packit 6c4009
				   carry bits reported for each byte which
Packit 6c4009
				   is *not* 0 */
Packit 6c4009
	jnc L(7)		/* highest byte is C => stop copying */
Packit 6c4009
	xorl %eax, %edi		/* ((word^charmask)+magic)^(word^charmask) */
Packit 6c4009
	orl $0xfefefeff, %edi	/* set all non-carry bits */
Packit 6c4009
	incl %edi		/* add 1: if one carry bit was *not* set
Packit 6c4009
				   the addition will not result in 0.  */
Packit 6c4009
	jz L(4)			/* no byte is NUL => carry on copying */
Packit 6c4009
Packit 6c4009
L(7):	addl $4, %edx		/* adjust source pointer */
Packit 6c4009
L(6):	addl $4, %edx
Packit 6c4009
L(5):	addl $4, %edx
Packit 6c4009
Packit 6c4009
L(3):	testb %al, %al		/* is first byte NUL? */
Packit 6c4009
	jz L(2)			/* yes => start copying */
Packit 6c4009
	incl %edx		/* increment source pointer */
Packit 6c4009
Packit 6c4009
	testb %ah, %ah		/* is second byte NUL? */
Packit 6c4009
	jz L(2)			/* yes => start copying */
Packit 6c4009
	incl %edx		/* increment source pointer */
Packit 6c4009
Packit 6c4009
	testl $0xff0000, %eax	/* is third byte NUL? */
Packit 6c4009
	jz L(2)			/* yes => start copying */
Packit 6c4009
	incl %edx		/* increment source pointer */
Packit 6c4009
Packit 6c4009
L(2):	subl %ecx, %edx		/* reduce number of loop variants */
Packit 6c4009
Packit 6c4009
	/* Now we have to align the source pointer.  */
Packit 6c4009
	testl $3, %ecx		/* pointer correctly aligned? */
Packit 6c4009
	jz L(29)		/* yes => start copy loop */
Packit 6c4009
	movb (%ecx), %al	/* get first byte */
Packit 6c4009
	movb %al, (%ecx,%edx)	/* and store it */
Packit 6c4009
	andb %al, %al		/* is byte NUL? */
Packit 6c4009
	jz L(8)			/* yes => return */
Packit 6c4009
	incl %ecx		/* increment pointer */
Packit 6c4009
Packit 6c4009
	testl $3, %ecx		/* pointer correctly aligned? */
Packit 6c4009
	jz L(29)		/* yes => start copy loop */
Packit 6c4009
	movb (%ecx), %al	/* get first byte */
Packit 6c4009
	movb %al, (%ecx,%edx)	/* and store it */
Packit 6c4009
	andb %al, %al		/* is byte NUL? */
Packit 6c4009
	jz L(8)			/* yes => return */
Packit 6c4009
	incl %ecx		/* increment pointer */
Packit 6c4009
Packit 6c4009
	testl $3, %ecx		/* pointer correctly aligned? */
Packit 6c4009
	jz L(29)		/* yes => start copy loop */
Packit 6c4009
	movb (%ecx), %al	/* get first byte */
Packit 6c4009
	movb %al, (%ecx,%edx)	/* and store it */
Packit 6c4009
	andb %al, %al		/* is byte NUL? */
Packit 6c4009
	jz L(8)			/* yes => return */
Packit 6c4009
	incl %ecx		/* increment pointer */
Packit 6c4009
Packit 6c4009
	/* Now we are aligned.  */
Packit 6c4009
	jmp L(29)		/* start copy loop */
Packit 6c4009
Packit 6c4009
	ALIGN(4)
Packit 6c4009
Packit 6c4009
L(28):	movl %eax, 12(%ecx,%edx)/* store word at destination */
Packit 6c4009
	addl $16, %ecx		/* adjust pointer for full round */
Packit 6c4009
Packit 6c4009
L(29):	movl (%ecx), %eax	/* get word from source */
Packit 6c4009
	movl $0xfefefeff, %edi	/* magic value */
Packit 6c4009
	addl %eax, %edi		/* add the magic value to the word.  We get
Packit 6c4009
				   carry bits reported for each byte which
Packit 6c4009
				   is *not* 0 */
Packit 6c4009
	jnc L(9)		/* highest byte is C => stop copying */
Packit 6c4009
	xorl %eax, %edi		/* ((word^charmask)+magic)^(word^charmask) */
Packit 6c4009
	orl $0xfefefeff, %edi	/* set all non-carry bits */
Packit 6c4009
	incl %edi		/* add 1: if one carry bit was *not* set
Packit 6c4009
				   the addition will not result in 0.  */
Packit 6c4009
	jnz L(9)		/* one byte is NUL => stop copying */
Packit 6c4009
	movl %eax, (%ecx,%edx)	/* store word to destination */
Packit 6c4009
Packit 6c4009
	movl 4(%ecx), %eax	/* get word from source */
Packit 6c4009
	movl $0xfefefeff, %edi	/* magic value */
Packit 6c4009
	addl %eax, %edi		/* add the magic value to the word.  We get
Packit 6c4009
				   carry bits reported for each byte which
Packit 6c4009
				   is *not* 0 */
Packit 6c4009
	jnc L(91)		/* highest byte is C => stop copying */
Packit 6c4009
	xorl %eax, %edi		/* ((word^charmask)+magic)^(word^charmask) */
Packit 6c4009
	orl $0xfefefeff, %edi	/* set all non-carry bits */
Packit 6c4009
	incl %edi		/* add 1: if one carry bit was *not* set
Packit 6c4009
				   the addition will not result in 0.  */
Packit 6c4009
	jnz L(91)		/* one byte is NUL => stop copying */
Packit 6c4009
	movl %eax, 4(%ecx,%edx)	/* store word to destination */
Packit 6c4009
Packit 6c4009
	movl 8(%ecx), %eax	/* get word from source */
Packit 6c4009
	movl $0xfefefeff, %edi	/* magic value */
Packit 6c4009
	addl %eax, %edi		/* add the magic value to the word.  We get
Packit 6c4009
				   carry bits reported for each byte which
Packit 6c4009
				   is *not* 0 */
Packit 6c4009
	jnc L(92)		/* highest byte is C => stop copying */
Packit 6c4009
	xorl %eax, %edi		/* ((word^charmask)+magic)^(word^charmask) */
Packit 6c4009
	orl $0xfefefeff, %edi	/* set all non-carry bits */
Packit 6c4009
	incl %edi		/* add 1: if one carry bit was *not* set
Packit 6c4009
				   the addition will not result in 0.  */
Packit 6c4009
	jnz L(92)		/* one byte is NUL => stop copying */
Packit 6c4009
	movl %eax, 8(%ecx,%edx)	/* store word to destination */
Packit 6c4009
Packit 6c4009
	movl 12(%ecx), %eax	/* get word from source */
Packit 6c4009
	movl $0xfefefeff, %edi	/* magic value */
Packit 6c4009
	addl %eax, %edi		/* add the magic value to the word.  We get
Packit 6c4009
				   carry bits reported for each byte which
Packit 6c4009
				   is *not* 0 */
Packit 6c4009
	jnc L(93)		/* highest byte is C => stop copying */
Packit 6c4009
	xorl %eax, %edi		/* ((word^charmask)+magic)^(word^charmask) */
Packit 6c4009
	orl $0xfefefeff, %edi	/* set all non-carry bits */
Packit 6c4009
	incl %edi		/* add 1: if one carry bit was *not* set
Packit 6c4009
				   the addition will not result in 0.  */
Packit 6c4009
	jz L(28)		/* no is NUL => carry on copying */
Packit 6c4009
Packit 6c4009
L(93):	addl $4, %ecx		/* adjust pointer */
Packit 6c4009
L(92):	addl $4, %ecx
Packit 6c4009
L(91):	addl $4, %ecx
Packit 6c4009
Packit 6c4009
L(9):	movb %al, (%ecx,%edx)	/* store first byte of last word */
Packit 6c4009
	orb %al, %al		/* is it NUL? */
Packit 6c4009
	jz L(8)			/* yes => return */
Packit 6c4009
Packit 6c4009
	movb %ah, 1(%ecx,%edx)	/* store second byte of last word */
Packit 6c4009
	orb %ah, %ah		/* is it NUL? */
Packit 6c4009
	jz L(8)			/* yes => return */
Packit 6c4009
Packit 6c4009
	shrl $16, %eax		/* make upper bytes accessible */
Packit 6c4009
	movb %al, 2(%ecx,%edx)	/* store third byte of last word */
Packit 6c4009
	orb %al, %al		/* is it NUL? */
Packit 6c4009
	jz L(8)			/* yes => return */
Packit 6c4009
Packit 6c4009
	movb %ah, 3(%ecx,%edx)	/* store fourth byte of last word */
Packit 6c4009
Packit 6c4009
L(8):	movl DEST(%esp), %eax	/* start address of destination is result */
Packit 6c4009
	popl %edi		/* restore saved register */
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	cfi_restore (edi)
Packit 6c4009
Packit 6c4009
	ret
Packit 6c4009
END (strcat)
Packit 6c4009
libc_hidden_builtin_def (strcat)