diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/libc.c | 143 | 
1 files changed, 143 insertions, 0 deletions
| diff --git a/src/libc.c b/src/libc.c new file mode 100644 index 000000000..e408ba51e --- /dev/null +++ b/src/libc.c @@ -0,0 +1,143 @@ +#include "global.h" +#include <stddef.h> + +#define LBLOCKSIZE (sizeof(long)) + +// Nonzero if (long)X contains a NULL byte. +#define CONTAINSNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080) + +// Nonzero if X is not aligned on a "long" boundary. +#define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) + +void *memcpy(void *dst0, const void *src0, size_t len0) +{ +	char *dst = dst0; +	const char *src = src0; +	long *aligned_dst; +	const long *aligned_src; +	unsigned int len = len0; +	 +	// If the size is small, or either src or dst is unaligned, +	// then go to the byte copy loop. This should be rare. +	if(len >= 16 && !(UNALIGNED(src) | UNALIGNED(dst))) +	{ +		aligned_dst = (long *)dst; +		aligned_src = (long *)src; +		 +		// Copy 4X long words at a time if possible. +		while(len >= 16) +		{ +			*aligned_dst++ = *aligned_src++; +			*aligned_dst++ = *aligned_src++; +			*aligned_dst++ = *aligned_src++; +			*aligned_dst++ = *aligned_src++; +			len -= 16; +		} +		 +		// Copy one long word at a time if possible +		while(len >= 4) +		{ +			*aligned_dst++ = *aligned_src++; +			len -= 4; +		} +		 +		dst = (char *)aligned_dst; +		src = (char *)aligned_src; +	} +	 +	// Pick up any remaining bytes with a byte copier. +	while(len--) +		*dst++ = *src++; +	 +	return dst0; +} + +void *memset(void *m, int c, size_t n) +{ +	char *s = (char *)m; +	int count, i; +	unsigned long buffer; +	unsigned long *aligned_addr; +	unsigned char *unaligned_addr; +	 +	// If the size is small or m is unaligned, +	// then go to the byte copy loop. This should be rare. +	if(n >= LBLOCKSIZE && !UNALIGNED(m)) +	{ +		// We know that n is large and m is word-aligned. +		aligned_addr = (unsigned long *)m; +		 +		// Store C into each char sized location in buffer so that +		// we can set large blocks quickly. +		c &= 0xFF; +		if(LBLOCKSIZE == 4) +		{ +			buffer = (c << 8) | c; +			buffer |= (buffer << 16); +		} +		else +		{ +			buffer = 0; +			for(i = 0; i < LBLOCKSIZE; i++) +				buffer = (buffer << 8) | c; +		} +		 +		while(n >= LBLOCKSIZE * 4) +		{ +			*aligned_addr++ = buffer; +			*aligned_addr++ = buffer; +			*aligned_addr++ = buffer; +			*aligned_addr++ = buffer; +			n -= LBLOCKSIZE * 4; +		} +		while(n >= LBLOCKSIZE) +		{ +			*aligned_addr++ = buffer; +			n -= LBLOCKSIZE; +		} +		 +		s = (char *)aligned_addr; +	} +	 +	// Pick up the remainder with a bytewise loop. +	while(n--) +		*s++ = (char)c; +	 +	return m; +} + +int strcmp(const char *s1, const char *s2) +{ +	unsigned long *a1; +	unsigned long *a2; +	 +	// If s1 or s2 are unaligned, then skip this and compare bytes. +	if(!(UNALIGNED(s1) | UNALIGNED(s2))) +	{ +		// Compare them a word at a time. +		a1 = (unsigned long *)s1; +		a2 = (unsigned long *)s2; +		while(*a1 == *a2) +		{ +			// If *a1 == *a2, and we find a null in *a1, +			// then the strings must be equal, so return zero. +			if(CONTAINSNULL(*a1)) +				return 0; +			 +			a1++; +			a2++; +		} +		 +		s1 = (char *)a1; +		s2 = (char *)a2; +	} +	 +	// Check the remaining few bytes. +	while(*s1 != '\0' && *s1 == *s2) +	{ +		s1++; +		s2++; +	} +	 +	return (*(unsigned char *) s1) - (*(unsigned char *) s2); +} | 
