-#ifndef _LINUX_STRING_H_
-#define _LINUX_STRING_H_
-
-extern void *_dl_malloc(int size);
-extern char *_dl_getenv(const char *symbol, char **envp);
-extern void _dl_unsetenv(const char *symbol, char **envp);
-extern char *_dl_strdup(const char *string);
-extern void _dl_dprintf(int, const char *, ...);
-
-
-static size_t _dl_strlen(const char * str);
-static char *_dl_strcat(char *dst, const char *src);
-static char * _dl_strcpy(char * dst,const char *src);
-static int _dl_strcmp(const char * s1,const char * s2);
-static int _dl_strncmp(const char * s1,const char * s2,size_t len);
-static char * _dl_strchr(const char * str,int c);
-static char *_dl_strrchr(const char *str, int c);
-static char *_dl_strstr(const char *s1, const char *s2);
-static void * _dl_memcpy(void * dst, const void * src, size_t len);
-static int _dl_memcmp(const void * s1,const void * s2,size_t len);
-static void *_dl_memset(void * str,int c,size_t len);
-static char *_dl_get_last_path_component(char *path);
-static char *_dl_simple_ltoa(char * local, unsigned long i);
-static char *_dl_simple_ltoahex(char * local, unsigned long i);
-
-#ifndef NULL
-#define NULL ((void *) 0)
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2000-2005 by Erik Andersen <andersen@codepoet.org>
+ *
+ * GNU Lesser General Public License version 2.1 or later.
+ */
+
+#ifndef _DL_STRING_H
+#define _DL_STRING_H
+
+#include <features.h>
+
+#define __need_NULL
+#include <stddef.h>
+
+#include <dl-defs.h> /* for do_rem by dl-sysdep.h */
+
+/* provide some sane defaults */
+#ifndef do_rem
+# define do_rem(result, n, base) ((result) = (n) % (base))
+#endif
+#ifndef do_div_10
+# define do_div_10(result, remain) ((result) /= 10)
#endif
-static inline size_t _dl_strlen(const char * str)
+#ifdef IS_IN_rtld
+static __always_inline size_t _dl_strlen(const char *str)
{
- register char *ptr = (char *) str;
-
- while (*ptr)
- ptr++;
+ register const char *ptr = (char *) str-1;
+ while (*++ptr)
+ ;/* empty */
return (ptr - str);
}
-static inline char *_dl_strcat(char *dst, const char *src)
+static __always_inline char * _dl_strcat(char *dst, const char *src)
{
- register char *ptr = dst;
-
- while (*ptr)
- ptr++;
-
- while (*src)
- *ptr++ = *src++;
- *ptr = '\0';
-
+ register char *ptr = dst-1;
+
+ src--;
+ while (*++ptr)
+ ;/* empty */
+ ptr--;
+ while ((*++ptr = *++src) != 0)
+ ;/* empty */
return dst;
}
-static inline char * _dl_strcpy(char * dst,const char *src)
+static __always_inline char * _dl_strcpy(char *dst, const char *src)
{
register char *ptr = dst;
- while (*src)
- *dst++ = *src++;
- *dst = '\0';
+ dst--;src--;
+ while ((*++dst = *++src) != 0)
+ ;/* empty */
return ptr;
}
-
-static inline int _dl_strcmp(const char * s1,const char * s2)
+
+static __always_inline int _dl_strcmp(const char *s1, const char *s2)
{
register unsigned char c1, c2;
-
+ s1--;s2--;
do {
- c1 = (unsigned char) *s1++;
- c2 = (unsigned char) *s2++;
+ c1 = (unsigned char) *++s1;
+ c2 = (unsigned char) *++s2;
if (c1 == '\0')
return c1 - c2;
- }
- while (c1 == c2);
+ } while (c1 == c2);
return c1 - c2;
}
-static inline int _dl_strncmp(const char * s1,const char * s2,size_t len)
-{
- register unsigned char c1 = '\0';
- register unsigned char c2 = '\0';
-
- while (len > 0) {
- c1 = (unsigned char) *s1++;
- c2 = (unsigned char) *s2++;
- if (c1 == '\0' || c1 != c2)
- return c1 - c2;
- len--;
- }
-
- return c1 - c2;
-}
-
-static inline char * _dl_strchr(const char * str,int c)
+static __always_inline char * _dl_strchr(const char *str, int c)
{
register char ch;
-
+ str--;
do {
- if ((ch = *str) == c)
+ if ((ch = *++str) == c)
return (char *) str;
- str++;
}
while (ch);
return 0;
}
-static inline char *_dl_strrchr(const char *str, int c)
+static __always_inline char * _dl_strrchr(const char *str, int c)
{
- register char *prev = 0;
- register char *ptr = (char *) str;
-
- while (*ptr != '\0') {
- if (*ptr == c)
- prev = ptr;
- ptr++;
- }
- if (c == '\0')
- return(ptr);
- return(prev);
-}
-
+ register char *prev = 0;
+ register char *ptr = (char *) str-1;
-static inline char *_dl_strstr(const char *s1, const char *s2)
-{
- register const char *s = s1;
- register const char *p = s2;
-
- do {
- if (!*p) {
- return (char *) s1;;
+ while (*++ptr != '\0') {
+ if (*ptr == c)
+ prev = ptr;
}
- if (*p == *s) {
- ++p;
- ++s;
- } else {
- p = s2;
- if (!*s) {
- return NULL;
- }
- s = ++s1;
- }
- } while (1);
+ if (c == '\0')
+ return(ptr);
+ return(prev);
}
-static inline void * _dl_memcpy(void * dst, const void * src, size_t len)
+static __always_inline char * _dl_strstr(const char *s1, const char *s2)
{
- register char *a = dst;
- register const char *b = src;
+ register const char *s = s1;
+ register const char *p = s2;
- while (len--)
- *a++ = *b++;
+ do {
+ if (!*p)
+ return (char *) s1;;
+ if (*p == *s) {
+ ++p;
+ ++s;
+ } else {
+ p = s2;
+ if (!*s)
+ return NULL;
+ s = ++s1;
+ }
+ } while (1);
+}
+
+static __always_inline void * _dl_memcpy(void *dst, const void *src, size_t len)
+{
+ register char *a = dst-1;
+ register const char *b = src-1;
+ while (len) {
+ *++a = *++b;
+ --len;
+ }
return dst;
}
-
-static inline int _dl_memcmp(const void * s1,const void * s2,size_t len)
+static __always_inline int _dl_memcmp(const void *s1, const void *s2, size_t len)
{
- unsigned char *c1 = (unsigned char *)s1;
- unsigned char *c2 = (unsigned char *)s2;
+ unsigned char *c1 = (unsigned char *)s1-1;
+ unsigned char *c2 = (unsigned char *)s2-1;
- while (len--) {
- if (*c1 != *c2)
+ while (len) {
+ if (*++c1 != *++c2)
return *c1 - *c2;
- c1++;
- c2++;
+ len--;
}
return 0;
}
-static inline void * _dl_memset(void * str,int c,size_t len)
+#if defined(__powerpc__)
+/* Will generate smaller and faster code due to loop unrolling.*/
+static __always_inline void * _dl_memset(void *to, int c, size_t n)
+{
+ unsigned long chunks;
+ unsigned long *tmp_to;
+ unsigned char *tmp_char;
+
+ chunks = n / 4;
+ tmp_to = to + n;
+ c = c << 8 | c;
+ c = c << 16 | c;
+ if (!chunks)
+ goto lessthan4;
+ do {
+ *--tmp_to = c;
+ } while (--chunks);
+lessthan4:
+ n = n % 4;
+ if (!n)
+ return to;
+ tmp_char = (unsigned char *)tmp_to;
+ do {
+ *--tmp_char = c;
+ } while (--n);
+ return to;
+}
+#else
+static __always_inline void * _dl_memset(void *str, int c, size_t len)
{
register char *a = str;
return str;
}
+#endif
-static inline char *_dl_get_last_path_component(char *path)
+static __always_inline char * _dl_get_last_path_component(char *path)
{
- char *s;
- register char *ptr = path;
- register char *prev = 0;
+ register char *ptr = path-1;
- while (*ptr)
- ptr++;
- s = ptr - 1;
+ while (*++ptr)
+ ;/* empty */
/* strip trailing slashes */
- while (s != path && *s == '/') {
- *s-- = '\0';
+ while (ptr != path && *--ptr == '/') {
+ *ptr = '\0';
}
/* find last component */
- ptr = path;
- while (*ptr != '\0') {
- if (*ptr == '/')
- prev = ptr;
- ptr++;
- }
- s = prev;
-
- if (s == NULL || s[1] == '\0')
- return path;
- else
- return s+1;
+ while (ptr != path && *--ptr != '/')
+ ;/* empty */
+ return ptr == path ? ptr : ptr+1;
}
-
+#else /* IS_IN_rtld */
+# include <string.h>
+# define _dl_strlen strlen
+# define _dl_strcat strcat
+# define _dl_strcpy strcpy
+# define _dl_strcmp strcmp
+# define _dl_strrchr strrchr
+# define _dl_memcpy memcpy
+# define _dl_memcmp memcmp
+# define _dl_memset memset
+#endif /* IS_IN_rtld */
+
+#if defined IS_IN_rtld || defined __SUPPORT_LD_DEBUG__
/* Early on, we can't call printf, so use this to print out
- * numbers using the SEND_STDERR() macro */
-static inline char *_dl_simple_ltoa(char * local, unsigned long i)
+ * numbers using the SEND_STDERR() macro. Avoid using mod
+ * or using long division */
+static __always_inline char * _dl_simple_ltoa(char *local, unsigned long i)
{
- /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+ /* 20 digits plus a null terminator should be good for
+ * 64-bit or smaller ints (2^64 - 1)*/
char *p = &local[22];
- *p-- = '\0';
+ *--p = '\0';
do {
- *p-- = '0' + i % 10;
- i /= 10;
+ char temp;
+ do_rem(temp, i, 10);
+ *--p = '0' + temp;
+ do_div_10(i, temp);
} while (i > 0);
- return p + 1;
+ return p;
}
+#endif
-static inline char *_dl_simple_ltoahex(char * local, unsigned long i)
+#ifdef IS_IN_rtld
+static __always_inline char * _dl_simple_ltoahex(char *local, unsigned long i)
{
- /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+ /* 16 digits plus a leading "0x" plus a null terminator,
+ * should be good for 64-bit or smaller ints */
char *p = &local[22];
- *p-- = '\0';
+ *--p = '\0';
do {
- char temp = i % 0x10;
+ char temp = i & 0xf;
if (temp <= 0x09)
- *p-- = '0' + temp;
+ *--p = '0' + temp;
else
- *p-- = 'a' - 0x0a + temp;
- i /= 0x10;
+ *--p = 'a' - 0x0a + temp;
+ i >>= 4;
} while (i > 0);
- *p-- = 'x';
- *p-- = '0';
- return p + 1;
+ *--p = 'x';
+ *--p = '0';
+ return p;
}
+/* The following macros may be used in dl-startup.c to debug
+ * ldso before ldso has fixed itself up to make function calls */
-#if defined mc68000 || defined __arm__ || defined __mips__ || defined __sh__
-/* On some arches constant strings are referenced through the GOT. */
-/* XXX Requires load_addr to be defined. */
-#define SEND_STDERR(X) \
- { const char *__s = (X); \
- if (__s < (const char *) load_addr) __s += load_addr; \
- _dl_write (2, __s, _dl_strlen (__s)); \
- }
+/* On some (wierd) arches, none of this stuff works at all, so
+ * disable the whole lot... */
+#if defined(__mips__)
+
+# define SEND_STDERR(X)
+# define SEND_ADDRESS_STDERR(X, add_a_newline)
+# define SEND_NUMBER_STDERR(X, add_a_newline)
+
+#else
+
+/* On some arches constant strings are referenced through the GOT.
+ * This requires that load_addr must already be defined... */
+#if defined(mc68000) || defined(__arm__) || defined(__thumb__) || \
+ defined(__sh__) || defined(__powerpc__) || \
+ defined(__avr32__) || defined(__xtensa__) || defined(__sparc__) || defined(__microblaze__)
+# define CONSTANT_STRING_GOT_FIXUP(X) \
+ if ((X) < (const char *) load_addr) (X) += load_addr
+# define NO_EARLY_SEND_STDERR
#else
-#define SEND_STDERR(X) _dl_write(2, X, _dl_strlen(X));
+# define CONSTANT_STRING_GOT_FIXUP(X)
#endif
-#define SEND_ADDRESS_STDERR(X, add_a_newline) { \
- char tmp[22], *tmp1; \
- _dl_memset(tmp, 0, sizeof(tmp)); \
- tmp1=_dl_simple_ltoahex( tmp, (unsigned long)(X)); \
- _dl_write(2, tmp1, _dl_strlen(tmp1)); \
- if (add_a_newline) { \
- tmp[0]='\n'; \
- _dl_write(2, tmp, 1); \
- } \
-};
-
-#define SEND_NUMBER_STDERR(X, add_a_newline) { \
- char tmp[22], *tmp1; \
- _dl_memset(tmp, 0, sizeof(tmp)); \
- tmp1=_dl_simple_ltoa( tmp, (unsigned long)(X)); \
- _dl_write(2, tmp1, _dl_strlen(tmp1)); \
- if (add_a_newline) { \
- tmp[0]='\n'; \
- _dl_write(2, tmp, 1); \
- } \
-};
+#define SEND_STDERR(X) \
+{ \
+ const char *tmp1 = (X); \
+ CONSTANT_STRING_GOT_FIXUP(tmp1); \
+ _dl_write(2, tmp1, _dl_strlen(tmp1)); \
+}
+#define SEND_ADDRESS_STDERR(ADR, add_a_newline) \
+{ \
+ char tmp[26], v, *tmp2, *tmp1 = tmp; \
+ unsigned long X = (unsigned long)(ADR); \
+ CONSTANT_STRING_GOT_FIXUP(tmp1); \
+ tmp2 = tmp1 + sizeof(tmp); \
+ *--tmp2 = '\0'; \
+ if (add_a_newline) *--tmp2 = '\n'; \
+ do { \
+ v = (X) & 0xf; \
+ if (v <= 0x09) \
+ *--tmp2 = '0' + v; \
+ else \
+ *--tmp2 = 'a' - 0x0a + v; \
+ (X) >>= 4; \
+ } while ((X) > 0); \
+ *--tmp2 = 'x'; \
+ *--tmp2 = '0'; \
+ _dl_write(2, tmp2, tmp1 - tmp2 + sizeof(tmp) - 1); \
+}
+#define SEND_NUMBER_STDERR(NUM, add_a_newline) \
+{ \
+ char tmp[26], v, *tmp2, *tmp1 = tmp; \
+ unsigned long X = (unsigned long)(NUM); \
+ CONSTANT_STRING_GOT_FIXUP(tmp1); \
+ tmp2 = tmp1 + sizeof(tmp); \
+ *--tmp2 = '\0'; \
+ if (add_a_newline) *--tmp2 = '\n'; \
+ do { \
+ do_rem(v, (X), 10); \
+ *--tmp2 = '0' + v; \
+ do_div_10((X), v); \
+ } while ((X) > 0); \
+ _dl_write(2, tmp2, tmp1 - tmp2 + sizeof(tmp) - 1); \
+}
#endif
+
+/* Some targets may have to override this to something that doesn't
+ * reference constant strings through the GOT. This macro should be
+ * preferred over SEND_STDERR for constant strings before we complete
+ * bootstrap.
+ */
+#ifndef SEND_EARLY_STDERR
+# define SEND_EARLY_STDERR(S) SEND_STDERR(S)
+#else
+# define EARLY_STDERR_SPECIAL
+#endif
+
+#ifdef __SUPPORT_LD_DEBUG_EARLY__
+# define SEND_STDERR_DEBUG(X) SEND_STDERR(X)
+# define SEND_EARLY_STDERR_DEBUG(X) SEND_EARLY_STDERR(X)
+# define SEND_NUMBER_STDERR_DEBUG(X, add_a_newline) SEND_NUMBER_STDERR(X, add_a_newline)
+# define SEND_ADDRESS_STDERR_DEBUG(X, add_a_newline) SEND_ADDRESS_STDERR(X, add_a_newline)
+#else
+# define SEND_STDERR_DEBUG(X)
+# define SEND_EARLY_STDERR_DEBUG(X)
+# define SEND_NUMBER_STDERR_DEBUG(X, add_a_newline)
+# define SEND_ADDRESS_STDERR_DEBUG(X, add_a_newline)
+#endif
+
+#endif /* IS_IN_rtld */
+
+#endif /* _DL_STRING_H */