Update to LGPL v2.1.
[kopensolaris-gnu/glibc.git] / sysdeps / i386 / strtok.S
1 /* strtok (str, delim) -- Return next DELIM separated token from STR.
2    For Intel 80x86, x>=3.
3    Copyright (C) 1996, 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
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
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.
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
15    Lesser General Public License for more details.
16
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.  */
21
22 #include <sysdep.h>
23 #include "asm-syntax.h"
24 #include "bp-sym.h"
25 #include "bp-asm.h"
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
40    We do a common implementation here.  */
41
42 #ifdef USE_AS_STRTOK_R
43 # define SAVE_PTR 0(%ecx)
44 #else
45         .bss
46         .local save_ptr
47         ASM_TYPE_DIRECTIVE (save_ptr, @object)
48         .size save_ptr, 4
49 save_ptr:
50 # if __BOUNDED_POINTERS__
51         .space 12
52 # else
53         .space 4
54 # endif
55
56 # ifdef PIC
57 #  define SAVE_PTR save_ptr@GOTOFF(%ebx)
58 # else
59 #  define SAVE_PTR save_ptr
60 # endif
61
62 # define FUNCTION strtok
63 #endif
64
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
71         .text
72 ENTRY (BP_SYM (FUNCTION))
73         ENTER
74
75         movl STR(%esp), %edx
76         movl DELIM(%esp), %eax
77         CHECK_BOUNDS_LOW (%eax, DELIM(%esp))
78
79 #if !defined USE_AS_STRTOK_R && defined PIC
80         pushl %ebx                      /* Save PIC register.  */
81         call L(here)
82 L(here):
83         popl %ebx
84         addl $_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebx
85 #endif
86
87         /* If the pointer is NULL we have to use the stored value of
88            the last run.  */
89         cmpl $0, %edx
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
106
107 #ifdef USE_AS_STRTOK_R
108         /* The value is stored in the third argument.  */
109         movl SAVE(%esp), %edx
110         movl (%edx), %edx
111 #else
112         /* The value is in the local variable defined above.  But
113            we have to take care for PIC code.  */
114         movl SAVE_PTR, %edx
115 #endif
116         testl %edx, %edx
117         jz L(returnNULL)
118
119 L(1):
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
196 L(2):   movb (%eax), %cl        /* get byte from stopset */
197         testb %cl, %cl          /* is NUL char? */
198         jz L(1_1)               /* yes => start compare loop */
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? */
203         jz L(1_2)               /* yes => start compare loop */
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? */
208         jz L(1_3)               /* yes => start compare loop */
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? */
215         jnz L(2)                /* no => process next dword from stopset */
216
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 */
222 L(1_0): CHECK_BOUNDS_HIGH (%eax, DELIM(%esp), jbe)
223 #else
224 L(1_3):; L(1_2):; L(1_1):       /* fall through */
225 #endif
226         leal -4(%edx), %eax     /* prepare loop */
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
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
235            terminates for NUL in every case.  */
236
237 L(3):   addl $4, %eax           /* adjust pointer for full loop round */
238
239         movb (%eax), %cl        /* get byte from string */
240         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
241         jz L(4)                 /* no => start of token */
242
243         movb 1(%eax), %cl       /* get byte from string */
244         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
245         jz L(5)                 /* no => start of token */
246
247         movb 2(%eax), %cl       /* get byte from string */
248         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
249         jz L(6)                 /* no => start of token */
250
251         movb 3(%eax), %cl       /* get byte from string */
252         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
253         jnz L(3)                /* yes => start of loop */
254
255         incl %eax               /* adjust pointer */
256 L(6):   incl %eax
257 L(5):   incl %eax
258
259         /* Now we have to terminate the string.  */
260
261 L(4):   leal -4(%eax), %edx     /* We use %EDX for the next run.  */
262
263 L(7):   addl $4, %edx           /* adjust pointer for full loop round */
264
265         movb (%edx), %cl        /* get byte from string */
266         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
267         je L(8)                 /* yes => return */
268
269         movb 1(%edx), %cl       /* get byte from string */
270         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
271         je L(9)                 /* yes => return */
272
273         movb 2(%edx), %cl       /* get byte from string */
274         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
275         je L(10)                /* yes => return */
276
277         movb 3(%edx), %cl       /* get byte from string */
278         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
279         jne L(7)                /* no => start loop again */
280
281         incl %edx               /* adjust pointer */
282 L(10):  incl %edx
283 L(9):   incl %edx
284
285 L(8):   /* Remove the stopset table.  */
286         addl $256, %esp
287
288         cmpl %eax, %edx
289         je L(returnNULL)        /* There was no token anymore.  */
290
291         movb $0, (%edx)         /* Terminate string.  */
292
293         /* Are we at end of string?  */
294         cmpb $0, %cl
295         je L(11)
296
297         incl %edx
298 L(11):
299
300         /* Store the pointer to the next character.  */
301 #ifdef USE_AS_STRTOK_R
302         movl SAVE(%esp), %ecx
303 #endif
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
311 #endif
312         LEAVE
313         RET_PTR
314
315 L(returnNULL):
316         xorl %eax, %eax
317         RETURN_NULL_BOUNDED_POINTER
318         jmp L(epilogue)
319
320 END (BP_SYM (FUNCTION))