* sysdeps/i386/add_n.S: Wrap entry-point symbol in BP_SYM ().
[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 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 Library General Public License as
9    published by the Free Software Foundation; either version 2 of the
10    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    Library General Public License for more details.
16
17    You should have received a copy of the GNU Library General Public
18    License along with the GNU C Library; see the file COPYING.LIB.  If not,
19    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20    Boston, MA 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 #ifndef USE_AS_STRTOK_R
43         .bss
44         .local save_ptr
45         ASM_TYPE_DIRECTIVE (save_ptr, @object)
46         .size save_ptr, 4
47 save_ptr:
48         .space 4
49
50 #define FUNCTION strtok
51 #endif
52
53 #define PARMS   LINKAGE         /* no space for saved regs */
54 #define RTN     PARMS
55 #define STR     RTN+RTN_SIZE
56 #define DELIM   STR+PTR_SIZE
57 #define SAVE    DELIM+PTR_SIZE
58
59         .text
60 ENTRY (BP_SYM (FUNCTION))
61         ENTER
62
63         movl STR(%esp), %edx
64         movl DELIM(%esp), %eax
65         CHECK_BOUNDS_LOW (%edx, STR(%esp))
66         CHECK_BOUNDS_LOW (%eax, DELIM(%esp))
67
68 #if !defined (USE_AS_STRTOK_R) && defined (PIC)
69         pushl %ebx                      /* Save PIC register.  */
70         call L(here)
71 L(here):
72         popl %ebx
73         addl $_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebx
74 #endif
75
76         /* If the pointer is NULL we have to use the stored value of
77            the last run.  */
78         cmpl $0, %edx
79         jne L(0)
80
81 #ifdef USE_AS_STRTOK_R
82         /* The value is stored in the third argument.  */
83         movl SAVE(%esp), %edx
84         movl (%edx), %edx
85 #else
86         /* The value is in the local variable defined above.  But
87            we have to take care for PIC code.  */
88 # ifndef PIC
89         movl save_ptr, %edx
90 # else
91         movl save_ptr@GOTOFF(%ebx), %edx
92 # endif
93 #endif
94
95 L(0):
96         /* First we create a table with flags for all possible characters.
97            For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
98            supported by the C string functions we have 256 characters.
99            Before inserting marks for the stop characters we clear the whole
100            table.  The unrolled form is much faster than a loop.  */
101         xorl %ecx, %ecx         /* %ecx = 0 !!! */
102
103         pushl %ecx              /* make a 256 bytes long block filled with 0 */
104         pushl %ecx
105         pushl %ecx
106         pushl %ecx
107         pushl %ecx
108         pushl %ecx
109         pushl %ecx
110         pushl %ecx
111         pushl %ecx
112         pushl %ecx
113         pushl %ecx
114         pushl %ecx
115         pushl %ecx
116         pushl %ecx
117         pushl %ecx
118         pushl %ecx
119         pushl %ecx
120         pushl %ecx
121         pushl %ecx
122         pushl %ecx
123         pushl %ecx
124         pushl %ecx
125         pushl %ecx
126         pushl %ecx
127         pushl %ecx
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 $0                /* These immediate values make the label 2 */
162         pushl $0                /* to be aligned on a 16 byte boundary to */
163         pushl $0                /* get a better performance of the loop.  */
164         pushl $0
165         pushl $0
166         pushl $0
167
168 /* For understanding the following code remember that %ecx == 0 now.
169    Although all the following instruction only modify %cl we always
170    have a correct zero-extended 32-bit value in %ecx.  */
171
172 L(2):   movb (%eax), %cl        /* get byte from stopset */
173         testb %cl, %cl          /* is NUL char? */
174         jz L(1_1)               /* yes => start compare loop */
175         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
176
177         movb 1(%eax), %cl       /* get byte from stopset */
178         testb $0xff, %cl        /* is NUL char? */
179         jz L(1_2)               /* yes => start compare loop */
180         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
181
182         movb 2(%eax), %cl       /* get byte from stopset */
183         testb $0xff, %cl        /* is NUL char? */
184         jz L(1_3)               /* yes => start compare loop */
185         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
186
187         movb 3(%eax), %cl       /* get byte from stopset */
188         addl $4, %eax           /* increment stopset pointer */
189         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
190         testb $0xff, %cl        /* is NUL char? */
191         jnz L(2)                /* no => process next dword from stopset */
192
193 #if __BOUNDED_POINTERS__
194         jmp L(1_0)              /* pointer is correct for bounds check */
195 L(1_3): incl %eax               /* adjust pointer for bounds check */
196 L(1_2): incl %eax               /* ditto */
197 L(1_1): incl %eax               /* ditto */
198 L(1_0): CHECK_BOUNDS_HIGH (%eax, DELIM(%esp), jb)
199 #else
200 L(1_3):; L(1_2):; L(1_1):       /* fall through */
201 #endif
202         leal -4(%edx), %eax     /* prepare loop */
203
204         /* We use a neat trick for the following loop.  Normally we would
205            have to test for two termination conditions
206            1. a character in the stopset was found
207            and
208            2. the end of the string was found
209            As a sign that the character is in the stopset we store its
210            value in the table.  The value of NUL is NUL so the loop
211            terminates for NUL in every case.  */
212
213 L(3):   addl $4, %eax           /* adjust pointer for full loop round */
214
215         movb (%eax), %cl        /* get byte from string */
216         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
217         jz L(4)                 /* no => start of token */
218
219         movb 1(%eax), %cl       /* get byte from string */
220         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
221         jz L(5)                 /* no => start of token */
222
223         movb 2(%eax), %cl       /* get byte from string */
224         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
225         jz L(6)                 /* no => start of token */
226
227         movb 3(%eax), %cl       /* get byte from string */
228         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
229         jnz L(3)                /* yes => start of loop */
230
231         incl %eax               /* adjust pointer */
232 L(6):   incl %eax
233 L(5):   incl %eax
234
235         /* Now we have to terminate the string.  */
236
237 L(4):   leal -4(%eax), %edx     /* We use %EDX for the next run.  */
238
239 L(7):   addl $4, %edx           /* adjust pointer for full loop round */
240
241         movb (%edx), %cl        /* get byte from string */
242         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
243         je L(8)                 /* yes => return */
244
245         movb 1(%edx), %cl       /* get byte from string */
246         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
247         je L(9)                 /* yes => return */
248
249         movb 2(%edx), %cl       /* get byte from string */
250         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
251         je L(10)                /* yes => return */
252
253         movb 3(%edx), %cl       /* get byte from string */
254         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
255         jne L(7)                /* no => start loop again */
256
257         incl %edx               /* adjust pointer */
258 L(10):  incl %edx
259 L(9):   incl %edx
260
261 L(8):   /* Remove the stopset table.  */
262         addl $256, %esp
263
264         cmpl %eax, %edx
265         je L(returnNULL)        /* There was no token anymore.  */
266
267         movb $0, (%edx)         /* Terminate string.  */
268
269         /* Are we at end of string?  */
270         cmpb $0, %cl
271         je L(11)
272
273         incl %edx
274 L(11):
275
276 L(return):
277         /* Store the pointer to the next character.  */
278 #ifdef USE_AS_STRTOK_R
279         movl SAVE(%esp), %ecx
280         movl %edx, (%ecx)
281 #else
282 # ifndef PIC
283         movl %edx, save_ptr
284 # else
285         movl %edx, save_ptr@GOTOFF(%ebx)
286         popl %ebx
287 # endif
288 #endif
289 #if __BOUNDED_POINTERS__
290         testl %eax, %eax
291         jz L(ret)
292         CHECK_BOUNDS_HIGH (%eax, STR(%esp), jb)
293         RETURN_BOUNDED_POINTER (STR(%esp))
294 L(ret):
295 #endif
296         LEAVE
297         RET_PTR
298
299 L(returnNULL):
300         xorl %eax, %eax
301         RETURN_NULL_BOUNDED_POINTER
302         jmp L(return)
303
304 END (BP_SYM (FUNCTION))