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