]>
Commit | Line | Data |
---|---|---|
59dd8641 | 1 | /* strtok (str, delim) -- Return next DELIM separated token from STR. |
5929563f | 2 | For Intel 80x86, x>=3. |
ef5166a6 | 3 | Copyright (C) 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc. |
5929563f UD |
4 | This file is part of the GNU C Library. |
5 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. | |
6 | ||
7 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
8 | modify it under the terms of the GNU Lesser General Public |
9 | License as published by the Free Software Foundation; either | |
10 | version 2.1 of the License, or (at your option) any later version. | |
5929563f UD |
11 | |
12 | The GNU C Library is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 15 | Lesser General Public License for more details. |
5929563f | 16 | |
41bdb6e2 AJ |
17 | You should have received a copy of the GNU Lesser General Public |
18 | License along with the GNU C Library; if not, write to the Free | |
19 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
20 | 02111-1307 USA. */ | |
59dd8641 | 21 | |
59dd8641 | 22 | #include <sysdep.h> |
5929563f | 23 | #include "asm-syntax.h" |
2fc08826 | 24 | #include "bp-sym.h" |
3f02f778 | 25 | #include "bp-asm.h" |
59dd8641 RM |
26 | |
27 | /* This file can be used for three variants of the strtok function: | |
28 | ||
29 | strtok: | |
30 | INPUT PARAMETER: | |
31 | str (sp + 4) | |
32 | delim (sp + 8) | |
33 | ||
34 | strtok_r: | |
35 | INPUT PARAMETER: | |
36 | str (sp + 4) | |
37 | delim (sp + 8) | |
38 | save_ptr (sp + 12) | |
39 | ||
59dd8641 RM |
40 | We do a common implementation here. */ |
41 | ||
2ed5fd9a GM |
42 | #ifdef USE_AS_STRTOK_R |
43 | # define SAVE_PTR 0(%ecx) | |
44 | #else | |
59dd8641 RM |
45 | .bss |
46 | .local save_ptr | |
47 | ASM_TYPE_DIRECTIVE (save_ptr, @object) | |
48 | .size save_ptr, 4 | |
49 | save_ptr: | |
2ed5fd9a GM |
50 | # if __BOUNDED_POINTERS__ |
51 | .space 12 | |
52 | # else | |
59dd8641 | 53 | .space 4 |
2ed5fd9a GM |
54 | # endif |
55 | ||
56 | # ifdef PIC | |
57 | # define SAVE_PTR save_ptr@GOTOFF(%ebx) | |
58 | # else | |
59 | # define SAVE_PTR save_ptr | |
60 | # endif | |
59dd8641 | 61 | |
2ed5fd9a | 62 | # define FUNCTION strtok |
59dd8641 RM |
63 | #endif |
64 | ||
3f02f778 GM |
65 | #define PARMS LINKAGE /* no space for saved regs */ |
66 | #define RTN PARMS | |
67 | #define STR RTN+RTN_SIZE | |
68 | #define DELIM STR+PTR_SIZE | |
69 | #define SAVE DELIM+PTR_SIZE | |
70 | ||
59dd8641 | 71 | .text |
2fc08826 | 72 | ENTRY (BP_SYM (FUNCTION)) |
3f02f778 | 73 | ENTER |
59dd8641 | 74 | |
3f02f778 GM |
75 | movl STR(%esp), %edx |
76 | movl DELIM(%esp), %eax | |
2fc08826 | 77 | CHECK_BOUNDS_LOW (%eax, DELIM(%esp)) |
59dd8641 | 78 | |
2ed5fd9a | 79 | #if !defined USE_AS_STRTOK_R && defined PIC |
59dd8641 | 80 | pushl %ebx /* Save PIC register. */ |
5929563f UD |
81 | call L(here) |
82 | L(here): | |
83 | popl %ebx | |
84 | addl $_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebx | |
76060ec0 | 85 | #endif |
59dd8641 RM |
86 | |
87 | /* If the pointer is NULL we have to use the stored value of | |
88 | the last run. */ | |
89 | cmpl $0, %edx | |
2ed5fd9a GM |
90 | #if __BOUNDED_POINTERS__ |
91 | movl SAVE(%esp), %ecx | |
92 | je L(0) | |
93 | /* Save bounds of incoming non-NULL STR into save area. */ | |
94 | movl 4+STR(%esp), %eax | |
95 | movl %eax, 4+SAVE_PTR | |
96 | movl 8+STR(%esp), %eax | |
97 | movl %eax, 8+SAVE_PTR | |
98 | CHECK_BOUNDS_LOW (%edx, SAVE_PTR) | |
99 | jmp L(1) | |
100 | L(0): movl SAVE_PTR, %edx | |
101 | CHECK_BOUNDS_LOW (%edx, SAVE_PTR) | |
102 | jmp L(1) | |
103 | #else | |
104 | jne L(1) | |
105 | #endif | |
59dd8641 | 106 | |
76060ec0 | 107 | #ifdef USE_AS_STRTOK_R |
59dd8641 | 108 | /* The value is stored in the third argument. */ |
3f02f778 | 109 | movl SAVE(%esp), %edx |
59dd8641 | 110 | movl (%edx), %edx |
76060ec0 | 111 | #else |
59dd8641 RM |
112 | /* The value is in the local variable defined above. But |
113 | we have to take care for PIC code. */ | |
2ed5fd9a | 114 | movl SAVE_PTR, %edx |
59dd8641 | 115 | #endif |
ef5166a6 UD |
116 | testl %edx, %edx |
117 | jz L(returnNULL) | |
59dd8641 | 118 | |
2ed5fd9a | 119 | L(1): |
59dd8641 RM |
120 | /* First we create a table with flags for all possible characters. |
121 | For the ASCII (7bit/8bit) or ISO-8859-X character sets which are | |
122 | supported by the C string functions we have 256 characters. | |
123 | Before inserting marks for the stop characters we clear the whole | |
124 | table. The unrolled form is much faster than a loop. */ | |
125 | xorl %ecx, %ecx /* %ecx = 0 !!! */ | |
126 | ||
127 | pushl %ecx /* make a 256 bytes long block filled with 0 */ | |
128 | pushl %ecx | |
129 | pushl %ecx | |
130 | pushl %ecx | |
131 | pushl %ecx | |
132 | pushl %ecx | |
133 | pushl %ecx | |
134 | pushl %ecx | |
135 | pushl %ecx | |
136 | pushl %ecx | |
137 | pushl %ecx | |
138 | pushl %ecx | |
139 | pushl %ecx | |
140 | pushl %ecx | |
141 | pushl %ecx | |
142 | pushl %ecx | |
143 | pushl %ecx | |
144 | pushl %ecx | |
145 | pushl %ecx | |
146 | pushl %ecx | |
147 | pushl %ecx | |
148 | pushl %ecx | |
149 | pushl %ecx | |
150 | pushl %ecx | |
151 | pushl %ecx | |
152 | pushl %ecx | |
153 | pushl %ecx | |
154 | pushl %ecx | |
155 | pushl %ecx | |
156 | pushl %ecx | |
157 | pushl %ecx | |
158 | pushl %ecx | |
159 | pushl %ecx | |
160 | pushl %ecx | |
161 | pushl %ecx | |
162 | pushl %ecx | |
163 | pushl %ecx | |
164 | pushl %ecx | |
165 | pushl %ecx | |
166 | pushl %ecx | |
167 | pushl %ecx | |
168 | pushl %ecx | |
169 | pushl %ecx | |
170 | pushl %ecx | |
171 | pushl %ecx | |
172 | pushl %ecx | |
173 | pushl %ecx | |
174 | pushl %ecx | |
175 | pushl %ecx | |
176 | pushl %ecx | |
177 | pushl %ecx | |
178 | pushl %ecx | |
179 | pushl %ecx | |
180 | pushl %ecx | |
181 | pushl %ecx | |
182 | pushl %ecx | |
183 | pushl %ecx | |
184 | pushl %ecx | |
185 | pushl $0 /* These immediate values make the label 2 */ | |
186 | pushl $0 /* to be aligned on a 16 byte boundary to */ | |
187 | pushl $0 /* get a better performance of the loop. */ | |
188 | pushl $0 | |
189 | pushl $0 | |
190 | pushl $0 | |
191 | ||
192 | /* For understanding the following code remember that %ecx == 0 now. | |
193 | Although all the following instruction only modify %cl we always | |
194 | have a correct zero-extended 32-bit value in %ecx. */ | |
195 | ||
5929563f | 196 | L(2): movb (%eax), %cl /* get byte from stopset */ |
59dd8641 | 197 | testb %cl, %cl /* is NUL char? */ |
2fc08826 | 198 | jz L(1_1) /* yes => start compare loop */ |
59dd8641 RM |
199 | movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */ |
200 | ||
201 | movb 1(%eax), %cl /* get byte from stopset */ | |
202 | testb $0xff, %cl /* is NUL char? */ | |
2fc08826 | 203 | jz L(1_2) /* yes => start compare loop */ |
59dd8641 RM |
204 | movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */ |
205 | ||
206 | movb 2(%eax), %cl /* get byte from stopset */ | |
207 | testb $0xff, %cl /* is NUL char? */ | |
2fc08826 | 208 | jz L(1_3) /* yes => start compare loop */ |
59dd8641 RM |
209 | movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */ |
210 | ||
211 | movb 3(%eax), %cl /* get byte from stopset */ | |
212 | addl $4, %eax /* increment stopset pointer */ | |
213 | movb %cl, (%esp,%ecx) /* set corresponding byte in stopset table */ | |
214 | testb $0xff, %cl /* is NUL char? */ | |
5929563f | 215 | jnz L(2) /* no => process next dword from stopset */ |
59dd8641 | 216 | |
2fc08826 GM |
217 | #if __BOUNDED_POINTERS__ |
218 | jmp L(1_0) /* pointer is correct for bounds check */ | |
219 | L(1_3): incl %eax /* adjust pointer for bounds check */ | |
220 | L(1_2): incl %eax /* ditto */ | |
221 | L(1_1): incl %eax /* ditto */ | |
2ed5fd9a | 222 | L(1_0): CHECK_BOUNDS_HIGH (%eax, DELIM(%esp), jbe) |
2fc08826 GM |
223 | #else |
224 | L(1_3):; L(1_2):; L(1_1): /* fall through */ | |
225 | #endif | |
226 | leal -4(%edx), %eax /* prepare loop */ | |
59dd8641 RM |
227 | |
228 | /* We use a neat trick for the following loop. Normally we would | |
229 | have to test for two termination conditions | |
230 | 1. a character in the stopset was found | |
231 | and | |
232 | 2. the end of the string was found | |
76060ec0 RM |
233 | As a sign that the character is in the stopset we store its |
234 | value in the table. The value of NUL is NUL so the loop | |
59dd8641 RM |
235 | terminates for NUL in every case. */ |
236 | ||
5929563f | 237 | L(3): addl $4, %eax /* adjust pointer for full loop round */ |
59dd8641 RM |
238 | |
239 | movb (%eax), %cl /* get byte from string */ | |
240 | testb %cl, (%esp,%ecx) /* is it contained in stopset? */ | |
5929563f | 241 | jz L(4) /* no => start of token */ |
59dd8641 RM |
242 | |
243 | movb 1(%eax), %cl /* get byte from string */ | |
244 | testb %cl, (%esp,%ecx) /* is it contained in stopset? */ | |
5929563f | 245 | jz L(5) /* no => start of token */ |
59dd8641 RM |
246 | |
247 | movb 2(%eax), %cl /* get byte from string */ | |
248 | testb %cl, (%esp,%ecx) /* is it contained in stopset? */ | |
5929563f | 249 | jz L(6) /* no => start of token */ |
59dd8641 RM |
250 | |
251 | movb 3(%eax), %cl /* get byte from string */ | |
252 | testb %cl, (%esp,%ecx) /* is it contained in stopset? */ | |
5929563f | 253 | jnz L(3) /* yes => start of loop */ |
59dd8641 RM |
254 | |
255 | incl %eax /* adjust pointer */ | |
5929563f UD |
256 | L(6): incl %eax |
257 | L(5): incl %eax | |
59dd8641 RM |
258 | |
259 | /* Now we have to terminate the string. */ | |
260 | ||
5929563f | 261 | L(4): leal -4(%eax), %edx /* We use %EDX for the next run. */ |
59dd8641 | 262 | |
5929563f | 263 | L(7): addl $4, %edx /* adjust pointer for full loop round */ |
59dd8641 RM |
264 | |
265 | movb (%edx), %cl /* get byte from string */ | |
266 | cmpb %cl, (%esp,%ecx) /* is it contained in skipset? */ | |
5929563f | 267 | je L(8) /* yes => return */ |
59dd8641 RM |
268 | |
269 | movb 1(%edx), %cl /* get byte from string */ | |
270 | cmpb %cl, (%esp,%ecx) /* is it contained in skipset? */ | |
5929563f | 271 | je L(9) /* yes => return */ |
59dd8641 RM |
272 | |
273 | movb 2(%edx), %cl /* get byte from string */ | |
274 | cmpb %cl, (%esp,%ecx) /* is it contained in skipset? */ | |
5929563f | 275 | je L(10) /* yes => return */ |
59dd8641 RM |
276 | |
277 | movb 3(%edx), %cl /* get byte from string */ | |
278 | cmpb %cl, (%esp,%ecx) /* is it contained in skipset? */ | |
5929563f | 279 | jne L(7) /* no => start loop again */ |
59dd8641 RM |
280 | |
281 | incl %edx /* adjust pointer */ | |
5929563f UD |
282 | L(10): incl %edx |
283 | L(9): incl %edx | |
59dd8641 | 284 | |
5929563f | 285 | L(8): /* Remove the stopset table. */ |
59dd8641 RM |
286 | addl $256, %esp |
287 | ||
288 | cmpl %eax, %edx | |
5929563f | 289 | je L(returnNULL) /* There was no token anymore. */ |
59dd8641 RM |
290 | |
291 | movb $0, (%edx) /* Terminate string. */ | |
292 | ||
293 | /* Are we at end of string? */ | |
294 | cmpb $0, %cl | |
5929563f | 295 | je L(11) |
59dd8641 RM |
296 | |
297 | incl %edx | |
5929563f | 298 | L(11): |
59dd8641 RM |
299 | |
300 | /* Store the pointer to the next character. */ | |
301 | #ifdef USE_AS_STRTOK_R | |
3f02f778 | 302 | movl SAVE(%esp), %ecx |
2fc08826 | 303 | #endif |
2ed5fd9a GM |
304 | movl %edx, SAVE_PTR |
305 | CHECK_BOUNDS_HIGH (%edx, SAVE_PTR, jb) | |
306 | RETURN_BOUNDED_POINTER (SAVE_PTR) | |
307 | ||
308 | L(epilogue): | |
309 | #if !defined USE_AS_STRTOK_R && defined PIC | |
310 | popl %ebx | |
59dd8641 | 311 | #endif |
3f02f778 GM |
312 | LEAVE |
313 | RET_PTR | |
59dd8641 | 314 | |
5929563f | 315 | L(returnNULL): |
59dd8641 | 316 | xorl %eax, %eax |
2fc08826 | 317 | RETURN_NULL_BOUNDED_POINTER |
2ed5fd9a | 318 | jmp L(epilogue) |
2fc08826 GM |
319 | |
320 | END (BP_SYM (FUNCTION)) |