.
[glibc/history.git] / sysdeps / i386 / strtok.S
blobc5f40a83b1e77d383a36785cd876f1183da636a6
1 /* strtok (str, delim) -- Return next DELIM separated token from STR.
2    For Intel 80x86, x>=3.
3    Copyright (C) 1996-1998,2000,2001,2005,2006 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
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.
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.
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.  */
22 #include <sysdep.h>
23 #include "asm-syntax.h"
24 #include "bp-sym.h"
25 #include "bp-asm.h"
27 /* This file can be used for three variants of the strtok function:
29    strtok:
30         INPUT PARAMETER:
31         str             (sp + 4)
32         delim           (sp + 8)
34    strtok_r:
35         INPUT PARAMETER:
36         str             (sp + 4)
37         delim           (sp + 8)
38         save_ptr        (sp + 12)
40    We do a common implementation here.  */
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
56 # ifdef PIC
57 #  define SAVE_PTR save_ptr@GOTOFF(%ebx)
58 # else
59 #  define SAVE_PTR save_ptr
60 # endif
62 # define FUNCTION strtok
63 #endif
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
71         .text
72 ENTRY (BP_SYM (FUNCTION))
73         ENTER
75         movl STR(%esp), %edx
76         movl DELIM(%esp), %eax
77         CHECK_BOUNDS_LOW (%eax, DELIM(%esp))
79 #if !defined USE_AS_STRTOK_R && defined PIC
80         pushl %ebx                      /* Save PIC register.  */
81         cfi_adjust_cfa_offset (4)
82         call L(here)
83         cfi_adjust_cfa_offset (4)
84         cfi_rel_offset (ebx, 0)
85 L(here):
86         popl %ebx
87         cfi_adjust_cfa_offset (-4)
88         addl $_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebx
89 #endif
91         /* If the pointer is NULL we have to use the stored value of
92            the last run.  */
93         cmpl $0, %edx
94 #if __BOUNDED_POINTERS__
95         movl SAVE(%esp), %ecx
96         je L(0)
97         /* Save bounds of incoming non-NULL STR into save area.  */
98         movl 4+STR(%esp), %eax
99         movl %eax, 4+SAVE_PTR
100         movl 8+STR(%esp), %eax
101         movl %eax, 8+SAVE_PTR
102         CHECK_BOUNDS_LOW (%edx, SAVE_PTR)
103         jmp L(1)
104 L(0):   movl SAVE_PTR, %edx
105         CHECK_BOUNDS_LOW (%edx, SAVE_PTR)
106         jmp L(1)
107 #else
108         jne L(1)
109 #endif
111 #ifdef USE_AS_STRTOK_R
112         /* The value is stored in the third argument.  */
113         movl SAVE(%esp), %edx
114         movl (%edx), %edx
115 #else
116         /* The value is in the local variable defined above.  But
117            we have to take care for PIC code.  */
118         movl SAVE_PTR, %edx
119 #endif
120         testl %edx, %edx
121         jz L(returnNULL)
123 L(1):
124         /* First we create a table with flags for all possible characters.
125            For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
126            supported by the C string functions we have 256 characters.
127            Before inserting marks for the stop characters we clear the whole
128            table.  The unrolled form is much faster than a loop.  */
129         xorl %ecx, %ecx         /* %ecx = 0 !!! */
131         pushl %ecx              /* make a 256 bytes long block filled with 0 */
132         cfi_adjust_cfa_offset (4)
133         pushl %ecx
134         cfi_adjust_cfa_offset (4)
135         pushl %ecx
136         cfi_adjust_cfa_offset (4)
137         pushl %ecx
138         cfi_adjust_cfa_offset (4)
139         pushl %ecx
140         cfi_adjust_cfa_offset (4)
141         pushl %ecx
142         cfi_adjust_cfa_offset (4)
143         pushl %ecx
144         cfi_adjust_cfa_offset (4)
145         pushl %ecx
146         cfi_adjust_cfa_offset (4)
147         pushl %ecx
148         cfi_adjust_cfa_offset (4)
149         pushl %ecx
150         cfi_adjust_cfa_offset (4)
151         pushl %ecx
152         cfi_adjust_cfa_offset (4)
153         pushl %ecx
154         cfi_adjust_cfa_offset (4)
155         pushl %ecx
156         cfi_adjust_cfa_offset (4)
157         pushl %ecx
158         cfi_adjust_cfa_offset (4)
159         pushl %ecx
160         cfi_adjust_cfa_offset (4)
161         pushl %ecx
162         cfi_adjust_cfa_offset (4)
163         pushl %ecx
164         cfi_adjust_cfa_offset (4)
165         pushl %ecx
166         cfi_adjust_cfa_offset (4)
167         pushl %ecx
168         cfi_adjust_cfa_offset (4)
169         pushl %ecx
170         cfi_adjust_cfa_offset (4)
171         pushl %ecx
172         cfi_adjust_cfa_offset (4)
173         pushl %ecx
174         cfi_adjust_cfa_offset (4)
175         pushl %ecx
176         cfi_adjust_cfa_offset (4)
177         pushl %ecx
178         cfi_adjust_cfa_offset (4)
179         pushl %ecx
180         cfi_adjust_cfa_offset (4)
181         pushl %ecx
182         cfi_adjust_cfa_offset (4)
183         pushl %ecx
184         cfi_adjust_cfa_offset (4)
185         pushl %ecx
186         cfi_adjust_cfa_offset (4)
187         pushl %ecx
188         cfi_adjust_cfa_offset (4)
189         pushl %ecx
190         cfi_adjust_cfa_offset (4)
191         pushl %ecx
192         cfi_adjust_cfa_offset (4)
193         pushl %ecx
194         cfi_adjust_cfa_offset (4)
195         pushl %ecx
196         cfi_adjust_cfa_offset (4)
197         pushl %ecx
198         cfi_adjust_cfa_offset (4)
199         pushl %ecx
200         cfi_adjust_cfa_offset (4)
201         pushl %ecx
202         cfi_adjust_cfa_offset (4)
203         pushl %ecx
204         cfi_adjust_cfa_offset (4)
205         pushl %ecx
206         cfi_adjust_cfa_offset (4)
207         pushl %ecx
208         cfi_adjust_cfa_offset (4)
209         pushl %ecx
210         cfi_adjust_cfa_offset (4)
211         pushl %ecx
212         cfi_adjust_cfa_offset (4)
213         pushl %ecx
214         cfi_adjust_cfa_offset (4)
215         pushl %ecx
216         cfi_adjust_cfa_offset (4)
217         pushl %ecx
218         cfi_adjust_cfa_offset (4)
219         pushl %ecx
220         cfi_adjust_cfa_offset (4)
221         pushl %ecx
222         cfi_adjust_cfa_offset (4)
223         pushl %ecx
224         cfi_adjust_cfa_offset (4)
225         pushl %ecx
226         cfi_adjust_cfa_offset (4)
227         pushl %ecx
228         cfi_adjust_cfa_offset (4)
229         pushl %ecx
230         cfi_adjust_cfa_offset (4)
231         pushl %ecx
232         cfi_adjust_cfa_offset (4)
233         pushl %ecx
234         cfi_adjust_cfa_offset (4)
235         pushl %ecx
236         cfi_adjust_cfa_offset (4)
237         pushl %ecx
238         cfi_adjust_cfa_offset (4)
239         pushl %ecx
240         cfi_adjust_cfa_offset (4)
241         pushl %ecx
242         cfi_adjust_cfa_offset (4)
243         pushl %ecx
244         cfi_adjust_cfa_offset (4)
245         pushl %ecx
246         cfi_adjust_cfa_offset (4)
247         pushl $0                /* These immediate values make the label 2 */
248         cfi_adjust_cfa_offset (4)
249         pushl $0                /* to be aligned on a 16 byte boundary to */
250         cfi_adjust_cfa_offset (4)
251         pushl $0                /* get a better performance of the loop.  */
252         cfi_adjust_cfa_offset (4)
253         pushl $0
254         cfi_adjust_cfa_offset (4)
255         pushl $0
256         cfi_adjust_cfa_offset (4)
257         pushl $0
258         cfi_adjust_cfa_offset (4)
260 /* For understanding the following code remember that %ecx == 0 now.
261    Although all the following instruction only modify %cl we always
262    have a correct zero-extended 32-bit value in %ecx.  */
264 L(2):   movb (%eax), %cl        /* get byte from stopset */
265         testb %cl, %cl          /* is NUL char? */
266         jz L(1_1)               /* yes => start compare loop */
267         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
269         movb 1(%eax), %cl       /* get byte from stopset */
270         testb $0xff, %cl        /* is NUL char? */
271         jz L(1_2)               /* yes => start compare loop */
272         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
274         movb 2(%eax), %cl       /* get byte from stopset */
275         testb $0xff, %cl        /* is NUL char? */
276         jz L(1_3)               /* yes => start compare loop */
277         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
279         movb 3(%eax), %cl       /* get byte from stopset */
280         addl $4, %eax           /* increment stopset pointer */
281         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
282         testb $0xff, %cl        /* is NUL char? */
283         jnz L(2)                /* no => process next dword from stopset */
285 #if __BOUNDED_POINTERS__
286         jmp L(1_0)              /* pointer is correct for bounds check */
287 L(1_3): incl %eax               /* adjust pointer for bounds check */
288 L(1_2): incl %eax               /* ditto */
289 L(1_1): incl %eax               /* ditto */
290 L(1_0): CHECK_BOUNDS_HIGH (%eax, DELIM(%esp), jbe)
291 #else
292 L(1_3):; L(1_2):; L(1_1):       /* fall through */
293 #endif
294         leal -4(%edx), %eax     /* prepare loop */
296         /* We use a neat trick for the following loop.  Normally we would
297            have to test for two termination conditions
298            1. a character in the stopset was found
299            and
300            2. the end of the string was found
301            As a sign that the character is in the stopset we store its
302            value in the table.  The value of NUL is NUL so the loop
303            terminates for NUL in every case.  */
305 L(3):   addl $4, %eax           /* adjust pointer for full loop round */
307         movb (%eax), %cl        /* get byte from string */
308         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
309         jz L(4)                 /* no => start of token */
311         movb 1(%eax), %cl       /* get byte from string */
312         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
313         jz L(5)                 /* no => start of token */
315         movb 2(%eax), %cl       /* get byte from string */
316         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
317         jz L(6)                 /* no => start of token */
319         movb 3(%eax), %cl       /* get byte from string */
320         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
321         jnz L(3)                /* yes => start of loop */
323         incl %eax               /* adjust pointer */
324 L(6):   incl %eax
325 L(5):   incl %eax
327         /* Now we have to terminate the string.  */
329 L(4):   leal -4(%eax), %edx     /* We use %EDX for the next run.  */
331 L(7):   addl $4, %edx           /* adjust pointer for full loop round */
333         movb (%edx), %cl        /* get byte from string */
334         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
335         je L(8)                 /* yes => return */
337         movb 1(%edx), %cl       /* get byte from string */
338         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
339         je L(9)                 /* yes => return */
341         movb 2(%edx), %cl       /* get byte from string */
342         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
343         je L(10)                /* yes => return */
345         movb 3(%edx), %cl       /* get byte from string */
346         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
347         jne L(7)                /* no => start loop again */
349         incl %edx               /* adjust pointer */
350 L(10):  incl %edx
351 L(9):   incl %edx
353 L(8):   /* Remove the stopset table.  */
354         addl $256, %esp
355         cfi_adjust_cfa_offset (-256)
357         cmpl %eax, %edx
358         je L(returnNULL)        /* There was no token anymore.  */
360         movb $0, (%edx)         /* Terminate string.  */
362         /* Are we at end of string?  */
363         cmpb $0, %cl
364         je L(11)
366         incl %edx
367 L(11):
369         /* Store the pointer to the next character.  */
370 #ifdef USE_AS_STRTOK_R
371         movl SAVE(%esp), %ecx
372 #endif
373         movl %edx, SAVE_PTR
374         CHECK_BOUNDS_HIGH (%edx, SAVE_PTR, jb)
375         RETURN_BOUNDED_POINTER (SAVE_PTR)
377 L(epilogue):
378 #if !defined USE_AS_STRTOK_R && defined PIC
379         popl %ebx
380         cfi_adjust_cfa_offset (-4)
381         cfi_restore (ebx)
382 #endif
383         LEAVE
384         RET_PTR
386 L(returnNULL):
387         xorl %eax, %eax
388 #ifdef USE_AS_STRTOK_R
389         movl SAVE(%esp), %ecx
390 #endif
391         movl %edx, SAVE_PTR
392         RETURN_NULL_BOUNDED_POINTER
393         jmp L(epilogue)
395 END (BP_SYM (FUNCTION))