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