Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | /* * Copyright (c) 2010, 2011 Apple, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ .text .syntax unified .code 32 .globl _strncmp // int strncmp(const char *s1, const char *s2, size_t n); // // Returns zero if the two NUL-terminated strings s1 and s2 are equal up to // n characters. Otherwise, returns the difference between the first two // characters that do not match, interpreted as unsigned integers. #define ESTABLISH_FRAME \ push {r4-r7,lr} ;\ add r7, sp, #12 ;\ push {r8,r10} #define CLEAR_FRAME \ pop {r8,r10} ;\ pop {r4-r7,lr} .align 3 .long 0, 0x01010101 _strncmp: // If n < 16, jump straight to the byte-by-byte comparison loop. cmp r2, #16 blo L_byteCompareLoop // Load a character from each string and advance the pointers. If the loaded // characters are unequal or NUL, return their difference. 0: ldrb r3, [r0],#1 ldrb ip, [r1],#1 sub r2, #1 cmp r3, #1 cmphs r3, ip bne L_earlyReturn // If the address of the next character from s1 does not have word alignment, // continue with the character-by-character comparison. Otherwise, fall // through into the word-by-word comparison path. tst r0, #3 bne 0b // We have not encountered a NUL or a mismatch, and s1 has word alignment. // Establish a frame, since we're going to need additional registers anyway. ESTABLISH_FRAME ldr lr, (_strncmp-4) // Word align s2, and place the remainder in r10. Compute the right- and // left-shifts to extract each word that we will compare to the other source // from the aligned words that we load: // // aligned s2 to be loaded on next iteration // | "true" s2 | // v v v // +---+---+---+---+ +---+---+---+---+ // | 0 | 1 | 2 | 3 | | 4 | 5 | 6 | 7 | // +---+---+---+---+ +---+---+---+---+ // ^-----------------^ // to be compared on next iteration and r10, r1, #3 bic r1, r1, #3 mov r10, r10, lsl #3 rsb r6, r10,#32 // Subtract the number of bytes of the initial word load from s2 that will // actually be used from n. sub r2, r2, r6, lsr #3 // Load the first aligned word of s2. OR 0x01 into any bytes that preceed the // "true s2", to prevent our check for NUL from generating a false positive. // Then check for NUL, and jump to the byte-by-byte comparison loop after // unwinding the pointers if we enounter one. ldr r8, [r1],#4 orr r8, r8, lr, lsr r6 sub r3, r8, lr bic r3, r3, r8 tst r3, lr, lsl #7 mov r5, r8, lsr r10 bne L_unwindLoopPreload .align 3 L_wordCompareLoop: // If n < 4, abort the word compare loop before we load any more data. subs r2, r2, #4 blo L_nIsLessThanFour // Load the next aligned word of s2 and check if it contains any NUL bytes. // Load the next aligned word of s1, and extract the corresponding bytes from // the two words of s2 loaded in this and the previous iteration of the loop. // Compare these two words. // If no NUL or mismatched words have been encountered, continue the loop. ldr r8, [r1],#4 #if defined _ARM_ARCH_6 uqsub8 r3, lr, r8 tst r3, r3 ldr ip, [r0],#4 #else sub r3, r8, lr bic r3, r3, r8 ldr ip, [r0],#4 tst r3, lr, lsl #7 #endif orr r4, r5, r8, lsl r6 cmpeq ip, r4 mov r5, r8, lsr r10 beq L_wordCompareLoop // Either we have encountered a NUL, or we have found a mismatch between s1 // and s2. Unwind the pointers and use a byte-by-byte comparison loop. sub r0, r0, #4 sub r1, r1, #4 L_nIsLessThanFour: add r2, r2, #4 L_unwindLoopPreload: sub r1, r1, r6, lsr #3 add r2, r2, r6, lsr #3 CLEAR_FRAME L_byteCompareLoop: // If n-- == 0, we have exhausted the allowed number of comparisons, and need // to return zero without additional loads. subs r2, r2, #1 movlo r0, #0 bxlo lr // Load a character from each string and advance the pointers. If the loaded // characters are unequal or NUL, return their difference. ldrb r3, [r0],#1 ldrb ip, [r1],#1 cmp r3, #1 cmpcs r3, ip beq L_byteCompareLoop L_earlyReturn: // Return the difference between the last two characters loaded. sub r0, r3, ip bx lr |