2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A .file "strncat.s"
2N/A
2N/A/
2N/A/ strncat(s1, s2, n)
2N/A/
2N/A/ Concatenates s2 on the end of s1. s1's space must be large enough.
2N/A/ At most n characters are moved.
2N/A/ Returns s1.
2N/A/
2N/A/ Fast assembly language version of the following C-program strncat
2N/A/ which represents the `standard' for the C-library.
2N/A/
2N/A/ char *
2N/A/ strncat(char *s1, const char *s2, size_t n)
2N/A/ {
2N/A/ char *os1 = s1;
2N/A/
2N/A/ n++;
2N/A/ while (*s1++)
2N/A/ ;
2N/A/ --s1;
2N/A/ while (*s1++ = *s2++)
2N/A/ if (--n == 0) {
2N/A/ s1[-1] = '\0';
2N/A/ break;
2N/A/ }
2N/A/ return (os1);
2N/A/ }
2N/A/
2N/A/ In this assembly language version, the following expression is used
2N/A/ to check if a 32-bit word data contains a null byte or not:
2N/A/ (((A & 0x7f7f7f7f) + 0x7f7f7f7f) | A) & 0x80808080
2N/A/ If the above expression geneates a value other than 0x80808080,
2N/A/ that means the 32-bit word data contains a null byte.
2N/A/
2N/A
2N/A#include "SYS.h"
2N/A
2N/A ENTRY(strncat)
2N/A pushl %edi / save register variables
2N/A pushl %esi
2N/A movl 12(%esp), %edi / %edi = destination string address
2N/A testl $3, %edi / if %edi not word aligned
2N/A jnz .L1 / goto .L1
2N/A .align 4
2N/A.L2:
2N/A movl (%edi), %edx / move 1 word from (%edi) to %edx
2N/A movl $0x7f7f7f7f, %ecx
2N/A andl %edx, %ecx / %ecx = %edx & 0x7f7f7f7f
2N/A addl $4, %edi / next word
2N/A addl $0x7f7f7f7f, %ecx / %ecx += 0x7f7f7f7f
2N/A orl %edx, %ecx / %ecx |= %edx
2N/A andl $0x80808080, %ecx / %ecx &= 0x80808080
2N/A cmpl $0x80808080, %ecx / if no null byte in this word
2N/A je .L2 / goto .L2
2N/A subl $4, %edi / post-incremented
2N/A.L1:
2N/A cmpb $0, (%edi) / if a byte in (%edi) is null
2N/A je .L3 / goto .L3
2N/A incl %edi / next byte
2N/A testl $3, %edi / if %edi not word aligned
2N/A jnz .L1 / goto .L1
2N/A jmp .L2 / goto .L2 (%edi word aligned)
2N/A .align 4
2N/A.L3:
2N/A / %edi points to a null byte in destination string
2N/A movl 16(%esp), %eax / %eax = source string address
2N/A movl 20(%esp), %esi / %esi = number of bytes
2N/A
2N/A testl $3, %eax / if %eax not word aligned
2N/A jnz .L4 / goto .L4
2N/A cmpl $4, %esi / if number of bytes < 4
2N/A jb .L7 / goto .L7
2N/A .align 4
2N/A.L5:
2N/A movl (%eax), %edx / move 1 word from (%eax) to %edx
2N/A movl $0x7f7f7f7f, %ecx
2N/A andl %edx, %ecx / %ecx = %edx & 0x7f7f7f7f
2N/A addl $4, %eax / next word
2N/A addl $0x7f7f7f7f, %ecx / %ecx += 0x7f7f7f7f
2N/A orl %edx, %ecx / %ecx |= %edx
2N/A andl $0x80808080, %ecx / %ecx &= 0x80808080
2N/A cmpl $0x80808080, %ecx / if null byte in this word
2N/A jne .L6 / goto .L6
2N/A movl %edx, (%edi) / copy this word to (%edi)
2N/A subl $4, %esi / decrement number of bytes by 4
2N/A addl $4, %edi / next word
2N/A cmpl $4, %esi / if number of bytes >= 4
2N/A jae .L5 / goto .L5
2N/A jmp .L7 / goto .L7
2N/A.L6:
2N/A subl $4, %eax / post-incremented
2N/A .align 4
2N/A.L7:
2N/A / number of bytes < 4 or a null byte found in the word
2N/A cmpl $0, %esi / if number of bytes == 0
2N/A jz .L8 / goto .L8 (finished)
2N/A movb (%eax), %dl / %dl = a byte in (%eax)
2N/A decl %esi / decrement number of bytes by 1
2N/A movb %dl, (%edi) / copy %dl to (%edi)
2N/A incl %eax / next byte
2N/A incl %edi / next byte
2N/A cmpb $0, %dl / compare %dl with a null byte
2N/A je .L9 / if %dl is a null, goto .L9
2N/A jmp .L7 / goto .L7
2N/A .align 4
2N/A
2N/A.L4:
2N/A / %eax not aligned
2N/A cmpl $0, %esi / if number of bytes == 0
2N/A jz .L8 / goto .L8 (finished)
2N/A movb (%eax), %dl / %dl = a byte in (%eax)
2N/A decl %esi / decrement number of bytes by 1
2N/A movb %dl, (%edi) / copy %dl to (%edi)
2N/A incl %edi / next byte
2N/A incl %eax / next byte
2N/A cmpb $0, %dl / compare %dl with a null byte
2N/A je .L9 / if %dl is a null, goto .L9
2N/A jmp .L4 / goto .L4
2N/A .align 4
2N/A.L8:
2N/A movb $0, (%edi) / null termination
2N/A.L9:
2N/A movl 12(%esp), %eax / return the destination address
2N/A popl %esi / restore register variables
2N/A popl %edi
2N/A ret
2N/A SET_SIZE(strncat)