2007-07-21 19:09:59 +04:00
/*
* Most of the string - functions are rather heavily hand - optimized ,
* see especially strsep , strstr , str [ c ] spn . They should work , but are not
* very easy to understand . Everything is done entirely within the register
* set , making the functions fast and clean . String instructions have been
* used through - out , making for " slightly " unclear code : - )
*
* AK : On P4 and K7 using non string instruction implementations might be faster
* for large memory blocks . But most of them are unlikely to be used on large
* strings .
*/
# include <linux/string.h>
# include <linux/module.h>
# ifdef __HAVE_ARCH_STRCPY
2008-02-20 01:09:59 +03:00
char * strcpy ( char * dest , const char * src )
2007-07-21 19:09:59 +04:00
{
int d0 , d1 , d2 ;
2008-02-20 01:09:59 +03:00
asm volatile ( " 1: \t lodsb \n \t "
2007-07-21 19:09:59 +04:00
" stosb \n \t "
" testb %%al,%%al \n \t "
" jne 1b "
: " =&S " ( d0 ) , " =&D " ( d1 ) , " =&a " ( d2 )
2008-08-02 23:25:13 +04:00
: " 0 " ( src ) , " 1 " ( dest ) : " memory " ) ;
2007-07-21 19:09:59 +04:00
return dest ;
}
EXPORT_SYMBOL ( strcpy ) ;
# endif
# ifdef __HAVE_ARCH_STRNCPY
2008-02-20 01:09:59 +03:00
char * strncpy ( char * dest , const char * src , size_t count )
2007-07-21 19:09:59 +04:00
{
int d0 , d1 , d2 , d3 ;
2008-02-20 01:09:59 +03:00
asm volatile ( " 1: \t decl %2 \n \t "
2007-07-21 19:09:59 +04:00
" js 2f \n \t "
" lodsb \n \t "
" stosb \n \t "
" testb %%al,%%al \n \t "
" jne 1b \n \t "
" rep \n \t "
" stosb \n "
" 2: "
: " =&S " ( d0 ) , " =&D " ( d1 ) , " =&c " ( d2 ) , " =&a " ( d3 )
2008-08-02 23:25:13 +04:00
: " 0 " ( src ) , " 1 " ( dest ) , " 2 " ( count ) : " memory " ) ;
2007-07-21 19:09:59 +04:00
return dest ;
}
EXPORT_SYMBOL ( strncpy ) ;
# endif
# ifdef __HAVE_ARCH_STRCAT
2008-02-20 01:09:59 +03:00
char * strcat ( char * dest , const char * src )
2007-07-21 19:09:59 +04:00
{
int d0 , d1 , d2 , d3 ;
2008-02-20 01:09:59 +03:00
asm volatile ( " repne \n \t "
2007-07-21 19:09:59 +04:00
" scasb \n \t "
" decl %1 \n "
" 1: \t lodsb \n \t "
" stosb \n \t "
" testb %%al,%%al \n \t "
" jne 1b "
: " =&S " ( d0 ) , " =&D " ( d1 ) , " =&a " ( d2 ) , " =&c " ( d3 )
2008-08-02 23:25:13 +04:00
: " 0 " ( src ) , " 1 " ( dest ) , " 2 " ( 0 ) , " 3 " ( 0xffffffffu ) : " memory " ) ;
2007-07-21 19:09:59 +04:00
return dest ;
}
EXPORT_SYMBOL ( strcat ) ;
# endif
# ifdef __HAVE_ARCH_STRNCAT
2008-02-20 01:09:59 +03:00
char * strncat ( char * dest , const char * src , size_t count )
2007-07-21 19:09:59 +04:00
{
int d0 , d1 , d2 , d3 ;
2008-02-20 01:09:59 +03:00
asm volatile ( " repne \n \t "
2007-07-21 19:09:59 +04:00
" scasb \n \t "
" decl %1 \n \t "
" movl %8,%3 \n "
" 1: \t decl %3 \n \t "
" js 2f \n \t "
" lodsb \n \t "
" stosb \n \t "
" testb %%al,%%al \n \t "
" jne 1b \n "
" 2: \t xorl %2,%2 \n \t "
" stosb "
: " =&S " ( d0 ) , " =&D " ( d1 ) , " =&a " ( d2 ) , " =&c " ( d3 )
2008-02-20 01:09:59 +03:00
: " 0 " ( src ) , " 1 " ( dest ) , " 2 " ( 0 ) , " 3 " ( 0xffffffffu ) , " g " ( count )
2007-07-21 19:09:59 +04:00
: " memory " ) ;
return dest ;
}
EXPORT_SYMBOL ( strncat ) ;
# endif
# ifdef __HAVE_ARCH_STRCMP
2008-02-20 01:09:59 +03:00
int strcmp ( const char * cs , const char * ct )
2007-07-21 19:09:59 +04:00
{
int d0 , d1 ;
int res ;
2008-02-20 01:09:59 +03:00
asm volatile ( " 1: \t lodsb \n \t "
2007-07-21 19:09:59 +04:00
" scasb \n \t "
" jne 2f \n \t "
" testb %%al,%%al \n \t "
" jne 1b \n \t "
" xorl %%eax,%%eax \n \t "
" jmp 3f \n "
" 2: \t sbbl %%eax,%%eax \n \t "
" orb $1,%%al \n "
" 3: "
2008-08-02 23:25:13 +04:00
: " =a " ( res ) , " =&S " ( d0 ) , " =&D " ( d1 )
: " 1 " ( cs ) , " 2 " ( ct )
: " memory " ) ;
2007-07-21 19:09:59 +04:00
return res ;
}
EXPORT_SYMBOL ( strcmp ) ;
# endif
# ifdef __HAVE_ARCH_STRNCMP
2008-02-20 01:09:59 +03:00
int strncmp ( const char * cs , const char * ct , size_t count )
2007-07-21 19:09:59 +04:00
{
int res ;
int d0 , d1 , d2 ;
2008-02-20 01:09:59 +03:00
asm volatile ( " 1: \t decl %3 \n \t "
2007-07-21 19:09:59 +04:00
" js 2f \n \t "
" lodsb \n \t "
" scasb \n \t "
" jne 3f \n \t "
" testb %%al,%%al \n \t "
" jne 1b \n "
" 2: \t xorl %%eax,%%eax \n \t "
" jmp 4f \n "
" 3: \t sbbl %%eax,%%eax \n \t "
" orb $1,%%al \n "
" 4: "
2008-08-02 23:25:13 +04:00
: " =a " ( res ) , " =&S " ( d0 ) , " =&D " ( d1 ) , " =&c " ( d2 )
: " 1 " ( cs ) , " 2 " ( ct ) , " 3 " ( count )
: " memory " ) ;
2007-07-21 19:09:59 +04:00
return res ;
}
EXPORT_SYMBOL ( strncmp ) ;
# endif
# ifdef __HAVE_ARCH_STRCHR
2008-02-20 01:09:59 +03:00
char * strchr ( const char * s , int c )
2007-07-21 19:09:59 +04:00
{
int d0 ;
2008-02-20 01:09:59 +03:00
char * res ;
asm volatile ( " movb %%al,%%ah \n "
2007-07-21 19:09:59 +04:00
" 1: \t lodsb \n \t "
" cmpb %%ah,%%al \n \t "
" je 2f \n \t "
" testb %%al,%%al \n \t "
" jne 1b \n \t "
" movl $1,%1 \n "
" 2: \t movl %1,%0 \n \t "
" decl %0 "
2008-08-02 23:25:13 +04:00
: " =a " ( res ) , " =&S " ( d0 )
: " 1 " ( s ) , " 0 " ( c )
: " memory " ) ;
2007-07-21 19:09:59 +04:00
return res ;
}
EXPORT_SYMBOL ( strchr ) ;
# endif
# ifdef __HAVE_ARCH_STRLEN
2008-02-20 01:09:59 +03:00
size_t strlen ( const char * s )
2007-07-21 19:09:59 +04:00
{
int d0 ;
2011-12-11 22:13:19 +04:00
size_t res ;
2008-02-20 01:09:59 +03:00
asm volatile ( " repne \n \t "
2011-12-11 22:13:19 +04:00
" scasb "
2008-08-02 23:25:13 +04:00
: " =c " ( res ) , " =&D " ( d0 )
: " 1 " ( s ) , " a " ( 0 ) , " 0 " ( 0xffffffffu )
: " memory " ) ;
2011-12-11 22:13:19 +04:00
return ~ res - 1 ;
2007-07-21 19:09:59 +04:00
}
EXPORT_SYMBOL ( strlen ) ;
# endif
# ifdef __HAVE_ARCH_MEMCHR
2008-02-20 01:09:59 +03:00
void * memchr ( const void * cs , int c , size_t count )
2007-07-21 19:09:59 +04:00
{
int d0 ;
void * res ;
if ( ! count )
return NULL ;
2008-02-20 01:09:59 +03:00
asm volatile ( " repne \n \t "
2007-07-21 19:09:59 +04:00
" scasb \n \t "
" je 1f \n \t "
" movl $1,%0 \n "
" 1: \t decl %0 "
2008-08-02 23:25:13 +04:00
: " =D " ( res ) , " =&c " ( d0 )
: " a " ( c ) , " 0 " ( cs ) , " 1 " ( count )
: " memory " ) ;
2007-07-21 19:09:59 +04:00
return res ;
}
EXPORT_SYMBOL ( memchr ) ;
# endif
# ifdef __HAVE_ARCH_MEMSCAN
2008-02-20 01:09:59 +03:00
void * memscan ( void * addr , int c , size_t size )
2007-07-21 19:09:59 +04:00
{
if ( ! size )
return addr ;
asm volatile ( " repnz; scasb \n \t "
" jnz 1f \n \t "
" dec %%edi \n "
" 1: "
: " =D " ( addr ) , " =c " ( size )
: " 0 " ( addr ) , " 1 " ( size ) , " a " ( c )
: " memory " ) ;
return addr ;
}
EXPORT_SYMBOL ( memscan ) ;
# endif
# ifdef __HAVE_ARCH_STRNLEN
size_t strnlen ( const char * s , size_t count )
{
int d0 ;
int res ;
2008-02-20 01:09:59 +03:00
asm volatile ( " movl %2,%0 \n \t "
2007-07-21 19:09:59 +04:00
" jmp 2f \n "
" 1: \t cmpb $0,(%0) \n \t "
" je 3f \n \t "
" incl %0 \n "
" 2: \t decl %1 \n \t "
" cmpl $-1,%1 \n \t "
" jne 1b \n "
" 3: \t subl %2,%0 "
2008-08-02 23:25:13 +04:00
: " =a " ( res ) , " =&d " ( d0 )
: " c " ( s ) , " 1 " ( count )
: " memory " ) ;
2007-07-21 19:09:59 +04:00
return res ;
}
EXPORT_SYMBOL ( strnlen ) ;
# endif