1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 .file "strncpy.s" 28 29/* 30 * strncpy(s1, s2) 31 * 32 * Copy string s2 to s1, truncating or null-padding to always copy n bytes 33 * return s1. 34 * 35 * Fast assembler language version of the following C-program for strncpy 36 * which represents the `standard' for the C-library. 37 * 38 * char * 39 * strncpy(char *s1, const char *s2, size_t n) 40 * { 41 * char *os1 = s1; 42 * 43 * n++; 44 * while ((--n != 0) && ((*s1++ = *s2++) != '\0')) 45 * ; 46 * if (n != 0) 47 * while (--n != 0) 48 * *s1++ = '\0'; 49 * return (os1); 50 * } 51 */ 52 53#include <sys/asm_linkage.h> 54 55 ! strncpy works similarly to strcpy, except that n bytes of s2 56 ! are copied to s1. If a null character is reached in s2 yet more 57 ! bytes remain to be copied, strncpy will copy null bytes into 58 ! the destination string. 59 ! 60 ! This implementation works by first aligning the src ptr and 61 ! performing small copies until it is aligned. Then, the string 62 ! is copied based upon destination alignment. (byte, half-word, 63 ! word, etc.) 64 65 ENTRY(strncpy) 66 67 .align 32 68 nop ! pad to align loop on 16-byte boundary 69 subcc %g0, %o2, %g4 ! n = -n, n == 0 ? 70 bz,pn %ncc, .done ! n == 0, done 71 add %o1, %o2, %o3 ! src = src + n 72 andcc %o1, 7, %o4 ! dword aligned ? 73 bz,pn %ncc, .dwordaligned ! yup 74 add %o0, %o2, %o2 ! dst = dst + n 75 sub %o4, 8, %o4 ! bytes until src aligned 76 77.alignsrc: 78 ldub [%o3 + %g4], %o1 ! src[] 79 stb %o1, [%o2 + %g4] ! dst[] = src[] 80 addcc %g4, 1, %g4 ! src++, dst++, n-- 81 bz,pn %ncc, .done ! n == 0, done 82 tst %o1 ! end of src reached (null byte) ? 83 bz,a %ncc, .bytepad ! yes, at least one byte to pad here 84 add %o2, %g4, %o3 ! need single dest pointer for fill 85 addcc %o4, 1, %o4 ! src aligned now? 86 bnz,a %ncc, .alignsrc ! no, copy another byte 87 nop ! pad 88 nop ! pad 89 90.dwordaligned: 91 sethi %hi(0x01010101), %o4 ! Alan Mycroft's magic1 92 add %o2, %g4, %g5 ! dst 93 or %o4, %lo(0x01010101),%o4! finish loading magic1 94 and %g5, 3, %g1 ! dst<1:0> to examine offset 95 sllx %o4, 32, %o1 ! spread magic1 96 cmp %g1, 1 ! dst offset of 1 or 5 97 or %o4, %o1, %o4 ! to all 64 bits 98 sub %o2, 8, %o2 ! adjust for dest pre-incr in cpy loops 99 be,pn %ncc, .storebyte1241 ! store 1, 2, 4, 1 bytes 100 sllx %o4, 7, %o5 ! Alan Mycroft's magic2 101 cmp %g1, 3 ! dst offset of 3 or 7 102 be,pn %ncc, .storebyte1421 ! store 1, 4, 2, 1 bytes 103 cmp %g1, 2 ! dst halfword aligned ? 104 be,pn %ncc, .storehalfword ! yup, store half-word wise 105 andcc %g5, 7, %g0 ! dst word aligned ? 106 bnz,pn %ncc, .storeword2 ! yup, store word wise 107 nop ! ensure loop is 16-byte aligned 108 109.storedword: 110 ldx [%o3 + %g4], %o1 ! src dword 111 addcc %g4, 8, %g4 ! n += 8, src += 8, dst += 8 112 bcs,pn %ncc,.lastword ! if counter wraps, last word 113 andn %o5, %o1, %g1 ! ~dword & 0x8080808080808080 114 sub %o1, %o4, %g5 ! dword - 0x0101010101010101 115 andcc %g5, %g1, %g0 ! ((dword - 0x0101010101010101) & ~dword & 0x8080808080808080) 116 bz,a,pt %ncc, .storedword ! no zero byte if magic expression == 0 117 stx %o1, [%o2 + %g4] ! store word to dst (address pre-incremented) 118 119 ! n has not expired, but src is at the end. we need to push out the 120 ! remaining src bytes and then start padding with null bytes 121 122.zerobyte: 123 add %o2, %g4, %o3 ! pointer to dest string 124 srlx %o1, 56, %g1 ! first byte 125 stb %g1, [%o3] ! store it 126 andcc %g1, 0xff, %g0 ! end of string ? 127 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 128 srlx %o1, 48, %g1 ! second byte 129 stb %g1, [%o3 + 1] ! store it 130 andcc %g1, 0xff, %g0 ! end of string ? 131 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 132 srlx %o1, 40, %g1 ! third byte 133 stb %g1, [%o3 + 2] ! store it 134 andcc %g1, 0xff, %g0 ! end of string ? 135 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 136 srlx %o1, 32, %g1 ! fourth byte 137 stb %g1, [%o3 + 3] ! store it 138 andcc %g1, 0xff, %g0 ! end of string ? 139 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 140 srlx %o1, 24, %g1 ! fifth byte 141 stb %g1, [%o3 + 4] ! store it 142 andcc %g1, 0xff, %g0 ! end of string ? 143 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 144 srlx %o1, 16, %g1 ! sixth byte 145 stb %g1, [%o3 + 5] ! store it 146 andcc %g1, 0xff, %g0 ! end of string ? 147 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 148 srlx %o1, 8, %g1 ! seventh byte 149 stb %g1, [%o3 + 6] ! store it 150 andcc %g1, 0xff, %g0 ! end of string ? 151 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 152 stb %o1, [%o3 + 7] ! store eighth byte 153 addcc %g4, 16, %g0 ! number of pad bytes < 16 ? 154 bcs,pn %ncc, .bytepad ! yes, do simple byte wise fill 155 add %o3, 8, %o3 ! dst += 8 156 andcc %o3, 7, %o4 ! dst offset relative to dword boundary 157 bz,pn %ncc, .fillaligned ! dst already dword aligned 158 159 ! here there is a least one more byte to zero out: otherwise we would 160 ! have exited through label .lastword 161 162 sub %o4, 8, %o4 ! bytes to align dst to dword boundary 163.makealigned: 164 stb %g0, [%o3] ! dst[] = 0 165 addcc %g4, 1, %g4 ! n-- 166 bz,pt %ncc, .done ! n == 0, we are done 167 addcc %o4, 1, %o4 ! any more byte needed to align 168 bnz,pt %ncc, .makealigned ! yup, pad another byte 169 add %o3, 1, %o3 ! dst++ 170 nop ! pad to align copy loop below 171 nop ! pad to align copy loop below 172 173 ! here we know that there at least another 8 bytes to pad, since 174 ! we don't get here unless there were >= 16 bytes to pad to begin 175 ! with, and we have padded at most 7 bytes suring dst aligning 176 177.fillaligned: 178 add %g4, 7, %o2 ! round up to next dword boundary 179 and %o2, -8, %o4 ! pointer to next dword boundary 180 and %o2, 8, %o2 ! dword count odd ? 8 : 0 181 stx %g0, [%o3] ! store first dword 182 addcc %o4, %o2, %o4 ! dword count == 1 ? 183 add %g4, %o2, %g4 ! if dword count odd, n -= 8 184 bz,pt %ncc, .bytepad ! if dword count == 1, pad leftover bytes 185 add %o3, %o2, %o3 ! bump dst if dword count odd 186 187.filldword: 188 addcc %o4, 16, %o4 ! count -= 16 189 stx %g0, [%o3] ! dst[n] = 0 190 stx %g0, [%o3 + 8] ! dst[n+8] = 0 191 add %o3, 16, %o3 ! dst += 16 192 bcc,pt %ncc, .filldword ! fill dwords until count == 0 193 addcc %g4, 16, %g4 ! n -= 16 194 bz,pn %ncc, .done ! if n == 0, we are done 195 196.bytepad: 197 and %g4, 1, %o2 ! byte count odd ? 1 : 0 198 stb %g0, [%o3] ! store first byte 199 addcc %g4, %o2, %g4 ! byte count == 1 ? 200 bz,pt %ncc, .done ! yup, we are done 201 add %o3, %o2, %o3 ! bump pointer if odd 202 203.fillbyte: 204 addcc %g4, 2, %g4 ! n -= 2 205 stb %g0, [%o3] ! dst[n] = 0 206 stb %g0, [%o3 + 1] ! dst[n+1] = 0 207 bnz,pt %ncc, .fillbyte ! fill until n == 0 208 add %o3, 2, %o3 ! dst += 2 209 210.done: 211 retl ! done 212 nop ! pad to align loops below 213 nop ! pad to align loops below 214 215 ! this is the last word. It may contain null bytes. store bytes 216 ! until n == 0. if null byte encountered, continue 217 218.lastword: 219 sub %g4, 8, %g4 ! undo counter pre-increment 220 add %o2, 8, %o2 ! adjust dst for counter un-bumping 221 222 srlx %o1, 56, %g1 ! first byte 223 stb %g1, [%o2 + %g4] ! store it 224 inccc %g4 ! n-- 225 bz .done ! if n == 0, we're done 226 andcc %g1, 0xff, %g0 ! end of src reached ? 227 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 228 srlx %o1, 48, %g1 ! second byte 229 stb %g1, [%o2 + %g4] ! store it 230 inccc %g4 ! n-- 231 bz .done ! if n == 0, we're done 232 andcc %g1, 0xff, %g0 ! end of src reached ? 233 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 234 srlx %o1, 40, %g1 ! third byte 235 stb %g1, [%o2 + %g4] ! store it 236 inccc %g4 ! n-- 237 bz .done ! if n == 0, we're done 238 andcc %g1, 0xff, %g0 ! end of src reached ? 239 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 240 srlx %o1, 32, %g1 ! fourth byte 241 stb %g1, [%o2 + %g4] ! store it 242 inccc %g4 ! n-- 243 bz .done ! if n == 0, we're done 244 andcc %g1, 0xff, %g0 ! end of src reached ? 245 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 246 srlx %o1, 24, %g1 ! fifth byte 247 stb %g1, [%o2 + %g4] ! store it 248 inccc %g4 ! n-- 249 bz .done ! if n == 0, we're done 250 andcc %g1, 0xff, %g0 ! end of src reached ? 251 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 252 srlx %o1, 16, %g1 ! sixth byte 253 stb %g1, [%o2 + %g4] ! store it 254 inccc %g4 ! n-- 255 bz .done ! if n == 0, we're done 256 andcc %g1, 0xff, %g0 ! end of src reached ? 257 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 258 srlx %o1, 8, %g1 ! seventh byte 259 stb %g1, [%o2 + %g4] ! store it 260 inccc %g4 ! n-- 261 bz .done ! if n == 0, we're done 262 andcc %g1, 0xff, %g0 ! end of src reached ? 263 movz %ncc, %g0, %o1 ! if so, start padding with null bytes 264 ba .done ! here n must be zero, we are done 265 stb %o1, [%o2 + %g4] ! store eigth byte 266 nop ! pad to align loops below 267 nop ! pad to align loops below 268 269.storebyte1421: 270 ldx [%o3 + %g4], %o1 ! x = src[] 271 addcc %g4, 8, %g4 ! src += 8, dst += 8 272 bcs,pn %ncc,.lastword ! if counter wraps, last word 273 andn %o5, %o1, %g1 ! ~x & 0x8080808080808080 274 sub %o1, %o4, %g5 ! x - 0x0101010101010101 275 andcc %g5, %g1, %g0 ! ((x - 0x0101010101010101) & ~x & 0x8080808080808080) 276 bnz,pn %ncc, .zerobyte ! end of src found, may need to pad 277 add %o2, %g4, %g5 ! dst (in pointer form) 278 srlx %o1, 56, %g1 ! %g1<7:0> = first byte; word aligned now 279 stb %g1, [%g5] ! store first byte 280 srlx %o1, 24, %g1 ! %g1<31:0> = bytes 2, 3, 4, 5 281 stw %g1, [%g5 + 1] ! store bytes 2, 3, 4, 5 282 srlx %o1, 8, %g1 ! %g1<15:0> = bytes 6, 7 283 sth %g1, [%g5 + 5] ! store bytes 6, 7 284 ba .storebyte1421 ! next dword 285 stb %o1, [%g5 + 7] ! store eigth byte 286 287.storebyte1241: 288 ldx [%o3 + %g4], %o1 ! x = src[] 289 addcc %g4, 8, %g4 ! src += 8, dst += 8 290 bcs,pn %ncc,.lastword ! if counter wraps, last word 291 andn %o5, %o1, %g1 ! ~x & 0x8080808080808080 292 sub %o1, %o4, %g5 ! x - 0x0101010101010101 293 andcc %g5, %g1, %g0 ! ((x - 0x0101010101010101) & ~x & 0x8080808080808080) 294 bnz,pn %ncc, .zerobyte ! x has zero byte, handle end cases 295 add %o2, %g4, %g5 ! dst (in pointer form) 296 srlx %o1, 56, %g1 ! %g1<7:0> = first byte; half-word aligned now 297 stb %g1, [%g5] ! store first byte 298 srlx %o1, 40, %g1 ! %g1<15:0> = bytes 2, 3 299 sth %g1, [%g5 + 1] ! store bytes 2, 3 300 srlx %o1, 8, %g1 ! %g1<31:0> = bytes 4, 5, 6, 7 301 stw %g1, [%g5 + 3] ! store bytes 4, 5, 6, 7 302 ba .storebyte1241 ! next dword 303 stb %o1, [%g5 + 7] ! store eigth byte 304 305.storehalfword: 306 ldx [%o3 + %g4], %o1 ! x = src[] 307 addcc %g4, 8, %g4 ! src += 8, dst += 8 308 bcs,pn %ncc,.lastword ! if counter wraps, last word 309 andn %o5, %o1, %g1 ! ~x & 0x8080808080808080 310 sub %o1, %o4, %g5 ! x - 0x0101010101010101 311 andcc %g5, %g1, %g0 ! ((x - 0x0101010101010101) & ~x & 0x8080808080808080) 312 bnz,pn %ncc, .zerobyte ! x has zero byte, handle end cases 313 add %o2, %g4, %g5 ! dst (in pointer form) 314 srlx %o1, 48, %g1 ! %g1<15:0> = bytes 1, 2; word aligned now 315 sth %g1, [%g5] ! store bytes 1, 2 316 srlx %o1, 16, %g1 ! %g1<31:0> = bytes 3, 4, 5, 6 317 stw %g1, [%g5 + 2] ! store bytes 3, 4, 5, 6 318 ba .storehalfword ! next dword 319 sth %o1, [%g5 + 6] ! store bytes 7, 8 320 nop ! align next loop to 16-byte boundary 321 nop ! align next loop to 16-byte boundary 322 323.storeword2: 324 ldx [%o3 + %g4], %o1 ! x = src[] 325 addcc %g4, 8, %g4 ! src += 8, dst += 8 326 bcs,pn %ncc,.lastword ! if counter wraps, last word 327 andn %o5, %o1, %g1 ! ~x & 0x8080808080808080 328 sub %o1, %o4, %g5 ! x - 0x0101010101010101 329 andcc %g5, %g1, %g0 ! ((x - 0x0101010101010101) & ~x & 0x8080808080808080) 330 bnz,pn %ncc, .zerobyte ! x has zero byte, handle end cases 331 add %o2, %g4, %g5 ! dst (in pointer form) 332 srlx %o1, 32, %g1 ! %g1<31:0> = bytes 1, 2, 3, 4 333 stw %g1, [%g5] ! store bytes 1, 2, 3, 4 334 ba .storeword2 ! next dword 335 stw %o1, [%g5 + 4] ! store bytes 5, 6, 7, 8 336 337 ! do not remove these pads, loop above may slow down otherwise 338 339 nop ! pad 340 nop ! pad 341 342 SET_SIZE(strncpy) 343