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