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/ The above has been extended for 64-bit support.
2N/A/
2N/A
2N/A#include "SYS.h"
2N/A
2N/A ENTRY(strncat) /* (char *, char *, size_t) */
2N/A movq %rdi, %rax / save return value
2N/A movabsq $0x7f7f7f7f7f7f7f7f, %r8 / %r8 = 0x7f...
2N/A movq %r8, %r9
2N/A notq %r9 / %r9 = 0x80...
2N/A testq $7, %rdi / if %rdi not quadword aligned
2N/A jnz .L1 / goto .L1
2N/A .align 4
2N/A.L2:
2N/A movq (%rdi), %r11 / move 1 quadword from (%rdi) to %r11
2N/A movq %r8, %rcx
2N/A andq %r11, %rcx / %rcx = %r11 & 0x7f7f7f7f
2N/A addq $8, %rdi / next quadword
2N/A addq %r8, %rcx / %rcx += 0x7f7f7f7f
2N/A orq %r11, %rcx / %rcx |= %r11
2N/A andq %r9, %rcx / %rcx &= 0x80808080
2N/A cmpq %r9, %rcx / if no null byte in this quadword
2N/A je .L2 / goto .L2
2N/A subq $8, %rdi / post-incremented
2N/A.L1:
2N/A cmpb $0, (%rdi) / if a byte in (%rdi) is null
2N/A je .L3 / goto .L3
2N/A incq %rdi / next byte
2N/A testq $7, %rdi / if %rdi not quadword aligned
2N/A jnz .L1 / goto .L1
2N/A jmp .L2 / goto .L2 (%rdi quadword aligned)
2N/A .align 4
2N/A.L3:
2N/A / %rdi points to a null byte in destination string
2N/A
2N/A testq $7, %rsi / if %rsi not quadword aligned
2N/A jnz .L4 / goto .L4
2N/A cmpq $8, %rdx / if number of bytes < 8
2N/A jb .L7 / goto .L7
2N/A .align 4
2N/A.L5:
2N/A movq (%rsi), %r11 / move 1 quadword from (%rsi) to %r11
2N/A movq %r8, %rcx
2N/A andq %r11, %rcx / %rcx = %r11 & 0x7f7f7f7f
2N/A addq $8, %rsi / next quadword
2N/A addq %r8, %rcx / %rcx += 0x7f7f7f7f
2N/A orq %r11, %rcx / %rcx |= %r11
2N/A andq %r9, %rcx / %rcx &= 0x80808080
2N/A cmpq %r9, %rcx / if null byte in this quadword
2N/A jne .L6 / goto .L6
2N/A movq %r11, (%rdi) / copy this quadword to (%rdi)
2N/A subq $8, %rdx / decrement number of bytes by 8
2N/A addq $8, %rdi / next quadword
2N/A cmpq $8, %rdx / if number of bytes >= 8
2N/A jae .L5 / goto .L5
2N/A jmp .L7 / goto .L7
2N/A.L6:
2N/A subq $8, %rsi / post-incremented
2N/A .align 4
2N/A.L7:
2N/A / number of bytes < 8 or a null byte found in the quadword
2N/A cmpq $0, %rdx / if number of bytes == 0
2N/A jz .L8 / goto .L8 (finished)
2N/A movb (%rsi), %r11b / %r11b = a byte in (%rsi)
2N/A decq %rdx / decrement number of bytes by 1
2N/A movb %r11b, (%rdi) / copy %r11b to (%rdi)
2N/A incq %rsi / next byte
2N/A incq %rdi / next byte
2N/A cmpb $0, %r11b / compare %r11b with a null byte
2N/A je .L9 / if %r11b is a null, goto .L9
2N/A jmp .L7 / goto .L7
2N/A .align 4
2N/A
2N/A.L4:
2N/A / %rsi not aligned
2N/A cmpq $0, %rdx / if number of bytes == 0
2N/A jz .L8 / goto .L8 (finished)
2N/A movb (%rsi), %r11b / %r11b = a byte in (%rsi)
2N/A decq %rdx / decrement number of bytes by 1
2N/A movb %r11b, (%rdi) / copy %r11b to (%rdi)
2N/A incq %rdi / next byte
2N/A incq %rsi / next byte
2N/A cmpb $0, %r11b / compare %r11b with a null byte
2N/A je .L9 / if %r11b is a null, goto .L9
2N/A jmp .L4 / goto .L4
2N/A .align 4
2N/A.L8:
2N/A movb $0, (%rdi) / null termination
2N/A.L9:
2N/A ret
2N/A SET_SIZE(strncat)