|
|
1.1 root 1: #ifndef _I386_STRING_H_
2: #define _I386_STRING_H_
3:
4: /*
5: * This string-include defines all string functions as inline
6: * functions. Use gcc. It also assumes ds=es=data space, this should be
7: * normal. Most of the string-functions are rather heavily hand-optimized,
8: * see especially strtok,strstr,str[c]spn. They should work, but are not
9: * very easy to understand. Everything is done entirely within the register
10: * set, making the functions fast and clean. String instructions have been
11: * used through-out, making for "slightly" unclear code :-)
12: *
13: * Copyright (C) 1991, 1992 Linus Torvalds
14: */
15:
16: #define __HAVE_ARCH_STRCPY
17: extern inline char * strcpy(char * dest,const char *src)
18: {
19: __asm__ __volatile__(
20: "cld\n"
21: "1:\tlodsb\n\t"
22: "stosb\n\t"
23: "testb %%al,%%al\n\t"
24: "jne 1b"
25: : /* no output */
26: :"S" (src),"D" (dest):"si","di","ax","memory");
27: return dest;
28: }
29:
30: #define __HAVE_ARCH_STRNCPY
31: extern inline char * strncpy(char * dest,const char *src,size_t count)
32: {
33: __asm__ __volatile__(
34: "cld\n"
35: "1:\tdecl %2\n\t"
36: "js 2f\n\t"
37: "lodsb\n\t"
38: "stosb\n\t"
39: "testb %%al,%%al\n\t"
40: "jne 1b\n\t"
41: "rep\n\t"
42: "stosb\n"
43: "2:"
44: : /* no output */
45: :"S" (src),"D" (dest),"c" (count):"si","di","ax","cx","memory");
46: return dest;
47: }
48:
49: #define __HAVE_ARCH_STRCAT
50: extern inline char * strcat(char * dest,const char * src)
51: {
52: __asm__ __volatile__(
53: "cld\n\t"
54: "repne\n\t"
55: "scasb\n\t"
56: "decl %1\n"
57: "1:\tlodsb\n\t"
58: "stosb\n\t"
59: "testb %%al,%%al\n\t"
60: "jne 1b"
61: : /* no output */
62: :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
63: return dest;
64: }
65:
66: #define __HAVE_ARCH_STRNCAT
67: extern inline char * strncat(char * dest,const char * src,size_t count)
68: {
69: __asm__ __volatile__(
70: "cld\n\t"
71: "repne\n\t"
72: "scasb\n\t"
73: "decl %1\n\t"
74: "movl %4,%3\n"
75: "1:\tdecl %3\n\t"
76: "js 2f\n\t"
77: "lodsb\n\t"
78: "stosb\n\t"
79: "testb %%al,%%al\n\t"
80: "jne 1b\n"
81: "2:\txorl %2,%2\n\t"
82: "stosb"
83: : /* no output */
84: :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
85: :"si","di","ax","cx","memory");
86: return dest;
87: }
88:
89: #define __HAVE_ARCH_STRCMP
90: extern inline int strcmp(const char * cs,const char * ct)
91: {
92: register int __res;
93: __asm__ __volatile__(
94: "cld\n"
95: "1:\tlodsb\n\t"
96: "scasb\n\t"
97: "jne 2f\n\t"
98: "testb %%al,%%al\n\t"
99: "jne 1b\n\t"
100: "xorl %%eax,%%eax\n\t"
101: "jmp 3f\n"
102: "2:\tsbbl %%eax,%%eax\n\t"
103: "orb $1,%%eax\n"
104: "3:"
105: :"=a" (__res):"S" (cs),"D" (ct):"si","di");
106: return __res;
107: }
108:
109: #define __HAVE_ARCH_STRNCMP
110: extern inline int strncmp(const char * cs,const char * ct,size_t count)
111: {
112: register int __res;
113: __asm__ __volatile__(
114: "cld\n"
115: "1:\tdecl %3\n\t"
116: "js 2f\n\t"
117: "lodsb\n\t"
118: "scasb\n\t"
119: "jne 3f\n\t"
120: "testb %%al,%%al\n\t"
121: "jne 1b\n"
122: "2:\txorl %%eax,%%eax\n\t"
123: "jmp 4f\n"
124: "3:\tsbbl %%eax,%%eax\n\t"
125: "orb $1,%%al\n"
126: "4:"
127: :"=a" (__res):"S" (cs),"D" (ct),"c" (count):"si","di","cx");
128: return __res;
129: }
130:
131: #define __HAVE_ARCH_STRCHR
132: extern inline char * strchr(const char * s, int c)
133: {
134: register char * __res;
135: __asm__ __volatile__(
136: "cld\n\t"
137: "movb %%al,%%ah\n"
138: "1:\tlodsb\n\t"
139: "cmpb %%ah,%%al\n\t"
140: "je 2f\n\t"
141: "testb %%al,%%al\n\t"
142: "jne 1b\n\t"
143: "movl $1,%1\n"
144: "2:\tmovl %1,%0\n\t"
145: "decl %0"
146: :"=a" (__res):"S" (s),"0" (c):"si");
147: return __res;
148: }
149:
150: #define __HAVE_ARCH_STRRCHR
151: extern inline char * strrchr(const char * s, int c)
152: {
153: register char * __res;
154: __asm__ __volatile__(
155: "cld\n\t"
156: "movb %%al,%%ah\n"
157: "1:\tlodsb\n\t"
158: "cmpb %%ah,%%al\n\t"
159: "jne 2f\n\t"
160: "leal -1(%%esi),%0\n"
161: "2:\ttestb %%al,%%al\n\t"
162: "jne 1b"
163: :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
164: return __res;
165: }
166:
167: #define __HAVE_ARCH_STRSPN
168: extern inline size_t strspn(const char * cs, const char * ct)
169: {
170: register char * __res;
171: __asm__ __volatile__(
172: "cld\n\t"
173: "movl %4,%%edi\n\t"
174: "repne\n\t"
175: "scasb\n\t"
176: "notl %%ecx\n\t"
177: "decl %%ecx\n\t"
178: "movl %%ecx,%%edx\n"
179: "1:\tlodsb\n\t"
180: "testb %%al,%%al\n\t"
181: "je 2f\n\t"
182: "movl %4,%%edi\n\t"
183: "movl %%edx,%%ecx\n\t"
184: "repne\n\t"
185: "scasb\n\t"
186: "je 1b\n"
187: "2:\tdecl %0"
188: :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
189: :"ax","cx","dx","di");
190: return __res-cs;
191: }
192:
193: #define __HAVE_ARCH_STRCSPN
194: extern inline size_t strcspn(const char * cs, const char * ct)
195: {
196: register char * __res;
197: __asm__ __volatile__(
198: "cld\n\t"
199: "movl %4,%%edi\n\t"
200: "repne\n\t"
201: "scasb\n\t"
202: "notl %%ecx\n\t"
203: "decl %%ecx\n\t"
204: "movl %%ecx,%%edx\n"
205: "1:\tlodsb\n\t"
206: "testb %%al,%%al\n\t"
207: "je 2f\n\t"
208: "movl %4,%%edi\n\t"
209: "movl %%edx,%%ecx\n\t"
210: "repne\n\t"
211: "scasb\n\t"
212: "jne 1b\n"
213: "2:\tdecl %0"
214: :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
215: :"ax","cx","dx","di");
216: return __res-cs;
217: }
218:
219: #define __HAVE_ARCH_STRPBRK
220: extern inline char * strpbrk(const char * cs,const char * ct)
221: {
222: register char * __res;
223: __asm__ __volatile__(
224: "cld\n\t"
225: "movl %4,%%edi\n\t"
226: "repne\n\t"
227: "scasb\n\t"
228: "notl %%ecx\n\t"
229: "decl %%ecx\n\t"
230: "movl %%ecx,%%edx\n"
231: "1:\tlodsb\n\t"
232: "testb %%al,%%al\n\t"
233: "je 2f\n\t"
234: "movl %4,%%edi\n\t"
235: "movl %%edx,%%ecx\n\t"
236: "repne\n\t"
237: "scasb\n\t"
238: "jne 1b\n\t"
239: "decl %0\n\t"
240: "jmp 3f\n"
241: "2:\txorl %0,%0\n"
242: "3:"
243: :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
244: :"ax","cx","dx","di");
245: return __res;
246: }
247:
248: #define __HAVE_ARCH_STRSTR
249: extern inline char * strstr(const char * cs,const char * ct)
250: {
251: register char * __res;
252: __asm__ __volatile__(
253: "cld\n\t" \
254: "movl %4,%%edi\n\t"
255: "repne\n\t"
256: "scasb\n\t"
257: "notl %%ecx\n\t"
258: "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
259: "movl %%ecx,%%edx\n"
260: "1:\tmovl %4,%%edi\n\t"
261: "movl %%esi,%%eax\n\t"
262: "movl %%edx,%%ecx\n\t"
263: "repe\n\t"
264: "cmpsb\n\t"
265: "je 2f\n\t" /* also works for empty string, see above */
266: "xchgl %%eax,%%esi\n\t"
267: "incl %%esi\n\t"
268: "cmpb $0,-1(%%eax)\n\t"
269: "jne 1b\n\t"
270: "xorl %%eax,%%eax\n\t"
271: "2:"
272: :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
273: :"cx","dx","di","si");
274: return __res;
275: }
276:
277: #define __HAVE_ARCH_STRLEN
278: extern inline size_t strlen(const char * s)
279: {
280: register int __res;
281: __asm__ __volatile__(
282: "cld\n\t"
283: "repne\n\t"
284: "scasb\n\t"
285: "notl %0\n\t"
286: "decl %0"
287: :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
288: return __res;
289: }
290:
291: #define __HAVE_ARCH_STRTOK
292: extern inline char * strtok(char * s,const char * ct)
293: {
294: register char * __res;
295: __asm__ __volatile__(
296: "testl %1,%1\n\t"
297: "jne 1f\n\t"
298: "testl %0,%0\n\t"
299: "je 8f\n\t"
300: "movl %0,%1\n"
301: "1:\txorl %0,%0\n\t"
302: "movl $-1,%%ecx\n\t"
303: "xorl %%eax,%%eax\n\t"
304: "cld\n\t"
305: "movl %4,%%edi\n\t"
306: "repne\n\t"
307: "scasb\n\t"
308: "notl %%ecx\n\t"
309: "decl %%ecx\n\t"
310: "je 7f\n\t" /* empty delimiter-string */
311: "movl %%ecx,%%edx\n"
312: "2:\tlodsb\n\t"
313: "testb %%al,%%al\n\t"
314: "je 7f\n\t"
315: "movl %4,%%edi\n\t"
316: "movl %%edx,%%ecx\n\t"
317: "repne\n\t"
318: "scasb\n\t"
319: "je 2b\n\t"
320: "decl %1\n\t"
321: "cmpb $0,(%1)\n\t"
322: "je 7f\n\t"
323: "movl %1,%0\n"
324: "3:\tlodsb\n\t"
325: "testb %%al,%%al\n\t"
326: "je 5f\n\t"
327: "movl %4,%%edi\n\t"
328: "movl %%edx,%%ecx\n\t"
329: "repne\n\t"
330: "scasb\n\t"
331: "jne 3b\n\t"
332: "decl %1\n\t"
333: "cmpb $0,(%1)\n\t"
334: "je 5f\n\t"
335: "movb $0,(%1)\n\t"
336: "incl %1\n\t"
337: "jmp 6f\n"
338: "5:\txorl %1,%1\n"
339: "6:\tcmpb $0,(%0)\n\t"
340: "jne 7f\n\t"
341: "xorl %0,%0\n"
342: "7:\ttestl %0,%0\n\t"
343: "jne 8f\n\t"
344: "movl %0,%1\n"
345: "8:"
346: :"=b" (__res),"=S" (___strtok)
347: :"0" (___strtok),"1" (s),"g" (ct)
348: :"ax","cx","dx","di","memory");
349: return __res;
350: }
351:
352: extern inline void * __memcpy(void * to, const void * from, size_t n)
353: {
354: __asm__ __volatile__(
355: "cld\n\t"
356: "rep ; movsl\n\t"
357: "testb $2,%b1\n\t"
358: "je 1f\n\t"
359: "movsw\n"
360: "1:\ttestb $1,%b1\n\t"
361: "je 2f\n\t"
362: "movsb\n"
363: "2:"
364: : /* no output */
365: :"c" (n/4), "q" (n),"D" ((long) to),"S" ((long) from)
366: : "cx","di","si","memory");
367: return (to);
368: }
369:
370: /*
371: * This looks horribly ugly, but the compiler can optimize it totally,
372: * as the count is constant.
373: */
374: extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
375: {
376: switch (n) {
377: case 0:
378: return to;
379: case 1:
380: *(unsigned char *)to = *(const unsigned char *)from;
381: return to;
382: case 2:
383: *(unsigned short *)to = *(const unsigned short *)from;
384: return to;
385: case 3:
386: *(unsigned short *)to = *(const unsigned short *)from;
387: *(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
388: return to;
389: case 4:
390: *(unsigned long *)to = *(const unsigned long *)from;
391: return to;
392: }
393: #define COMMON(x) \
394: __asm__("cld\n\t" \
395: "rep ; movsl" \
396: x \
397: : /* no outputs */ \
398: : "c" (n/4),"D" ((long) to),"S" ((long) from) \
399: : "cx","di","si","memory");
400:
401: switch (n % 4) {
402: case 0: COMMON(""); return to;
403: case 1: COMMON("\n\tmovsb"); return to;
404: case 2: COMMON("\n\tmovsw"); return to;
405: case 3: COMMON("\n\tmovsw\n\tmovsb"); return to;
406: }
407: #undef COMMON
408: }
409:
410: #define __HAVE_ARCH_MEMCPY
411: #define memcpy(t, f, n) \
412: (__builtin_constant_p(n) ? \
413: __constant_memcpy((t),(f),(n)) : \
414: __memcpy((t),(f),(n)))
415:
416: #define __HAVE_ARCH_MEMMOVE
417: extern inline void * memmove(void * dest,const void * src, size_t n)
418: {
419: if (dest<src)
420: __asm__ __volatile__(
421: "cld\n\t"
422: "rep\n\t"
423: "movsb"
424: : /* no output */
425: :"c" (n),"S" (src),"D" (dest)
426: :"cx","si","di");
427: else
428: __asm__ __volatile__(
429: "std\n\t"
430: "rep\n\t"
431: "movsb\n\t"
432: "cld"
433: : /* no output */
434: :"c" (n),
435: "S" (n-1+(const char *)src),
436: "D" (n-1+(char *)dest)
437: :"cx","si","di","memory");
438: return dest;
439: }
440:
441: #define memcmp __builtin_memcmp
442:
443: #define __HAVE_ARCH_MEMCHR
444: extern inline void * memchr(const void * cs,int c,size_t count)
445: {
446: register void * __res;
447: if (!count)
448: return NULL;
449: __asm__ __volatile__(
450: "cld\n\t"
451: "repne\n\t"
452: "scasb\n\t"
453: "je 1f\n\t"
454: "movl $1,%0\n"
455: "1:\tdecl %0"
456: :"=D" (__res):"a" (c),"D" (cs),"c" (count)
457: :"cx");
458: return __res;
459: }
460:
461: extern inline void * __memset_generic(void * s, char c,size_t count)
462: {
463: __asm__ __volatile__(
464: "cld\n\t"
465: "rep\n\t"
466: "stosb"
467: : /* no output */
468: :"a" (c),"D" (s),"c" (count)
469: :"cx","di","memory");
470: return s;
471: }
472:
473: /* we might want to write optimized versions of these later */
474: #define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
475:
476: /*
477: * memset(x,0,y) is a reasonably common thing to do, so we want to fill
478: * things 32 bits at a time even when we don't know the size of the
479: * area at compile-time..
480: */
481: extern inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
482: {
483: __asm__ __volatile__(
484: "cld\n\t"
485: "rep ; stosl\n\t"
486: "testb $2,%b1\n\t"
487: "je 1f\n\t"
488: "stosw\n"
489: "1:\ttestb $1,%b1\n\t"
490: "je 2f\n\t"
491: "stosb\n"
492: "2:"
493: : /* no output */
494: :"a" (c), "q" (count), "c" (count/4), "D" ((long) s)
495: :"cx","di","memory");
496: return (s);
497: }
498:
499: /* Added by Gertjan van Wingerde to make minix and sysv module work */
500: #define __HAVE_ARCH_STRNLEN
501: extern inline size_t strnlen(const char * s, size_t count)
502: {
503: register int __res;
504: __asm__ __volatile__(
505: "movl %1,%0\n\t"
506: "jmp 2f\n"
507: "1:\tcmpb $0,(%0)\n\t"
508: "je 3f\n\t"
509: "incl %0\n"
510: "2:\tdecl %2\n\t"
511: "cmpl $-1,%2\n\t"
512: "jne 1b\n"
513: "3:\tsubl %1,%0"
514: :"=a" (__res):"c" (s),"d" (count));
515: return __res;
516: }
517: /* end of additional stuff */
518:
519: /*
520: * This looks horribly ugly, but the compiler can optimize it totally,
521: * as we by now know that both pattern and count is constant..
522: */
523: extern inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
524: {
525: switch (count) {
526: case 0:
527: return s;
528: case 1:
529: *(unsigned char *)s = pattern;
530: return s;
531: case 2:
532: *(unsigned short *)s = pattern;
533: return s;
534: case 3:
535: *(unsigned short *)s = pattern;
536: *(2+(unsigned char *)s) = pattern;
537: return s;
538: case 4:
539: *(unsigned long *)s = pattern;
540: return s;
541: }
542: #define COMMON(x) \
543: __asm__("cld\n\t" \
544: "rep ; stosl" \
545: x \
546: : /* no outputs */ \
547: : "a" (pattern),"c" (count/4),"D" ((long) s) \
548: : "cx","di","memory")
549:
550: switch (count % 4) {
551: case 0: COMMON(""); return s;
552: case 1: COMMON("\n\tstosb"); return s;
553: case 2: COMMON("\n\tstosw"); return s;
554: case 3: COMMON("\n\tstosw\n\tstosb"); return s;
555: }
556: #undef COMMON
557: }
558:
559: #define __constant_c_x_memset(s, c, count) \
560: (__builtin_constant_p(count) ? \
561: __constant_c_and_count_memset((s),(c),(count)) : \
562: __constant_c_memset((s),(c),(count)))
563:
564: #define __memset(s, c, count) \
565: (__builtin_constant_p(count) ? \
566: __constant_count_memset((s),(c),(count)) : \
567: __memset_generic((s),(c),(count)))
568:
569: #define __HAVE_ARCH_MEMSET
570: #define memset(s, c, count) \
571: (__builtin_constant_p(c) ? \
572: __constant_c_x_memset((s),(0x01010101UL*(unsigned char)c),(count)) : \
573: __memset((s),(c),(count)))
574:
575: /*
576: * find the first occurrence of byte 'c', or 1 past the area if none
577: */
578: #define __HAVE_ARCH_MEMSCAN
579: extern inline void * memscan(void * addr, int c, size_t size)
580: {
581: if (!size)
582: return addr;
583: __asm__("cld
584: repnz; scasb
585: jnz 1f
586: dec %%edi
587: 1: "
588: : "=D" (addr), "=c" (size)
589: : "0" (addr), "1" (size), "a" (c));
590: return addr;
591: }
592:
593: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.