[BZ #2126]
[platform/upstream/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-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.
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         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
90
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
110
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)
122
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 !!! */
130
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)
259
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.  */
263
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 */
268
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 */
273
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 */
278
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 */
284
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 */
295
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.  */
304
305 L(3):   addl $4, %eax           /* adjust pointer for full loop round */
306
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 */
310
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 */
314
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 */
318
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 */
322
323         incl %eax               /* adjust pointer */
324 L(6):   incl %eax
325 L(5):   incl %eax
326
327         /* Now we have to terminate the string.  */
328
329 L(4):   leal -4(%eax), %edx     /* We use %EDX for the next run.  */
330
331 L(7):   addl $4, %edx           /* adjust pointer for full loop round */
332
333         movb (%edx), %cl        /* get byte from string */
334         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
335         je L(8)                 /* yes => return */
336
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 */
340
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 */
344
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 */
348
349         incl %edx               /* adjust pointer */
350 L(10):  incl %edx
351 L(9):   incl %edx
352
353 L(8):   /* Remove the stopset table.  */
354         addl $256, %esp
355         cfi_adjust_cfa_offset (-256)
356
357         cmpl %eax, %edx
358         je L(returnNULL)        /* There was no token anymore.  */
359
360         movb $0, (%edx)         /* Terminate string.  */
361
362         /* Are we at end of string?  */
363         cmpb $0, %cl
364         je L(11)
365
366         incl %edx
367 L(11):
368
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)
376
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
385
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)
394
395 END (BP_SYM (FUNCTION))