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