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