From 8187b0ccda766ff2000e954f01ba918faefc05d2 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Thu, 5 Oct 2000 05:10:27 +0000 Subject: Major update to string handling. strcmp and friends were horribly broken. They now test out as working properly. -Erik --- Makefile | 8 +- include/errno.h | 13 +- libc/string/Makefile | 10 +- libc/string/string.c | 580 ++++++++++--------------------------------------- test/string/Makefile | 21 ++ test/string/testcopy.c | 108 +++++++++ 6 files changed, 257 insertions(+), 483 deletions(-) create mode 100644 test/string/testcopy.c diff --git a/Makefile b/Makefile index ef5e37c85..f161f2b4c 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ DIRS = error getent malloc misc regex stdio \ string termios time sysdeps #rpc all: libc.a -libc.a: subdirs headers +libc.a: headers subdirs @echo @echo Finally finished compiling... @echo @@ -32,9 +32,9 @@ libc.a: subdirs headers headers: dummy - @if [ ! -L "include/asm" ]; then ln -s /usr/src/linux/include/asm include/asm ; fi - @if [ ! -L "include/net" ]; then ln -s /usr/src/linux/include/net include/net ; fi - @if [ ! -L "include/linux" ]; then ln -s /usr/src/linux/include/linux include/linux ; fi + @if [ ! -L "include/asm" ]; then ln -s /usr/include/asm include/asm ; fi + @if [ ! -L "include/net" ]; then ln -s /usr/include/net include/net ; fi + @if [ ! -L "include/linux" ]; then ln -s /usr/include/linux include/linux ; fi tags: ctags -R diff --git a/include/errno.h b/include/errno.h index 498db0fbf..862d0f2cb 100644 --- a/include/errno.h +++ b/include/errno.h @@ -4,23 +4,14 @@ #include #include -#ifdef __USE_BSD extern int sys_nerr; extern char *sys_errlist[]; -#endif -#ifdef __USE_GNU -extern int _sys_nerr; -extern char *_sys_errlist[]; -#endif +#define _sys_nerr sys_nerr +#define _sys_errlist sys_errlist extern int errno; - -__BEGIN_DECLS - extern void perror __P ((__const char* __s)); extern char* strerror __P ((int __errno)); -__END_DECLS - #endif diff --git a/libc/string/Makefile b/libc/string/Makefile index 3af022365..01d1ee433 100644 --- a/libc/string/Makefile +++ b/libc/string/Makefile @@ -26,11 +26,13 @@ LIBC=$(TOPDIR)libc.a MSRC=string.c MOBJ=strlen.o strcat.o strcpy.o strcmp.o strncat.o strncpy.o strncmp.o \ - strchr.o strrchr.o strdup.o memcpy.o memccpy.o memchr.o memset.o \ - memcmp.o memmove.o movedata.o + strchr.o strrchr.o strdup.o memcpy.o memccpy.o memset.o \ + memmove.o + CSRC=strpbrk.c strsep.c strstr.c strtok.c strcspn.c \ - strspn.c strcasecmp.c strncasecmp.c config.c -COBJS=$(patsubst %.c,%.o, $(CFILES)) + config.c memcmp.c memchr.c strspn.c strcasecmp.c \ + strncasecmp.c +COBJS=$(patsubst %.c,%.o, $(CSRC)) all: $(MOBJ) $(COBJS) $(LIBC) diff --git a/libc/string/string.c b/libc/string/string.c index 0025cec2b..1777ce03c 100644 --- a/libc/string/string.c +++ b/libc/string/string.c @@ -6,21 +6,10 @@ #include #include -#ifdef __AS386_16__ -#if __FIRST_ARG_IN_AX__ -#define BCC_AX_ASM /* BCC Assembler that can cope with arg in AX */ -#else -#define BCC_AX_ASM -#define BCC_ASM /* Use 16 bit BCC assembler */ -#endif - -#define PARANOID /* Include extra code for cld and ES register */ -#endif - /* This is a basic string package; it includes the most used functions strlen strcat strcpy strcmp strncat strncpy strncmp strchr strrchr strdup - memcpy memccpy memchr memset memcmp memmove + memcpy memccpy memset memmove These functions are in seperate files. strpbrk.o strsep.o strstr.o strtok.o strcspn.o @@ -30,56 +19,18 @@ /********************** Function strlen ************************************/ #ifdef L_strlen -size_t strlen(str) -const char * str; +size_t strlen(const char * str) { -#ifdef BCC_AX_ASM -#asm -#if !__FIRST_ARG_IN_AX__ - mov bx,sp -#endif - push di - -#ifdef PARANOID - push es - push ds ; Im not sure if this is needed, so just in case. - pop es - cld -#endif ! This is almost the same as memchr, but it can - ! stay as a special. - -#if __FIRST_ARG_IN_AX__ - mov di,ax -#else - mov di,[bx+2] -#endif - mov cx,#-1 - xor ax,ax - repne - scasb - not cx - dec cx - mov ax,cx - -#ifdef PARANOID - pop es -#endif - pop di -#endasm -#else register char * p =(char *) str; while(*p) p++; return p-str; -#endif /* ifdef BCC_AX_ASM */ } #endif /********************** Function strcat ************************************/ #ifdef L_strcat -char * strcat(d, s) -char *d; -const char * s; +char * strcat(char *d, const char * s) { (void) strcpy(d+strlen(d), s); return d; @@ -89,9 +40,7 @@ const char * s; /********************** Function strcpy ************************************/ #ifdef L_strcpy -char * strcpy(d, s) -char *d; -const char * s; +char * strcpy( char *d, const char * s) { /* This is probably the quickest on an 8086 but a CPU with a cache will * prefer to do this in one pass */ @@ -102,68 +51,29 @@ const char * s; /********************** Function strcmp ************************************/ #ifdef L_strcmp -int strcmp(d, s) -const char *d; -const char * s; +int strcmp(const char *d, const char * s) { - /* There are a number of ways to do this and it really does depend on the - types of strings given as to which is better, nevertheless the Glib - method is quite reasonable so we'll take that */ - -#ifdef BCC_AX_ASM -#asm - mov bx,sp - push di - push si - -#ifdef PARANOID - push es - push ds ; Im not sure if this is needed, so just in case. - pop es - cld -#endif - -#if __FIRST_ARG_IN_AX__ - mov di,ax ; dest - mov si,[bx+2] ; source -#else - mov di,[bx+2] ; dest - mov si,[bx+4] ; source -#endif -sc_1: - lodsb - scasb - jne sc_2 ; If bytes are diff skip out. - testb al,al - jne sc_1 ; If this byte in str1 is nul the strings are equal - xor ax,ax ; so return zero - jmp sc_3 -sc_2: - sbb ax,ax ; Collect correct val (-1,1). - orb al,#1 -sc_3: - -#ifdef PARANOID - pop es -#endif - pop si - pop di -#endasm -#else /* ifdef BCC_AX_ASM */ - register char *s1=(char *)d, *s2=(char *)s, c1,c2; - while((c1= *s1++) == (c2= *s2++) && c1 ); - return c1 - c2; -#endif /* ifdef BCC_AX_ASM */ + register const unsigned char *s1 = (const unsigned char *) d; + register const unsigned char *s2 = (const unsigned char *) s; + unsigned register char c1, c2; + + do + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0') + return c1 - c2; + } + while (c1 == c2); + + return c1 - c2; } #endif /********************** Function strncat ************************************/ #ifdef L_strncat -char * strncat(d, s, l) -char *d; -const char *s; -size_t l; +char * strncat( char *d, const char *s, size_t l) { register char *s1=d+strlen(d), *s2; @@ -182,86 +92,110 @@ size_t l; /********************** Function strncpy ************************************/ #ifdef L_strncpy -char * strncpy(d, s, l) /* FIXME need the fast version of this */ -char *d; -const char *s; -size_t l; +char * strncpy ( char *s1, const char *s2, size_t n) { - register char *s1=d; - register const char *s2=s; - while(l > 0) - { - l--; - if( (*s1++ = *s2++) == '\0') - break; - } - - /* This _is_ correct strncpy is supposed to zap */ - for(; l>0; l--) *s1++ = '\0'; - return d; + register char c; + char *s = s1; + + --s1; + + if (n >= 4) + { + size_t n4 = n >> 2; + + for (;;) + { + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + if (--n4 == 0) + goto last_chars; + } + n = n - (s1 - s) - 1; + if (n == 0) + return s; + goto zero_fill; + } + +last_chars: + n &= 3; + if (n == 0) + return s; + + do + { + c = *s2++; + *++s1 = c; + if (--n == 0) + return s; + } + while (c != '\0'); + +zero_fill: + do + *++s1 = '\0'; + while (--n > 0); + + return s; } #endif /********************** Function strncmp ************************************/ #ifdef L_strncmp -int strncmp(d, s, l) -const char *d, *s; -size_t l; +int strncmp (const char *s1, const char *s2, size_t n) { -#ifdef BCC_AX_ASM -#asm - mov bx,sp - push si - push di - -#ifdef PARANOID - push es - push ds ! Im not sure if this is needed, so just in case. - pop es - cld -#endif - -#if __FIRST_ARG_IN_AX__ - mov si,ax - mov di,[bx+2] - mov cx,[bx+4] -#else - mov si,[bx+2] ! Fetch - mov di,[bx+4] - mov cx,[bx+6] -#endif - - inc cx -lp1: - dec cx - je lp2 - lodsb - scasb - jne lp3 - testb al,al - jne lp1 -lp2: - xor ax,ax - jmp lp4 -lp3: - sbb ax,ax - or al,#1 -lp4: - -#ifdef PARANOID - pop es -#endif - pop di - pop si -#endasm -#else - register char c1=0, c2=0; - while(l-- >0) - if( (c1= *d++) != (c2= *s++) || c1 == '\0' ) - break; - return c1-c2; -#endif + unsigned register char c1 = '\0'; + unsigned register char c2 = '\0'; + + if (n >= 4) + { + size_t n4 = n >> 2; + do + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + } while (--n4 > 0); + n &= 3; + } + + while (n > 0) + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + n--; + } + + return c1 - c2; } #endif @@ -273,37 +207,6 @@ strchr(s, c) const char * s; int c; { -#ifdef BCC_AX_ASM -#asm - mov bx,sp - push si -#if __FIRST_ARG_IN_AX__ - mov bx,[bx+2] - mov si,ax -#else - mov si,[bx+2] - mov bx,[bx+4] -#endif - xor ax,ax - -#ifdef PARANOID - cld -#endif - -in_loop: - lodsb - cmp al,bl - jz got_it - or al,al - jnz in_loop - pop si - ret -got_it: - lea ax,[si-1] - pop si - -#endasm -#else /* ifdef BCC_AX_ASM */ register char ch; for(;;) { @@ -311,7 +214,6 @@ got_it: if( ch == 0 ) return 0; s++; } -#endif /* ifdef BCC_AX_ASM */ } #endif @@ -361,52 +263,9 @@ void *d; const void *s; size_t l; { -#ifdef BCC_AX_ASM -#asm - mov bx,sp - push di - push si - -#ifdef PARANOID - push es - push ds ; Im not sure if this is needed, so just in case. - pop es - cld -#endif - -#if __FIRST_ARG_IN_AX__ - mov di,ax ; dest - mov si,[bx+2] ; source - mov cx,[bx+4] ; count -#else - mov di,[bx+2] ; dest - mov si,[bx+4] ; source - mov cx,[bx+6] ; count - - mov ax,di -#endif - ; If di is odd mov 1 byte before doing word move - ; this will speed slightly but - ; NB 8086 has no problem with mis-aligned access. - - shr cx,#1 ; Do this faster by doing a mov word - rep - movsw - adc cx,cx ; Retrieve the leftover 1 bit from cflag. - rep - movsb - -#ifdef PARANOID - pop es -#endif - pop si - pop di -#endasm -#else /* ifdef BCC_AX_ASM */ register char *s1=d, *s2=(char *)s; for( ; l>0; l--) *((unsigned char*)s1++) = *((unsigned char*)s2++); return d; -#endif /* ifdef BCC_AX_ASM */ } #endif @@ -427,59 +286,6 @@ size_t l; } #endif -/********************** Function memchr ************************************/ - -#ifdef L_memchr -void * memchr(str, c, l) -const void * str; -int c; -size_t l; -{ -#ifdef BCC_ASM -#asm - mov bx,sp - push di - -#ifdef PARANOID - push es - push ds ; Im not sure if this is needed, so just in case. - pop es - cld -#endif - - mov di,[bx+2] - mov ax,[bx+4] - mov cx,[bx+6] - test cx,cx - je is_z ! Zero length, do not find. - - repne ! Scan - scasb - jne is_z ! Not found, ret zero - dec di ! Adjust ptr - mov ax,di ! return - jmp xit -is_z: - xor ax,ax -xit: - -#ifdef PARANOID - pop es -#endif - pop di -#endasm -#else /* ifdef BCC_ASM */ - register char *p=(char *)str; - while(l-- > 0) - { - if(*p == c) return p; - p++; - } - return 0; -#endif /* ifdef BCC_ASM */ -} -#endif - /********************** Function memset ************************************/ #ifdef L_memset @@ -488,109 +294,9 @@ void * str; int c; size_t l; { -#ifdef BCC_AX_ASM -#asm - mov bx,sp - push di - -#ifdef PARANOID - push es - push ds ; Im not sure if this is needed, so just in case. - pop es - cld -#endif - -#if __FIRST_ARG_IN_AX__ - mov di,ax ; Fetch - mov ax,[bx+2] - mov cx,[bx+4] -#else - mov di,[bx+2] ; Fetch - mov ax,[bx+4] - mov cx,[bx+6] -#endif - -; How much difference does this alignment make ? -; I don`t think it`s significant cause most will already be aligned. - -; test cx,cx ; Zero size - skip -; je xit -; -; test di,#1 ; Line it up -; je s_1 -; stosb -; dec cx -;s_1: - - mov ah,al ; Replicate byte - shr cx,#1 ; Do this faster by doing a sto word - rep ; Bzzzzz ... - stosw - adc cx,cx ; Retrieve the leftover 1 bit from cflag. - - rep ; ... z - stosb - -xit: - mov ax,[bx+2] -#ifdef PARANOID - pop es -#endif - pop di -#endasm -#else /* ifdef BCC_AX_ASM */ register char *s1=str; while(l-->0) *s1++ = c; return str; -#endif /* ifdef BCC_AX_ASM */ -} -#endif - -/********************** Function memcmp ************************************/ - -#ifdef L_memcmp -int memcmp(s, d, l) -const void *s, *d; -size_t l; -{ -#ifdef BCC_ASM -#asm - mov bx,sp - push di - push si - -#ifdef PARANOID - push es - push ds ! Im not sure if this is needed, so just in case. - pop es - cld -#endif - - mov si,[bx+2] ! Fetch - mov di,[bx+4] - mov cx,[bx+6] - xor ax,ax - - rep ! Bzzzzz - cmpsb - je xit ! All the same! - sbb ax,ax - sbb ax,#-1 ! choose +/-1 -xit: -#ifdef PARANOID - pop es -#endif - pop si - pop di -#endasm -#else /* ifdef BCC_ASM */ - register const char *s1=d, *s2=s; - register char c1=0, c2=0; - while(l-- > 0) - if( (c1= *s1++) != (c2= *s2++) ) - break; - return c1-c2; -#endif /* ifdef BCC_ASM */ } #endif @@ -615,60 +321,6 @@ size_t l; } #endif -/********************** Function movedata ***********************************/ - -#ifdef L_movedata - -/* NB There isn't any C version of this function ... */ - -#ifdef BCC_AX_ASM -void -__movedata(srcseg, srcoff, destseg, destoff, len) -unsigned int srcseg, srcoff, destseg, destoff, len; -{ -#asm - push bp - mov bp,sp - push si - push di - push ds -#ifdef PARANOID - push es - cld -#endif - - ! sei ! Are we _really_ paranoid ? - -#if !__FIRST_ARG_IN_AX__ - mov ds,[bp+4] ! Careful, [bp+xx] is SS based. - mov si,[bp+6] - mov es,[bp+8] - mov di,[bp+10] - mov cx,[bp+12] -#else - mov ds,ax - mov si,[bp+4] - mov es,[bp+6] - mov di,[bp+8] - mov cx,[bp+10] -#endif - rep - movsb - - ! cli ! Are we _really_ paranoid ? - -#ifdef PARANOID - pop es -#endif - pop ds - pop di - pop si - pop bp -#endasm -} -#endif - -#endif /********************** THE END ********************************************/ diff --git a/test/string/Makefile b/test/string/Makefile index b3021e0fc..5384c9dec 100644 --- a/test/string/Makefile +++ b/test/string/Makefile @@ -20,6 +20,7 @@ endif STRIP = $(STRIPTOOL) --remove-section=.note --remove-section=.comment $@ TARGETS=string string_glibc +TARGETS+=testcopy testcopy_glibc all: $(TARGETS) @@ -43,6 +44,26 @@ string_glibc: string.c Makefile $(TOPDIR)libc.a -./$@ -@ echo " " +testcopy: testcopy.c Makefile $(TOPDIR)libc.a + -@ echo "-------" + -@ echo " " + -@ echo "Compiling vs uCLibc: " + -@ echo " " + $(CC) $(XCFLAGS) -c $< -o $@.o + $(CC) $(XLDFLAGS) $@.o -o $@ $(EXTRA_LIBS) + -./$@ + -@ echo " " + +testcopy_glibc: testcopy.c Makefile $(TOPDIR)libc.a + -@ echo "-------" + -@ echo " " + -@ echo "Compiling vs GNU libc: " + -@ echo " " + $(CC) $(YCFLAGS) -c $< -o $@.o + $(CC) $(YLDFLAGS) --static $@.o -o $@ + -./$@ + -@ echo " " + clean: rm -f *.[oa] *~ core $(TARGETS) diff --git a/test/string/testcopy.c b/test/string/testcopy.c new file mode 100644 index 000000000..02d193779 --- /dev/null +++ b/test/string/testcopy.c @@ -0,0 +1,108 @@ +/* Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + Contributed by Torbjorn Granlund (tege@sics.se). + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + char *mem, *memp; + char *rand_mem; + char *lo_around, *hi_around; + int size, max_size; + int src_off, dst_off; + int i; + int space_around = 10; + + max_size = 256; + + mem = malloc (max_size + 2 * max_size + 2 * space_around); + rand_mem = malloc (max_size); + lo_around = malloc (space_around); + hi_around = malloc (space_around); + memp = mem + space_around; + + /* Fill RAND_MEM with random bytes, each non-zero. */ + for (i = 0; i < max_size; i++) + { + int x; + do + x = rand (); + while (x == 0); + rand_mem[i] = x; + } + + for (size = 0; size < max_size; size++) + { + printf("phase %d\n", size); + for (src_off = 0; src_off <= 16; src_off++) + { + for (dst_off = 0; dst_off <= 16; dst_off++) + { + /* Put zero around the intended destination, to check + that it's not clobbered. */ + for (i = 1; i < space_around; i++) + { + memp[dst_off - i] = 0; + memp[dst_off + size - 1 + i] = 0; + } + + /* Fill the source area with known contents. */ + for (i = 0; i < size; i++) + memp[src_off + i] = rand_mem[i]; + + /* Remember the contents around the destination area. + (It might not be what we wrote some lines above, since + the src area and the dst area overlap.) */ + for (i = 1; i < space_around; i++) + { + lo_around[i] = memp[dst_off - i]; + hi_around[i] = memp[dst_off + size - 1 + i]; + } + + memmove (memp + dst_off, memp + src_off, size); + + /* Check that the destination area has the same + contents we wrote to the source area. */ + for (i = 0; i < size; i++) + { + if (memp[dst_off + i] != rand_mem[i]) + abort (); + } + + /* Check that the area around the destination is not + clobbered. */ + for (i = 1; i < space_around; i++) + { + if (memp[dst_off - i] != lo_around[i]) + abort (); + if (memp[dst_off + size - 1 + i] != hi_around[i]) + abort (); + } + } + } + } + + puts ("Test succeeded."); + + return 0; +} -- cgit v1.2.3