2.9
[glibc/nacl-glibc.git] / sysdeps / i386 / i686 / strtok.S
blobfe225e54855a0d0be0bb3f2523edaa9cde38a407
1 /* strtok (str, delim) -- Return next DELIM separated token from STR.
2    For Intel 80686.
3    Copyright (C) 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>, 1998.
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 #if !defined USE_AS_STRTOK_R && defined PIC
66 # define PARMS  LINKAGE+256+4   /* space for table and saved PIC register */
67 #else
68 # define PARMS  LINKAGE+256     /* space for table */
69 #endif
70 #define RTN     PARMS
71 #define STR     RTN+RTN_SIZE
72 #define DELIM   STR+PTR_SIZE
73 #ifdef USE_AS_STRTOK_R
74 # define SAVE   DELIM+PTR_SIZE
75 #endif
77         .text
79 #if !defined USE_AS_STRTOK_R && defined PIC
80 0:      movl (%esp), %ebx
81         ret
82 #endif
84 ENTRY (BP_SYM (FUNCTION))
85         ENTER
87 #if !defined USE_AS_STRTOK_R && defined PIC
88         pushl %ebx                      /* Save PIC register.  */
89         cfi_adjust_cfa_offset (4)
90         cfi_rel_offset (ebx, 0)
91         call 0b
92         addl $_GLOBAL_OFFSET_TABLE_, %ebx
93 #endif
95         /* First we create a table with flags for all possible characters.
96            For the ASCII (7bit/8bit) or ISO-8859-X character sets which are
97            supported by the C string functions we have 256 characters.
98            Before inserting marks for the stop characters we clear the whole
99            table.  */
100         movl %edi, %edx
101         subl $256, %esp
102         cfi_adjust_cfa_offset (256)
103         movl $64, %ecx
104         movl %esp, %edi
105         xorl %eax, %eax
106         cld
107         rep
108         stosl
110         /* Note: %ecx = 0 !!! */
111         movl %edx, %edi
113         movl STR(%esp), %edx            /* Get start of string.  */
115 #ifdef USE_AS_STRTOK_R
116         /* The value is stored in the third argument.  */
117         movl SAVE(%esp), %eax
118         movl (%eax), %eax
119 #else
120         /* The value is in the local variable defined above.  But
121            we have to take care for PIC code.  */
122         movl SAVE_PTR, %eax
123 #endif
125         /* If the pointer is NULL we have to use the stored value of
126            the last run.  */
127         cmpl $0, %edx
128         cmove %eax, %edx
129         testl %edx, %edx
130         jz L(returnNULL)
131 #if __BOUNDED_POINTERS__
132 # ifdef USE_AS_STRTOK_R
133         movl SAVE(%esp), %ecx   /* borrow %ecx for a moment */
134 # endif
135         je L(0)
136         /* Save bounds of incoming non-NULL STR into save area.  */
137         movl 4+STR(%esp), %eax
138         movl %eax, 4+SAVE_PTR
139         movl 8+STR(%esp), %eax
140         movl %eax, 8+SAVE_PTR
141 L(0):   CHECK_BOUNDS_LOW (%edx, SAVE_PTR)
142 # ifdef USE_AS_STRTOK_R
143         xorl %ecx, %ecx         /* restore %ecx to zero */
144 # endif
145 #endif
146         movl DELIM(%esp), %eax          /* Get start of delimiter set.  */
147         CHECK_BOUNDS_LOW (%eax, DELIM(%esp))
149 /* For understanding the following code remember that %ecx == 0 now.
150    Although all the following instruction only modify %cl we always
151    have a correct zero-extended 32-bit value in %ecx.  */
153 L(2):   movb (%eax), %cl        /* get byte from stopset */
154         testb %cl, %cl          /* is NUL char? */
155         jz L(1_1)               /* yes => start compare loop */
156         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
158         movb 1(%eax), %cl       /* get byte from stopset */
159         testb $0xff, %cl        /* is NUL char? */
160         jz L(1_2)               /* yes => start compare loop */
161         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
163         movb 2(%eax), %cl       /* get byte from stopset */
164         testb $0xff, %cl        /* is NUL char? */
165         jz L(1_3)               /* yes => start compare loop */
166         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
168         movb 3(%eax), %cl       /* get byte from stopset */
169         addl $4, %eax           /* increment stopset pointer */
170         movb %cl, (%esp,%ecx)   /* set corresponding byte in stopset table */
171         testb $0xff, %cl        /* is NUL char? */
172         jnz L(2)                /* no => process next dword from stopset */
174 #if __BOUNDED_POINTERS__
175         jmp L(1_0)              /* pointer is correct for bounds check */
176 L(1_3): incl %eax               /* adjust pointer for bounds check */
177 L(1_2): incl %eax               /* ditto */
178 L(1_1): incl %eax               /* ditto */
179 L(1_0): CHECK_BOUNDS_HIGH (%eax, DELIM(%esp), jbe)
180 #else
181 L(1_3):; L(1_2):; L(1_1):       /* fall through */
182 #endif
183         leal -4(%edx), %eax     /* prepare loop */
185         /* We use a neat trick for the following loop.  Normally we would
186            have to test for two termination conditions
187            1. a character in the stopset was found
188            and
189            2. the end of the string was found
190            As a sign that the character is in the stopset we store its
191            value in the table.  The value of NUL is NUL so the loop
192            terminates for NUL in every case.  */
194 L(3):   addl $4, %eax           /* adjust pointer for full loop round */
196         movb (%eax), %cl        /* get byte from string */
197         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
198         jz L(4)                 /* no => start of token */
200         movb 1(%eax), %cl       /* get byte from string */
201         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
202         jz L(5)                 /* no => start of token */
204         movb 2(%eax), %cl       /* get byte from string */
205         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
206         jz L(6)                 /* no => start of token */
208         movb 3(%eax), %cl       /* get byte from string */
209         testb %cl, (%esp,%ecx)  /* is it contained in stopset? */
210         jnz L(3)                /* yes => start of loop */
212         incl %eax               /* adjust pointer */
213 L(6):   incl %eax
214 L(5):   incl %eax
216         /* Now we have to terminate the string.  */
218 L(4):   leal -4(%eax), %edx     /* We use %EDX for the next run.  */
220 L(7):   addl $4, %edx           /* adjust pointer for full loop round */
222         movb (%edx), %cl        /* get byte from string */
223         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
224         je L(8)                 /* yes => return */
226         movb 1(%edx), %cl       /* get byte from string */
227         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
228         je L(9)                 /* yes => return */
230         movb 2(%edx), %cl       /* get byte from string */
231         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
232         je L(10)                /* yes => return */
234         movb 3(%edx), %cl       /* get byte from string */
235         cmpb %cl, (%esp,%ecx)   /* is it contained in skipset? */
236         jne L(7)                /* no => start loop again */
238         incl %edx               /* adjust pointer */
239 L(10):  incl %edx
240 L(9):   incl %edx
242 L(8):   cmpl %eax, %edx
243         je L(returnNULL)        /* There was no token anymore.  */
245         movb $0, (%edx)         /* Terminate string.  */
247         /* Are we at end of string?  */
248         cmpb $0, %cl
249         leal 1(%edx), %ecx
250         cmovne %ecx, %edx
252         /* Store the pointer to the next character.  */
253 #ifdef USE_AS_STRTOK_R
254         movl SAVE(%esp), %ecx
255 #endif
256         movl %edx, SAVE_PTR
257         CHECK_BOUNDS_HIGH (%edx, SAVE_PTR, jb)
258         RETURN_BOUNDED_POINTER (SAVE_PTR)
260 L(epilogue):
261         /* Remove the stopset table.  */
262         addl $256, %esp
263         cfi_adjust_cfa_offset (-256)
264 #if !defined USE_AS_STRTOK_R && defined PIC
265         popl %ebx
266         cfi_adjust_cfa_offset (-4)
267         cfi_restore (ebx)
268 #endif
269         LEAVE
270         RET_PTR
272 L(returnNULL):
273         xorl %eax, %eax
274 #ifdef USE_AS_STRTOK_R
275         movl SAVE(%esp), %ecx
276 #endif
277         movl %edx, SAVE_PTR
278         RETURN_NULL_BOUNDED_POINTER
279         jmp L(epilogue)
281 END (BP_SYM (FUNCTION))