xref: /openbmc/linux/arch/x86/lib/string_32.c (revision 8dce88fe)
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