Loading...
arm/string/strstr.s Libc-763.13 Libc-825.26
--- Libc/Libc-763.13/arm/string/strstr.s
+++ Libc/Libc-825.26/arm/string/strstr.s
@@ -21,3 +21,129 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
+//  char * strstr(const char *s1, const char *s2);
+//
+//  If s2 is empty, s1 is returned.
+//  If s2 does not occur in s1, NULL is returned.
+//  Otherwise, a pointer to the first character of the first occurrence of s2
+//  in s1 is returned.
+//
+//  We use a hand-tuned version of the naive quadratic time algorithm; we have
+//  experimented with more sophisticated algorithms, however they have been
+//  found wanting.  The increased startup cost combines with the frequency of
+//  calls to strstr with small strings to swamp the gains from improved
+//  asymptotic complexity.
+
+#define CLEAR_FRAME_AND_RETURN \
+    pop    {r4,r5,r6,r7,pc}
+
+.text
+.syntax unified
+.code 32
+.globl _strstr
+.align 2
+_strstr:
+    push   {r4,r5,r6,r7,lr}
+    add     r7,     sp, #12
+    
+//  Throughout this function, I will refer to the string in which we are
+//  searching as "string" and the string for which we are searching as "word".
+//  Using s1 and s2 is too confusing.  Thus, we want to return a pointer to
+//  the first occurrence of "word" in "string".
+    mov     r5,     r1
+    mov     r4,     r0
+
+//  We begin by calling strlen to find the length of "word".  We also handle
+//  two special cases here: we early-out if word is an empty string (length
+//  zero), and we call strchr if word is only a single character.
+    mov     r0,     r5
+    bl      _strlen
+    subs    r0,     r0, #1
+    ble     L_tinyWord
+    
+//  Load the first character of word
+    ldrb    ip,    [r5]
+
+L_lookForFirstCharacter:
+//  Load the first character from string.  If it is equal to the first
+//  character of word, or is a zero byte, then we do more processing;
+//  otherwise, proceed to the next character.
+    ldrb    r1,    [r4],#1
+    cmp     r1,     ip
+    tstne   r1,     r1
+    bne     L_lookForFirstCharacter
+    
+//  The byte that we loaded from string either matched the first character
+//  of word, or was a zero byte.  If it was a zero byte, then we have reached
+//  the end of string without finding a match of word.  Otherwise, we fall
+//  into a loop that checks additional characters to see if we have a match.
+    tst     r1,     r1
+    beq     L_noMatch
+    
+//  We have found a match for the first character of word; we want to read
+//  characters from this point on to see if we have a match for the entirety
+//  of word.  We want to be sure to preserve the state of the outside loop,
+//  however:
+//
+//      r0: length(word) - 1
+//      r4: pointer to the next character in string
+//      r5: pointer to the first character in word
+//      ip: first character in word
+//
+//  The registers r1-r3, r6, and lr are available as scratch.  We set them up
+//  for the inner loop as follows:
+//
+//      r1: remaining length to be matched
+//      r2: pointer to next character of string to match
+//      r3: pointer to next character of word to match
+//      r6: current character from string
+//      lr: current character from word    
+    mov     r2,     r4
+    add     r3,     r5, #1
+    mov     r1,     r0
+    
+L_checkMatch:
+//  Load the next byte from both the candidate match and from word.  If they
+//  are not equal, jump back to the outer loop.  If they are equal, decrement
+//  the length, and continue the inner loop if we have not yet found a
+//  complete match.
+//
+//  We don't need to worry about looking for null bytes in this loop; we know
+//  that we won't load a null byte from word, because we computed it's length
+//  earlier, and are using that as a termination condition.  If we hit a null
+//  byte in string, the comparison will fail (because the corresponding byte
+//  in word is non-null), and we will return to the outer loop, where the
+//  null byte will be detected and handled properly.
+    ldrb    r6,    [r2],#1
+    ldrb    lr,    [r3],#1
+    cmp     r6,     lr
+    bne     L_lookForFirstCharacter
+    subs    r1,     r1, #1
+    bne     L_checkMatch
+
+//  We have exhausted the length of word without finding a mismatched character
+//  so we have found a match.  Return a pointer to the beginning of the match
+//  string.  (This pointer is r4 - 1 because r4 was auto-incremented when we
+//  loaded the first character).
+    sub     r0,     r4, #1
+    CLEAR_FRAME_AND_RETURN
+
+L_noMatch:
+//  No match was found; return NULL.
+    mov     r0,     #0
+    CLEAR_FRAME_AND_RETURN
+
+L_tinyWord:
+//  "word" is either empty or a single character.  If it is a single character,
+//  translate strstr into a call to the (more efficient) strchr.
+    blt     L_emptyWord
+    ldrb    r1,    [r5]
+    mov     r0,     r4
+    bl      _strchr
+    CLEAR_FRAME_AND_RETURN
+    
+L_emptyWord:
+//  "word" is empty; return "string".
+    movlt   r0,     r4
+    CLEAR_FRAME_AND_RETURN
+