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
strcpy(char * dest,const char * src)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
strncpy(char * dest,const char * src,size_t count)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
strcat(char * dest,const char * src)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
strncat(char * dest,const char * src,size_t count)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
strcmp(const char * cs,const char * ct)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
strncmp(const char * cs,const char * ct,size_t count)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
strchr(const char * s,int c)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
strlen(const char * s)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
memchr(const void * cs,int c,size_t count)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
memscan(void * addr,int c,size_t size)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
strnlen(const char * s,size_t count)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