]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/i386/strtok.S
Update to LGPL v2.1.
[thirdparty/glibc.git] / sysdeps / i386 / strtok.S
CommitLineData
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
49save_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 72ENTRY (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)
82L(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)
100L(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 119L(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 196L(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 */
219L(1_3): incl %eax /* adjust pointer for bounds check */
220L(1_2): incl %eax /* ditto */
221L(1_1): incl %eax /* ditto */
2ed5fd9a 222L(1_0): CHECK_BOUNDS_HIGH (%eax, DELIM(%esp), jbe)
2fc08826
GM
223#else
224L(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 237L(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
256L(6): incl %eax
257L(5): incl %eax
59dd8641
RM
258
259 /* Now we have to terminate the string. */
260
5929563f 261L(4): leal -4(%eax), %edx /* We use %EDX for the next run. */
59dd8641 262
5929563f 263L(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
282L(10): incl %edx
283L(9): incl %edx
59dd8641 284
5929563f 285L(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 298L(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
308L(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 315L(returnNULL):
59dd8641 316 xorl %eax, %eax
2fc08826 317 RETURN_NULL_BOUNDED_POINTER
2ed5fd9a 318 jmp L(epilogue)
2fc08826
GM
319
320END (BP_SYM (FUNCTION))