1 /* 2 * Most of the string-functions are rather heavily hand-optimized, 3 * see especially strsep,strstr,str[c]spn. They should work, but are not 4 * very easy to understand. Everything is done entirely within the register 5 * set, making the functions fast and clean. String instructions have been 6 * used through-out, making for "slightly" unclear code :-) 7 * 8 * AK: On P4 and K7 using non string instruction implementations might be faster 9 * for large memory blocks. But most of them are unlikely to be used on large 10 * strings. 11 */ 12 13 #include <linux/string.h> 14 #include <linux/module.h> 15 16 #ifdef __HAVE_ARCH_STRCPY 17 char *strcpy(char * dest,const char *src) 18 { 19 int d0, d1, d2; 20 asm volatile( "1:\tlodsb\n\t" 21 "stosb\n\t" 22 "testb %%al,%%al\n\t" 23 "jne 1b" 24 : "=&S" (d0), "=&D" (d1), "=&a" (d2) 25 :"0" (src),"1" (dest) : "memory"); 26 return dest; 27 } 28 EXPORT_SYMBOL(strcpy); 29 #endif 30 31 #ifdef __HAVE_ARCH_STRNCPY 32 char *strncpy(char * dest,const char *src,size_t count) 33 { 34 int d0, d1, d2, d3; 35 asm volatile( "1:\tdecl %2\n\t" 36 "js 2f\n\t" 37 "lodsb\n\t" 38 "stosb\n\t" 39 "testb %%al,%%al\n\t" 40 "jne 1b\n\t" 41 "rep\n\t" 42 "stosb\n" 43 "2:" 44 : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3) 45 :"0" (src),"1" (dest),"2" (count) : "memory"); 46 return dest; 47 } 48 EXPORT_SYMBOL(strncpy); 49 #endif 50 51 #ifdef __HAVE_ARCH_STRCAT 52 char *strcat(char * dest,const char * src) 53 { 54 int d0, d1, d2, d3; 55 asm volatile( "repne\n\t" 56 "scasb\n\t" 57 "decl %1\n" 58 "1:\tlodsb\n\t" 59 "stosb\n\t" 60 "testb %%al,%%al\n\t" 61 "jne 1b" 62 : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) 63 : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu): "memory"); 64 return dest; 65 } 66 EXPORT_SYMBOL(strcat); 67 #endif 68 69 #ifdef __HAVE_ARCH_STRNCAT 70 char *strncat(char * dest,const char * src,size_t count) 71 { 72 int d0, d1, d2, d3; 73 asm volatile( "repne\n\t" 74 "scasb\n\t" 75 "decl %1\n\t" 76 "movl %8,%3\n" 77 "1:\tdecl %3\n\t" 78 "js 2f\n\t" 79 "lodsb\n\t" 80 "stosb\n\t" 81 "testb %%al,%%al\n\t" 82 "jne 1b\n" 83 "2:\txorl %2,%2\n\t" 84 "stosb" 85 : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) 86 : "0" (src),"1" (dest),"2" (0),"3" (0xffffffffu), "g" (count) 87 : "memory"); 88 return dest; 89 } 90 EXPORT_SYMBOL(strncat); 91 #endif 92 93 #ifdef __HAVE_ARCH_STRCMP 94 int strcmp(const char * cs,const char * ct) 95 { 96 int d0, d1; 97 int res; 98 asm volatile( "1:\tlodsb\n\t" 99 "scasb\n\t" 100 "jne 2f\n\t" 101 "testb %%al,%%al\n\t" 102 "jne 1b\n\t" 103 "xorl %%eax,%%eax\n\t" 104 "jmp 3f\n" 105 "2:\tsbbl %%eax,%%eax\n\t" 106 "orb $1,%%al\n" 107 "3:" 108 :"=a" (res), "=&S" (d0), "=&D" (d1) 109 :"1" (cs),"2" (ct) 110 :"memory"); 111 return res; 112 } 113 EXPORT_SYMBOL(strcmp); 114 #endif 115 116 #ifdef __HAVE_ARCH_STRNCMP 117 int strncmp(const char * cs,const char * ct,size_t count) 118 { 119 int res; 120 int d0, d1, d2; 121 asm volatile( "1:\tdecl %3\n\t" 122 "js 2f\n\t" 123 "lodsb\n\t" 124 "scasb\n\t" 125 "jne 3f\n\t" 126 "testb %%al,%%al\n\t" 127 "jne 1b\n" 128 "2:\txorl %%eax,%%eax\n\t" 129 "jmp 4f\n" 130 "3:\tsbbl %%eax,%%eax\n\t" 131 "orb $1,%%al\n" 132 "4:" 133 :"=a" (res), "=&S" (d0), "=&D" (d1), "=&c" (d2) 134 :"1" (cs),"2" (ct),"3" (count) 135 :"memory"); 136 return res; 137 } 138 EXPORT_SYMBOL(strncmp); 139 #endif 140 141 #ifdef __HAVE_ARCH_STRCHR 142 char *strchr(const char * s, int c) 143 { 144 int d0; 145 char * res; 146 asm volatile( "movb %%al,%%ah\n" 147 "1:\tlodsb\n\t" 148 "cmpb %%ah,%%al\n\t" 149 "je 2f\n\t" 150 "testb %%al,%%al\n\t" 151 "jne 1b\n\t" 152 "movl $1,%1\n" 153 "2:\tmovl %1,%0\n\t" 154 "decl %0" 155 :"=a" (res), "=&S" (d0) 156 :"1" (s),"0" (c) 157 :"memory"); 158 return res; 159 } 160 EXPORT_SYMBOL(strchr); 161 #endif 162 163 #ifdef __HAVE_ARCH_STRRCHR 164 char *strrchr(const char * s, int c) 165 { 166 int d0, d1; 167 char * res; 168 asm volatile( "movb %%al,%%ah\n" 169 "1:\tlodsb\n\t" 170 "cmpb %%ah,%%al\n\t" 171 "jne 2f\n\t" 172 "leal -1(%%esi),%0\n" 173 "2:\ttestb %%al,%%al\n\t" 174 "jne 1b" 175 :"=g" (res), "=&S" (d0), "=&a" (d1) 176 :"0" (0),"1" (s),"2" (c) 177 :"memory"); 178 return res; 179 } 180 EXPORT_SYMBOL(strrchr); 181 #endif 182 183 #ifdef __HAVE_ARCH_STRLEN 184 size_t strlen(const char * s) 185 { 186 int d0; 187 int res; 188 asm volatile( "repne\n\t" 189 "scasb\n\t" 190 "notl %0\n\t" 191 "decl %0" 192 :"=c" (res), "=&D" (d0) 193 :"1" (s),"a" (0), "0" (0xffffffffu) 194 :"memory"); 195 return res; 196 } 197 EXPORT_SYMBOL(strlen); 198 #endif 199 200 #ifdef __HAVE_ARCH_MEMCHR 201 void *memchr(const void *cs,int c,size_t count) 202 { 203 int d0; 204 void *res; 205 if (!count) 206 return NULL; 207 asm volatile( "repne\n\t" 208 "scasb\n\t" 209 "je 1f\n\t" 210 "movl $1,%0\n" 211 "1:\tdecl %0" 212 :"=D" (res), "=&c" (d0) 213 :"a" (c),"0" (cs),"1" (count) 214 :"memory"); 215 return res; 216 } 217 EXPORT_SYMBOL(memchr); 218 #endif 219 220 #ifdef __HAVE_ARCH_MEMSCAN 221 void *memscan(void * addr, int c, size_t size) 222 { 223 if (!size) 224 return addr; 225 asm volatile("repnz; scasb\n\t" 226 "jnz 1f\n\t" 227 "dec %%edi\n" 228 "1:" 229 : "=D" (addr), "=c" (size) 230 : "0" (addr), "1" (size), "a" (c) 231 : "memory"); 232 return addr; 233 } 234 EXPORT_SYMBOL(memscan); 235 #endif 236 237 #ifdef __HAVE_ARCH_STRNLEN 238 size_t strnlen(const char *s, size_t count) 239 { 240 int d0; 241 int res; 242 asm volatile( "movl %2,%0\n\t" 243 "jmp 2f\n" 244 "1:\tcmpb $0,(%0)\n\t" 245 "je 3f\n\t" 246 "incl %0\n" 247 "2:\tdecl %1\n\t" 248 "cmpl $-1,%1\n\t" 249 "jne 1b\n" 250 "3:\tsubl %2,%0" 251 :"=a" (res), "=&d" (d0) 252 :"c" (s),"1" (count) 253 :"memory"); 254 return res; 255 } 256 EXPORT_SYMBOL(strnlen); 257 #endif 258