| 1 | /* copy no more then N bytes from SRC to DEST, returning the address of
|
|---|
| 2 | the terminating '\0' in DEST.
|
|---|
| 3 | For Intel 80x86, x>=3.
|
|---|
| 4 | Copyright (C) 1994-1997,2000,2002,2005 Free Software Foundation, Inc.
|
|---|
| 5 | This file is part of the GNU C Library.
|
|---|
| 6 | Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>
|
|---|
| 7 | Some bug fixes by Alan Modra <Alan@SPRI.Levels.UniSA.Edu.Au>
|
|---|
| 8 | - original wrote n+1 chars in some cases.
|
|---|
| 9 | - stpncpy() ought to behave like strncpy() ie. not null-terminate
|
|---|
| 10 | if limited by n. glibc-1.09 stpncpy() does this.
|
|---|
| 11 |
|
|---|
| 12 | The GNU C Library is free software; you can redistribute it and/or
|
|---|
| 13 | modify it under the terms of the GNU Lesser General Public
|
|---|
| 14 | License as published by the Free Software Foundation; either
|
|---|
| 15 | version 2.1 of the License, or (at your option) any later version.
|
|---|
| 16 |
|
|---|
| 17 | The GNU C Library is distributed in the hope that it will be useful,
|
|---|
| 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|---|
| 20 | Lesser General Public License for more details.
|
|---|
| 21 |
|
|---|
| 22 | You should have received a copy of the GNU Lesser General Public
|
|---|
| 23 | License along with the GNU C Library; if not, write to the Free
|
|---|
| 24 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|---|
| 25 | 02111-1307 USA. */
|
|---|
| 26 |
|
|---|
| 27 | #include <sysdep.h>
|
|---|
| 28 | #include "asm-syntax.h"
|
|---|
| 29 | #include "bp-sym.h"
|
|---|
| 30 | #include "bp-asm.h"
|
|---|
| 31 |
|
|---|
| 32 | #define PARMS LINKAGE+4 /* space for 1 saved reg */
|
|---|
| 33 | #define RTN PARMS
|
|---|
| 34 | #define DEST RTN+RTN_SIZE
|
|---|
| 35 | #define SRC DEST+PTR_SIZE
|
|---|
| 36 | #define LEN SRC+PTR_SIZE
|
|---|
| 37 |
|
|---|
| 38 | .text
|
|---|
| 39 | ENTRY (BP_SYM (__stpncpy))
|
|---|
| 40 | ENTER
|
|---|
| 41 |
|
|---|
| 42 | pushl %esi
|
|---|
| 43 | cfi_adjust_cfa_offset (4)
|
|---|
| 44 |
|
|---|
| 45 | movl DEST(%esp), %eax
|
|---|
| 46 | movl SRC(%esp), %esi
|
|---|
| 47 | cfi_rel_offset (esi, 0)
|
|---|
| 48 | movl LEN(%esp), %ecx
|
|---|
| 49 | CHECK_BOUNDS_LOW (%eax, DEST(%esp))
|
|---|
| 50 | CHECK_BOUNDS_LOW (%esi, SRC(%esp))
|
|---|
| 51 |
|
|---|
| 52 | subl %eax, %esi /* magic: reduce number of loop variants
|
|---|
| 53 | to one using addressing mode */
|
|---|
| 54 | jmp L(1) /* jump to loop "head" */
|
|---|
| 55 |
|
|---|
| 56 | ALIGN(4)
|
|---|
| 57 |
|
|---|
| 58 | /* Four times unfolded loop with two loop counters. We get the
|
|---|
| 59 | the third value (the source address) by using the index+base
|
|---|
| 60 | addressing mode. */
|
|---|
| 61 | L(2): movb (%eax,%esi), %dl /* load current char */
|
|---|
| 62 | movb %dl, (%eax) /* and store it */
|
|---|
| 63 | testb %dl, %dl /* was it NUL? */
|
|---|
| 64 | jz L(7) /* yes, then exit */
|
|---|
| 65 |
|
|---|
| 66 | movb 1(%eax,%esi), %dl /* load current char */
|
|---|
| 67 | movb %dl, 1(%eax) /* and store it */
|
|---|
| 68 | testb %dl, %dl /* was it NUL? */
|
|---|
| 69 | jz L(6) /* yes, then exit */
|
|---|
| 70 |
|
|---|
| 71 | movb 2(%eax,%esi), %dl /* load current char */
|
|---|
| 72 | movb %dl, 2(%eax) /* and store it */
|
|---|
| 73 | testb %dl, %dl /* was it NUL? */
|
|---|
| 74 | jz L(5) /* yes, then exit */
|
|---|
| 75 |
|
|---|
| 76 | movb 3(%eax,%esi), %dl /* load current char */
|
|---|
| 77 | movb %dl, 3(%eax) /* and store it */
|
|---|
| 78 | testb %dl, %dl /* was it NUL? */
|
|---|
| 79 | jz L(4) /* yes, then exit */
|
|---|
| 80 |
|
|---|
| 81 | addl $4, %eax /* increment loop counter for full round */
|
|---|
| 82 |
|
|---|
| 83 | L(1): subl $4, %ecx /* still more than 4 bytes allowed? */
|
|---|
| 84 | jae L(2) /* yes, then go to start of loop */
|
|---|
| 85 |
|
|---|
| 86 | /* The maximal remaining 15 bytes are not processed in a loop. */
|
|---|
| 87 |
|
|---|
| 88 | addl $4, %ecx /* correct above subtraction */
|
|---|
| 89 | jz L(9) /* maximal allowed char reached => go to end */
|
|---|
| 90 |
|
|---|
| 91 | movb (%eax,%esi), %dl /* load current char */
|
|---|
| 92 | movb %dl, (%eax) /* and store it */
|
|---|
| 93 | testb %dl, %dl /* was it NUL? */
|
|---|
| 94 | jz L(3) /* yes, then exit */
|
|---|
| 95 |
|
|---|
| 96 | incl %eax /* increment pointer */
|
|---|
| 97 | decl %ecx /* decrement length counter */
|
|---|
| 98 | jz L(9) /* no more allowed => exit */
|
|---|
| 99 |
|
|---|
| 100 | movb (%eax,%esi), %dl /* load current char */
|
|---|
| 101 | movb %dl, (%eax) /* and store it */
|
|---|
| 102 | testb %dl, %dl /* was it NUL? */
|
|---|
| 103 | jz L(3) /* yes, then exit */
|
|---|
| 104 |
|
|---|
| 105 | incl %eax /* increment pointer */
|
|---|
| 106 | decl %ecx /* decrement length counter */
|
|---|
| 107 | jz L(9) /* no more allowed => exit */
|
|---|
| 108 |
|
|---|
| 109 | movb (%eax,%esi), %dl /* load current char */
|
|---|
| 110 | movb %dl, (%eax) /* and store it */
|
|---|
| 111 | testb %dl, %dl /* was it NUL? */
|
|---|
| 112 | jz L(3) /* yes, then exit */
|
|---|
| 113 |
|
|---|
| 114 | incl %eax /* increment pointer */
|
|---|
| 115 | jmp L(9) /* we don't have to test for counter underflow
|
|---|
| 116 | because we know we had a most 3 bytes
|
|---|
| 117 | remaining => exit */
|
|---|
| 118 |
|
|---|
| 119 | /* When coming from the main loop we have to adjust the pointer. */
|
|---|
| 120 | L(4): decl %ecx /* decrement counter */
|
|---|
| 121 | incl %eax /* increment pointer */
|
|---|
| 122 |
|
|---|
| 123 | L(5): decl %ecx /* increment pointer */
|
|---|
| 124 | incl %eax /* increment pointer */
|
|---|
| 125 |
|
|---|
| 126 | L(6): decl %ecx /* increment pointer */
|
|---|
| 127 | incl %eax /* increment pointer */
|
|---|
| 128 | L(7):
|
|---|
| 129 |
|
|---|
| 130 | addl $3, %ecx /* correct pre-decrementation of counter
|
|---|
| 131 | at the beginning of the loop; but why 3
|
|---|
| 132 | and not 4? Very simple, we have to count
|
|---|
| 133 | the NUL char we already wrote. */
|
|---|
| 134 | jz L(9) /* counter is also 0 => exit */
|
|---|
| 135 |
|
|---|
| 136 | /* We now have to fill the rest of the buffer with NUL. This
|
|---|
| 137 | is done in a tricky way. Please note that the addressing mode
|
|---|
| 138 | used below is not the same we used above. Here we use the
|
|---|
| 139 | %ecx register. */
|
|---|
| 140 | L(8):
|
|---|
| 141 | movb $0, (%ecx,%eax) /* store NUL char */
|
|---|
| 142 | L(3): decl %ecx /* all bytes written? */
|
|---|
| 143 | jnz L(8) /* no, then again */
|
|---|
| 144 |
|
|---|
| 145 | L(9):
|
|---|
| 146 | #if __BOUNDED_POINTERS__
|
|---|
| 147 | addl %eax, %esi /* undo magic: %esi now points beyond end of SRC */
|
|---|
| 148 | CHECK_BOUNDS_HIGH (%esi, SRC(%esp), jbe)
|
|---|
| 149 | CHECK_BOUNDS_HIGH (%eax, DEST(%esp), jbe)
|
|---|
| 150 | RETURN_BOUNDED_POINTER (DEST(%esp))
|
|---|
| 151 | #endif
|
|---|
| 152 | popl %esi /* restore saved register content */
|
|---|
| 153 | cfi_adjust_cfa_offset (-4)
|
|---|
| 154 | cfi_restore (esi)
|
|---|
| 155 |
|
|---|
| 156 | LEAVE
|
|---|
| 157 | RET_PTR
|
|---|
| 158 | END (BP_SYM (__stpncpy))
|
|---|
| 159 |
|
|---|
| 160 | libc_hidden_def (BP_SYM (__stpncpy))
|
|---|
| 161 | weak_alias (BP_SYM (__stpncpy), BP_SYM (stpncpy))
|
|---|