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 | |