/* * Copyright (c) 2010, 2011 Apple, Inc. All rights reserved. * * @APPLE_OSREFERENCE_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. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * 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_OSREFERENCE_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