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 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 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 scasb\n\t" 74 "decl %1\n\t" 75 "movl %8,%3\n" 76 "1:\tdecl %3\n\t" 77 "js 2f\n\t" 78 "lodsb\n\t" 79 "stosb\n\t" 80 "testb %%al,%%al\n\t" 81 "jne 1b\n" 82 "2:\txorl %2,%2\n\t" 83 "stosb" 84 : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) 85 : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu), "g" (count) 86 : "memory"); 87 return dest; 88 } 89 EXPORT_SYMBOL(strncat); 90 #endif 91 92 #ifdef __HAVE_ARCH_STRCMP 93 int strcmp(const char *cs, const char *ct) 94 { 95 int d0, d1; 96 int res; 97 asm volatile("1:\tlodsb\n\t" 98 "scasb\n\t" 99 "jne 2f\n\t" 100 "testb %%al,%%al\n\t" 101 "jne 1b\n\t" 102 "xorl %%eax,%%eax\n\t" 103 "jmp 3f\n" 104 "2:\tsbbl %%eax,%%eax\n\t" 105 "orb $1,%%al\n" 106 "3:" 107 : "=a" (res), "=&S" (d0), "=&D" (d1) 108 : "1" (cs), "2" (ct) 109 : "memory"); 110 return res; 111 } 112 EXPORT_SYMBOL(strcmp); 113 #endif 114 115 #ifdef __HAVE_ARCH_STRNCMP 116 int strncmp(const char *cs, const char *ct, size_t count) 117 { 118 int res; 119 int d0, d1, d2; 120 asm volatile("1:\tdecl %3\n\t" 121 "js 2f\n\t" 122 "lodsb\n\t" 123 "scasb\n\t" 124 "jne 3f\n\t" 125 "testb %%al,%%al\n\t" 126 "jne 1b\n" 127 "2:\txorl %%eax,%%eax\n\t" 128 "jmp 4f\n" 129 "3:\tsbbl %%eax,%%eax\n\t" 130 "orb $1,%%al\n" 131 "4:" 132 : "=a" (res), "=&S" (d0), "=&D" (d1), "=&c" (d2) 133 : "1" (cs), "2" (ct), "3" (count) 134 : "memory"); 135 return res; 136 } 137 EXPORT_SYMBOL(strncmp); 138 #endif 139 140 #ifdef __HAVE_ARCH_STRCHR 141 char *strchr(const char *s, int c) 142 { 143 int d0; 144 char *res; 145 asm volatile("movb %%al,%%ah\n" 146 "1:\tlodsb\n\t" 147 "cmpb %%ah,%%al\n\t" 148 "je 2f\n\t" 149 "testb %%al,%%al\n\t" 150 "jne 1b\n\t" 151 "movl $1,%1\n" 152 "2:\tmovl %1,%0\n\t" 153 "decl %0" 154 : "=a" (res), "=&S" (d0) 155 : "1" (s), "0" (c) 156 : "memory"); 157 return res; 158 } 159 EXPORT_SYMBOL(strchr); 160 #endif 161 162 #ifdef __HAVE_ARCH_STRLEN 163 size_t strlen(const char *s) 164 { 165 int d0; 166 size_t res; 167 asm volatile("repne scasb" 168 : "=c" (res), "=&D" (d0) 169 : "1" (s), "a" (0), "0" (0xffffffffu) 170 : "memory"); 171 return ~res - 1; 172 } 173 EXPORT_SYMBOL(strlen); 174 #endif 175 176 #ifdef __HAVE_ARCH_MEMCHR 177 void *memchr(const void *cs, int c, size_t count) 178 { 179 int d0; 180 void *res; 181 if (!count) 182 return NULL; 183 asm volatile("repne scasb\n\t" 184 "je 1f\n\t" 185 "movl $1,%0\n" 186 "1:\tdecl %0" 187 : "=D" (res), "=&c" (d0) 188 : "a" (c), "0" (cs), "1" (count) 189 : "memory"); 190 return res; 191 } 192 EXPORT_SYMBOL(memchr); 193 #endif 194 195 #ifdef __HAVE_ARCH_MEMSCAN 196 void *memscan(void *addr, int c, size_t size) 197 { 198 if (!size) 199 return addr; 200 asm volatile("repnz scasb\n\t" 201 "jnz 1f\n\t" 202 "dec %%edi\n" 203 "1:" 204 : "=D" (addr), "=c" (size) 205 : "0" (addr), "1" (size), "a" (c) 206 : "memory"); 207 return addr; 208 } 209 EXPORT_SYMBOL(memscan); 210 #endif 211 212 #ifdef __HAVE_ARCH_STRNLEN 213 size_t strnlen(const char *s, size_t count) 214 { 215 int d0; 216 int res; 217 asm volatile("movl %2,%0\n\t" 218 "jmp 2f\n" 219 "1:\tcmpb $0,(%0)\n\t" 220 "je 3f\n\t" 221 "incl %0\n" 222 "2:\tdecl %1\n\t" 223 "cmpl $-1,%1\n\t" 224 "jne 1b\n" 225 "3:\tsubl %2,%0" 226 : "=a" (res), "=&d" (d0) 227 : "c" (s), "1" (count) 228 : "memory"); 229 return res; 230 } 231 EXPORT_SYMBOL(strnlen); 232 #endif 233