summaryrefslogtreecommitdiff
path: root/ldso/include
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2003-08-19 06:05:34 +0000
committerEric Andersen <andersen@codepoet.org>2003-08-19 06:05:34 +0000
commitbca6a155c79147f706242ed7c590a3538e407a40 (patch)
tree17c7d7784edc61f3984fb3255672f3ecfe826d22 /ldso/include
parentfd47fd4039cadf42620bbfce43c3a0338e23ee26 (diff)
Phase one of my evil plan to clean up ld.so...
Diffstat (limited to 'ldso/include')
-rw-r--r--ldso/include/.cvsignore4
-rw-r--r--ldso/include/dl-elf.h91
-rw-r--r--ldso/include/dl-hash.h118
-rw-r--r--ldso/include/dl-string.h281
-rw-r--r--ldso/include/dl-syscall.h157
-rw-r--r--ldso/include/dlfcn.h22
-rw-r--r--ldso/include/ld_elf.h91
-rw-r--r--ldso/include/ld_hash.h118
-rw-r--r--ldso/include/ld_string.h281
-rw-r--r--ldso/include/ld_syscall.h157
-rw-r--r--ldso/include/ldso.h11
11 files changed, 1331 insertions, 0 deletions
diff --git a/ldso/include/.cvsignore b/ldso/include/.cvsignore
new file mode 100644
index 000000000..b48ed1fa5
--- /dev/null
+++ b/ldso/include/.cvsignore
@@ -0,0 +1,4 @@
+elf.h
+ld_syscalls.h
+ld_sysdep.h
+boot1_arch.h
diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h
new file mode 100644
index 000000000..95de118f5
--- /dev/null
+++ b/ldso/include/dl-elf.h
@@ -0,0 +1,91 @@
+#ifndef LINUXELF_H
+#define LINUXELF_H
+
+#include <ld_sysdep.h> /* before elf.h to get ELF_USES_RELOCA right */
+#include <elf.h>
+#include <link.h>
+
+#ifdef DEBUG
+# define LDSO_CONF "../util/ld.so.conf"
+# define LDSO_CACHE "../util/ld.so.cache"
+# define LDSO_PRELOAD "../util/ld.so.preload"
+#else
+# define LDSO_CONF UCLIBC_TARGET_PREFIX "etc/ld.so.conf"
+# define LDSO_CACHE UCLIBC_TARGET_PREFIX "etc/ld.so.cache"
+# define LDSO_PRELOAD UCLIBC_TARGET_PREFIX "etc/ld.so.preload"
+#endif
+
+
+#define LIB_ANY -1
+#define LIB_DLL 0
+#define LIB_ELF 1
+#define LIB_ELF_LIBC5 2
+#define LIB_ELF_LIBC6 3
+#define LIB_ELF64 0x80
+
+/* Forward declarations for stuff defined in ld_hash.h */
+struct dyn_elf;
+struct elf_resolve;
+
+
+/* Definitions and prototypes for cache stuff */
+#ifdef USE_CACHE
+extern int _dl_map_cache(void);
+extern int _dl_unmap_cache(void);
+
+#define LDSO_CACHE_MAGIC "ld.so-"
+#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
+#define LDSO_CACHE_VER "1.7.0"
+#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
+
+typedef struct {
+ char magic [LDSO_CACHE_MAGIC_LEN];
+ char version [LDSO_CACHE_VER_LEN];
+ int nlibs;
+} header_t;
+
+typedef struct {
+ int flags;
+ int sooffset;
+ int liboffset;
+} libentry_t;
+
+#else
+static inline void _dl_map_cache(void) { }
+static inline void _dl_unmap_cache(void) { }
+#endif
+
+
+/* Function prototypes for non-static stuff in readelflib1.c */
+int _dl_copy_fixups(struct dyn_elf * tpnt);
+extern int _dl_parse_copy_information(struct dyn_elf *rpnt,
+ unsigned long rel_addr, unsigned long rel_size, int type);
+extern void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
+ unsigned long rel_addr, unsigned long rel_size, int type);
+extern int _dl_parse_relocation_information(struct elf_resolve *tpnt,
+ unsigned long rel_addr, unsigned long rel_size, int type);
+extern struct elf_resolve * _dl_load_shared_library(int secure,
+ struct dyn_elf **rpnt, struct elf_resolve *tpnt, char *full_libname);
+extern struct elf_resolve * _dl_load_elf_shared_library(int secure,
+ struct dyn_elf **rpnt, char *libname);
+extern int _dl_linux_resolve(void);
+
+
+/*
+ * Datatype of a relocation on this platform
+ */
+#ifdef ELF_USES_RELOCA
+# define ELF_RELOC ElfW(Rela)
+#else
+# define ELF_RELOC ElfW(Rel)
+#endif
+
+
+/* Convert between the Linux flags for page protections and the
+ ones specified in the ELF standard. */
+#define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \
+ (((X) & PF_W) ? PROT_WRITE : 0) | \
+ (((X) & PF_X) ? PROT_EXEC : 0))
+
+
+#endif /* LINUXELF_H */
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
new file mode 100644
index 000000000..d7ed5ab2c
--- /dev/null
+++ b/ldso/include/dl-hash.h
@@ -0,0 +1,118 @@
+#ifndef _LD_HASH_H_
+#define _LD_HASH_H_
+
+#ifndef RTLD_NEXT
+#define RTLD_NEXT ((void*)-1)
+#endif
+
+struct dyn_elf{
+ unsigned long flags;
+ struct elf_resolve * dyn;
+ struct dyn_elf * next_handle; /* Used by dlopen et al. */
+ struct dyn_elf * next;
+ struct dyn_elf * prev;
+};
+
+struct elf_resolve{
+ /* These entries must be in this order to be compatible with the interface used
+ by gdb to obtain the list of symbols. */
+ char * loadaddr;
+ char * libname;
+ unsigned long dynamic_addr;
+ struct elf_resolve * next;
+ struct elf_resolve * prev;
+ /* Nothing after this address is used by gdb. */
+ enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
+ struct dyn_elf * symbol_scope;
+ unsigned short usage_count;
+ unsigned short int init_flag;
+ unsigned int nbucket;
+ unsigned long * elf_buckets;
+ /*
+ * These are only used with ELF style shared libraries
+ */
+ unsigned long nchain;
+ unsigned long * chains;
+ unsigned long dynamic_info[24];
+
+ unsigned long dynamic_size;
+ unsigned long n_phent;
+ Elf32_Phdr * ppnt;
+
+#if defined(__mips__)
+ /* Needed for MIPS relocation */
+ unsigned long mips_gotsym;
+ unsigned long mips_local_gotno;
+ unsigned long mips_symtabno;
+#endif
+
+#ifdef __powerpc__
+ /* this is used to store the address of relocation data words, so
+ * we don't have to calculate it every time, which requires a divide */
+ unsigned long data_words;
+#endif
+};
+
+#if 0
+/*
+ * The DT_DEBUG entry in the .dynamic section is given the address of this structure.
+ * gdb can pick this up to obtain the correct list of loaded modules.
+ */
+
+struct r_debug{
+ int r_version;
+ struct elf_resolve * link_map;
+ unsigned long brk_fun;
+ enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
+ unsigned long ldbase;
+};
+#endif
+
+#define COPY_RELOCS_DONE 1
+#define RELOCS_DONE 2
+#define JMP_RELOCS_DONE 4
+#define INIT_FUNCS_CALLED 8
+
+extern struct dyn_elf * _dl_symbol_tables;
+extern struct elf_resolve * _dl_loaded_modules;
+extern struct dyn_elf * _dl_handles;
+
+extern struct elf_resolve * _dl_check_hashed_files(const char * libname);
+extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
+ char * loadaddr, unsigned long * dynamic_info,
+ unsigned long dynamic_addr, unsigned long dynamic_size);
+
+enum caller_type{symbolrel=0,copyrel=1,resolver=2};
+extern char * _dl_find_hash(const char * name, struct dyn_elf * rpnt1,
+ struct elf_resolve * f_tpnt, enum caller_type);
+
+extern int _dl_linux_dynamic_link(void);
+
+extern char * _dl_library_path;
+extern char * _dl_not_lazy;
+extern unsigned long _dl_elf_hash(const char * name);
+
+static inline int _dl_symbol(char * name)
+{
+ if(name[0] != '_' || name[1] != 'd' || name[2] != 'l' || name[3] != '_')
+ return 0;
+ return 1;
+}
+
+
+#define LD_ERROR_NOFILE 1
+#define LD_ERROR_NOZERO 2
+#define LD_ERROR_NOTELF 3
+#define LD_ERROR_NOTMAGIC 4
+#define LD_ERROR_NOTDYN 5
+#define LD_ERROR_MMAP_FAILED 6
+#define LD_ERROR_NODYNAMIC 7
+#define LD_WRONG_RELOCS 8
+#define LD_BAD_HANDLE 9
+#define LD_NO_SYMBOL 10
+
+
+
+#endif /* _LD_HASH_H_ */
+
+
diff --git a/ldso/include/dl-string.h b/ldso/include/dl-string.h
new file mode 100644
index 000000000..647ab1efd
--- /dev/null
+++ b/ldso/include/dl-string.h
@@ -0,0 +1,281 @@
+#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)
+#endif
+
+static inline size_t _dl_strlen(const char * str)
+{
+ register char *ptr = (char *) str;
+
+ while (*ptr)
+ ptr++;
+ return (ptr - str);
+}
+
+static inline char *_dl_strcat(char *dst, const char *src)
+{
+ register char *ptr = dst;
+
+ while (*ptr)
+ ptr++;
+
+ while (*src)
+ *ptr++ = *src++;
+ *ptr = '\0';
+
+ return dst;
+}
+
+static inline char * _dl_strcpy(char * dst,const char *src)
+{
+ register char *ptr = dst;
+
+ while (*src)
+ *dst++ = *src++;
+ *dst = '\0';
+
+ return ptr;
+}
+
+static inline int _dl_strcmp(const char * s1,const char * s2)
+{
+ register unsigned char c1, c2;
+
+ do {
+ c1 = (unsigned char) *s1++;
+ c2 = (unsigned char) *s2++;
+ if (c1 == '\0')
+ return 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)
+{
+ register char ch;
+
+ do {
+ if ((ch = *str) == c)
+ return (char *) str;
+ str++;
+ }
+ while (ch);
+
+ return 0;
+}
+
+static 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);
+}
+
+
+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;;
+ }
+ if (*p == *s) {
+ ++p;
+ ++s;
+ } else {
+ p = s2;
+ if (!*s) {
+ return NULL;
+ }
+ s = ++s1;
+ }
+ } while (1);
+}
+
+static inline void * _dl_memcpy(void * dst, const void * src, size_t len)
+{
+ register char *a = dst;
+ register const char *b = src;
+
+ while (len--)
+ *a++ = *b++;
+
+ return dst;
+}
+
+
+static 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;
+
+ while (len--) {
+ if (*c1 != *c2)
+ return *c1 - *c2;
+ c1++;
+ c2++;
+ }
+ return 0;
+}
+
+static inline void * _dl_memset(void * str,int c,size_t len)
+{
+ register char *a = str;
+
+ while (len--)
+ *a++ = c;
+
+ return str;
+}
+
+static inline char *_dl_get_last_path_component(char *path)
+{
+ char *s;
+ register char *ptr = path;
+ register char *prev = 0;
+
+ while (*ptr)
+ ptr++;
+ s = ptr - 1;
+
+ /* strip trailing slashes */
+ while (s != path && *s == '/') {
+ *s-- = '\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;
+}
+
+/* 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)
+{
+ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+ char *p = &local[22];
+ *p-- = '\0';
+ do {
+ *p-- = '0' + i % 10;
+ i /= 10;
+ } while (i > 0);
+ return p + 1;
+}
+
+static inline char *_dl_simple_ltoahex(char * local, unsigned long i)
+{
+ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+ char *p = &local[22];
+ *p-- = '\0';
+ do {
+ char temp = i % 0x10;
+ if (temp <= 0x09)
+ *p-- = '0' + temp;
+ else
+ *p-- = 'a' - 0x0a + temp;
+ i /= 0x10;
+ } while (i > 0);
+ *p-- = 'x';
+ *p-- = '0';
+ return p + 1;
+}
+
+
+#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)); \
+ }
+#else
+#define SEND_STDERR(X) _dl_write(2, X, _dl_strlen(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); \
+ } \
+};
+
+
+#endif
diff --git a/ldso/include/dl-syscall.h b/ldso/include/dl-syscall.h
new file mode 100644
index 000000000..72574b9a9
--- /dev/null
+++ b/ldso/include/dl-syscall.h
@@ -0,0 +1,157 @@
+#ifndef _LD_SYSCALL_H_
+#define _LD_SYSCALL_H_
+
+/* Pull in the arch specific syscall implementation */
+#include <ld_syscalls.h>
+/* For MAP_ANONYMOUS -- differs between platforms */
+#include <asm/mman.h>
+/* Pull in whatever this particular arch's kernel thinks the kernel version of
+ * struct stat should look like. It turns out that each arch has a different
+ * opinion on the subject, and different kernel revs use different names... */
+#define kernel_stat stat
+#include <bits/kernel_stat.h>
+
+
+/* Encoding of the file mode. */
+#define S_IFMT 0170000 /* These bits determine file type. */
+
+/* File types. */
+#define S_IFDIR 0040000 /* Directory. */
+#define S_IFCHR 0020000 /* Character device. */
+#define S_IFBLK 0060000 /* Block device. */
+#define S_IFREG 0100000 /* Regular file. */
+#define S_IFIFO 0010000 /* FIFO. */
+#define S_IFLNK 0120000 /* Symbolic link. */
+#define S_IFSOCK 0140000 /* Socket. */
+
+/* Protection bits. */
+
+#define S_ISUID 04000 /* Set user ID on execution. */
+#define S_ISGID 02000 /* Set group ID on execution. */
+#define S_ISVTX 01000 /* Save swapped text after use (sticky). */
+#define S_IREAD 0400 /* Read by owner. */
+#define S_IWRITE 0200 /* Write by owner. */
+#define S_IEXEC 0100 /* Execute by owner. */
+
+
+/* Here are the definitions for some syscalls that are used
+ by the dynamic linker. The idea is that we want to be able
+ to call these before the errno symbol is dynamicly linked, so
+ we use our own version here. Note that we cannot assume any
+ dynamic linking at all, so we cannot return any error codes.
+ We just punt if there is an error. */
+
+
+#define __NR__dl_exit __NR_exit
+static inline _syscall1(void, _dl_exit, int, status);
+
+
+#define __NR__dl_close __NR_close
+static inline _syscall1(int, _dl_close, int, fd);
+
+
+#if defined(__powerpc__) || defined(__mips__) || defined(__sh__)
+/* PowerPC, MIPS and SuperH have a different calling convention for mmap(). */
+#define __NR__dl_mmap __NR_mmap
+static inline _syscall6(void *, _dl_mmap, void *, start, size_t, length,
+ int, prot, int, flags, int, fd, off_t, offset);
+#else
+#define __NR__dl_mmap_real __NR_mmap
+static inline _syscall1(void *, _dl_mmap_real, unsigned long *, buffer);
+
+static inline void * _dl_mmap(void * addr, unsigned long size, int prot,
+ int flags, int fd, unsigned long offset)
+{
+ unsigned long buffer[6];
+
+ buffer[0] = (unsigned long) addr;
+ buffer[1] = (unsigned long) size;
+ buffer[2] = (unsigned long) prot;
+ buffer[3] = (unsigned long) flags;
+ buffer[4] = (unsigned long) fd;
+ buffer[5] = (unsigned long) offset;
+ return (void *) _dl_mmap_real(buffer);
+}
+#endif
+
+#ifndef _dl_MAX_ERRNO
+#define _dl_MAX_ERRNO 4096
+#endif
+#define _dl_mmap_check_error(__res) \
+ (((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
+#ifndef MAP_ANONYMOUS
+#ifdef __sparc__
+#define MAP_ANONYMOUS 0x20
+#else
+#error MAP_ANONYMOUS not defined and suplementary value not known
+#endif
+#endif
+
+
+#define __NR__dl_open __NR_open
+#define O_RDONLY 0x0000
+#define O_WRONLY 01
+#define O_RDWR 02
+#define O_CREAT 0100 /* not fcntl */
+static inline _syscall2(int, _dl_open, const char *, fn, int, flags);
+
+#define __NR__dl_write __NR_write
+static inline _syscall3(unsigned long, _dl_write, int, fd,
+ const void *, buf, unsigned long, count);
+
+
+#define __NR__dl_read __NR_read
+static inline _syscall3(unsigned long, _dl_read, int, fd,
+ const void *, buf, unsigned long, count);
+
+#define __NR__dl_mprotect __NR_mprotect
+static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, len, int, prot);
+
+
+
+#define __NR__dl_stat __NR_stat
+static inline _syscall2(int, _dl_stat, const char *, file_name, struct stat *, buf);
+
+
+#define __NR__dl_munmap __NR_munmap
+static inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length);
+
+#define __NR__dl_getuid __NR_getuid
+static inline _syscall0(uid_t, _dl_getuid);
+
+#define __NR__dl_geteuid __NR_geteuid
+static inline _syscall0(uid_t, _dl_geteuid);
+
+#define __NR__dl_getgid __NR_getgid
+static inline _syscall0(gid_t, _dl_getgid);
+
+#define __NR__dl_getegid __NR_getegid
+static inline _syscall0(gid_t, _dl_getegid);
+
+#define __NR__dl_getpid __NR_getpid
+static inline _syscall0(gid_t, _dl_getpid);
+
+/*
+ * Not an actual syscall, but we need something in assembly to say whether
+ * this is OK or not.
+ */
+static inline int _dl_suid_ok(void)
+{
+ uid_t uid, euid, gid, egid;
+
+ uid = _dl_getuid();
+ euid = _dl_geteuid();
+ gid = _dl_getgid();
+ egid = _dl_getegid();
+
+ if(uid == euid && gid == egid)
+ return 1;
+ else
+ return 0;
+}
+
+#define __NR__dl_readlink __NR_readlink
+static inline _syscall3(int, _dl_readlink, const char *, path, char *, buf, size_t, bufsiz);
+
+#endif /* _LD_SYSCALL_H_ */
+
diff --git a/ldso/include/dlfcn.h b/ldso/include/dlfcn.h
new file mode 100644
index 000000000..484558d83
--- /dev/null
+++ b/ldso/include/dlfcn.h
@@ -0,0 +1,22 @@
+/* User functions for run-time dynamic loading. libdl version */
+#ifndef _DLFCN_H
+#define _DLFCN_H 1
+
+#include <features.h>
+#include <bits/dlfcn.h>
+
+#define RTLD_NEXT ((void *) -1l)
+#define RTLD_DEFAULT ((void *) 0)
+
+/* Structure containing information about object searched using
+ `dladdr'. */
+typedef struct
+{
+ __const char *dli_fname; /* File name of defining object. */
+ void *dli_fbase; /* Load address of that object. */
+ __const char *dli_sname; /* Name of nearest symbol. */
+ void *dli_saddr; /* Exact value of nearest symbol. */
+} Dl_info;
+
+
+#endif /* dlfcn.h */
diff --git a/ldso/include/ld_elf.h b/ldso/include/ld_elf.h
new file mode 100644
index 000000000..95de118f5
--- /dev/null
+++ b/ldso/include/ld_elf.h
@@ -0,0 +1,91 @@
+#ifndef LINUXELF_H
+#define LINUXELF_H
+
+#include <ld_sysdep.h> /* before elf.h to get ELF_USES_RELOCA right */
+#include <elf.h>
+#include <link.h>
+
+#ifdef DEBUG
+# define LDSO_CONF "../util/ld.so.conf"
+# define LDSO_CACHE "../util/ld.so.cache"
+# define LDSO_PRELOAD "../util/ld.so.preload"
+#else
+# define LDSO_CONF UCLIBC_TARGET_PREFIX "etc/ld.so.conf"
+# define LDSO_CACHE UCLIBC_TARGET_PREFIX "etc/ld.so.cache"
+# define LDSO_PRELOAD UCLIBC_TARGET_PREFIX "etc/ld.so.preload"
+#endif
+
+
+#define LIB_ANY -1
+#define LIB_DLL 0
+#define LIB_ELF 1
+#define LIB_ELF_LIBC5 2
+#define LIB_ELF_LIBC6 3
+#define LIB_ELF64 0x80
+
+/* Forward declarations for stuff defined in ld_hash.h */
+struct dyn_elf;
+struct elf_resolve;
+
+
+/* Definitions and prototypes for cache stuff */
+#ifdef USE_CACHE
+extern int _dl_map_cache(void);
+extern int _dl_unmap_cache(void);
+
+#define LDSO_CACHE_MAGIC "ld.so-"
+#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
+#define LDSO_CACHE_VER "1.7.0"
+#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
+
+typedef struct {
+ char magic [LDSO_CACHE_MAGIC_LEN];
+ char version [LDSO_CACHE_VER_LEN];
+ int nlibs;
+} header_t;
+
+typedef struct {
+ int flags;
+ int sooffset;
+ int liboffset;
+} libentry_t;
+
+#else
+static inline void _dl_map_cache(void) { }
+static inline void _dl_unmap_cache(void) { }
+#endif
+
+
+/* Function prototypes for non-static stuff in readelflib1.c */
+int _dl_copy_fixups(struct dyn_elf * tpnt);
+extern int _dl_parse_copy_information(struct dyn_elf *rpnt,
+ unsigned long rel_addr, unsigned long rel_size, int type);
+extern void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
+ unsigned long rel_addr, unsigned long rel_size, int type);
+extern int _dl_parse_relocation_information(struct elf_resolve *tpnt,
+ unsigned long rel_addr, unsigned long rel_size, int type);
+extern struct elf_resolve * _dl_load_shared_library(int secure,
+ struct dyn_elf **rpnt, struct elf_resolve *tpnt, char *full_libname);
+extern struct elf_resolve * _dl_load_elf_shared_library(int secure,
+ struct dyn_elf **rpnt, char *libname);
+extern int _dl_linux_resolve(void);
+
+
+/*
+ * Datatype of a relocation on this platform
+ */
+#ifdef ELF_USES_RELOCA
+# define ELF_RELOC ElfW(Rela)
+#else
+# define ELF_RELOC ElfW(Rel)
+#endif
+
+
+/* Convert between the Linux flags for page protections and the
+ ones specified in the ELF standard. */
+#define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \
+ (((X) & PF_W) ? PROT_WRITE : 0) | \
+ (((X) & PF_X) ? PROT_EXEC : 0))
+
+
+#endif /* LINUXELF_H */
diff --git a/ldso/include/ld_hash.h b/ldso/include/ld_hash.h
new file mode 100644
index 000000000..d7ed5ab2c
--- /dev/null
+++ b/ldso/include/ld_hash.h
@@ -0,0 +1,118 @@
+#ifndef _LD_HASH_H_
+#define _LD_HASH_H_
+
+#ifndef RTLD_NEXT
+#define RTLD_NEXT ((void*)-1)
+#endif
+
+struct dyn_elf{
+ unsigned long flags;
+ struct elf_resolve * dyn;
+ struct dyn_elf * next_handle; /* Used by dlopen et al. */
+ struct dyn_elf * next;
+ struct dyn_elf * prev;
+};
+
+struct elf_resolve{
+ /* These entries must be in this order to be compatible with the interface used
+ by gdb to obtain the list of symbols. */
+ char * loadaddr;
+ char * libname;
+ unsigned long dynamic_addr;
+ struct elf_resolve * next;
+ struct elf_resolve * prev;
+ /* Nothing after this address is used by gdb. */
+ enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
+ struct dyn_elf * symbol_scope;
+ unsigned short usage_count;
+ unsigned short int init_flag;
+ unsigned int nbucket;
+ unsigned long * elf_buckets;
+ /*
+ * These are only used with ELF style shared libraries
+ */
+ unsigned long nchain;
+ unsigned long * chains;
+ unsigned long dynamic_info[24];
+
+ unsigned long dynamic_size;
+ unsigned long n_phent;
+ Elf32_Phdr * ppnt;
+
+#if defined(__mips__)
+ /* Needed for MIPS relocation */
+ unsigned long mips_gotsym;
+ unsigned long mips_local_gotno;
+ unsigned long mips_symtabno;
+#endif
+
+#ifdef __powerpc__
+ /* this is used to store the address of relocation data words, so
+ * we don't have to calculate it every time, which requires a divide */
+ unsigned long data_words;
+#endif
+};
+
+#if 0
+/*
+ * The DT_DEBUG entry in the .dynamic section is given the address of this structure.
+ * gdb can pick this up to obtain the correct list of loaded modules.
+ */
+
+struct r_debug{
+ int r_version;
+ struct elf_resolve * link_map;
+ unsigned long brk_fun;
+ enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
+ unsigned long ldbase;
+};
+#endif
+
+#define COPY_RELOCS_DONE 1
+#define RELOCS_DONE 2
+#define JMP_RELOCS_DONE 4
+#define INIT_FUNCS_CALLED 8
+
+extern struct dyn_elf * _dl_symbol_tables;
+extern struct elf_resolve * _dl_loaded_modules;
+extern struct dyn_elf * _dl_handles;
+
+extern struct elf_resolve * _dl_check_hashed_files(const char * libname);
+extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
+ char * loadaddr, unsigned long * dynamic_info,
+ unsigned long dynamic_addr, unsigned long dynamic_size);
+
+enum caller_type{symbolrel=0,copyrel=1,resolver=2};
+extern char * _dl_find_hash(const char * name, struct dyn_elf * rpnt1,
+ struct elf_resolve * f_tpnt, enum caller_type);
+
+extern int _dl_linux_dynamic_link(void);
+
+extern char * _dl_library_path;
+extern char * _dl_not_lazy;
+extern unsigned long _dl_elf_hash(const char * name);
+
+static inline int _dl_symbol(char * name)
+{
+ if(name[0] != '_' || name[1] != 'd' || name[2] != 'l' || name[3] != '_')
+ return 0;
+ return 1;
+}
+
+
+#define LD_ERROR_NOFILE 1
+#define LD_ERROR_NOZERO 2
+#define LD_ERROR_NOTELF 3
+#define LD_ERROR_NOTMAGIC 4
+#define LD_ERROR_NOTDYN 5
+#define LD_ERROR_MMAP_FAILED 6
+#define LD_ERROR_NODYNAMIC 7
+#define LD_WRONG_RELOCS 8
+#define LD_BAD_HANDLE 9
+#define LD_NO_SYMBOL 10
+
+
+
+#endif /* _LD_HASH_H_ */
+
+
diff --git a/ldso/include/ld_string.h b/ldso/include/ld_string.h
new file mode 100644
index 000000000..647ab1efd
--- /dev/null
+++ b/ldso/include/ld_string.h
@@ -0,0 +1,281 @@
+#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)
+#endif
+
+static inline size_t _dl_strlen(const char * str)
+{
+ register char *ptr = (char *) str;
+
+ while (*ptr)
+ ptr++;
+ return (ptr - str);
+}
+
+static inline char *_dl_strcat(char *dst, const char *src)
+{
+ register char *ptr = dst;
+
+ while (*ptr)
+ ptr++;
+
+ while (*src)
+ *ptr++ = *src++;
+ *ptr = '\0';
+
+ return dst;
+}
+
+static inline char * _dl_strcpy(char * dst,const char *src)
+{
+ register char *ptr = dst;
+
+ while (*src)
+ *dst++ = *src++;
+ *dst = '\0';
+
+ return ptr;
+}
+
+static inline int _dl_strcmp(const char * s1,const char * s2)
+{
+ register unsigned char c1, c2;
+
+ do {
+ c1 = (unsigned char) *s1++;
+ c2 = (unsigned char) *s2++;
+ if (c1 == '\0')
+ return 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)
+{
+ register char ch;
+
+ do {
+ if ((ch = *str) == c)
+ return (char *) str;
+ str++;
+ }
+ while (ch);
+
+ return 0;
+}
+
+static 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);
+}
+
+
+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;;
+ }
+ if (*p == *s) {
+ ++p;
+ ++s;
+ } else {
+ p = s2;
+ if (!*s) {
+ return NULL;
+ }
+ s = ++s1;
+ }
+ } while (1);
+}
+
+static inline void * _dl_memcpy(void * dst, const void * src, size_t len)
+{
+ register char *a = dst;
+ register const char *b = src;
+
+ while (len--)
+ *a++ = *b++;
+
+ return dst;
+}
+
+
+static 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;
+
+ while (len--) {
+ if (*c1 != *c2)
+ return *c1 - *c2;
+ c1++;
+ c2++;
+ }
+ return 0;
+}
+
+static inline void * _dl_memset(void * str,int c,size_t len)
+{
+ register char *a = str;
+
+ while (len--)
+ *a++ = c;
+
+ return str;
+}
+
+static inline char *_dl_get_last_path_component(char *path)
+{
+ char *s;
+ register char *ptr = path;
+ register char *prev = 0;
+
+ while (*ptr)
+ ptr++;
+ s = ptr - 1;
+
+ /* strip trailing slashes */
+ while (s != path && *s == '/') {
+ *s-- = '\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;
+}
+
+/* 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)
+{
+ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+ char *p = &local[22];
+ *p-- = '\0';
+ do {
+ *p-- = '0' + i % 10;
+ i /= 10;
+ } while (i > 0);
+ return p + 1;
+}
+
+static inline char *_dl_simple_ltoahex(char * local, unsigned long i)
+{
+ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+ char *p = &local[22];
+ *p-- = '\0';
+ do {
+ char temp = i % 0x10;
+ if (temp <= 0x09)
+ *p-- = '0' + temp;
+ else
+ *p-- = 'a' - 0x0a + temp;
+ i /= 0x10;
+ } while (i > 0);
+ *p-- = 'x';
+ *p-- = '0';
+ return p + 1;
+}
+
+
+#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)); \
+ }
+#else
+#define SEND_STDERR(X) _dl_write(2, X, _dl_strlen(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); \
+ } \
+};
+
+
+#endif
diff --git a/ldso/include/ld_syscall.h b/ldso/include/ld_syscall.h
new file mode 100644
index 000000000..72574b9a9
--- /dev/null
+++ b/ldso/include/ld_syscall.h
@@ -0,0 +1,157 @@
+#ifndef _LD_SYSCALL_H_
+#define _LD_SYSCALL_H_
+
+/* Pull in the arch specific syscall implementation */
+#include <ld_syscalls.h>
+/* For MAP_ANONYMOUS -- differs between platforms */
+#include <asm/mman.h>
+/* Pull in whatever this particular arch's kernel thinks the kernel version of
+ * struct stat should look like. It turns out that each arch has a different
+ * opinion on the subject, and different kernel revs use different names... */
+#define kernel_stat stat
+#include <bits/kernel_stat.h>
+
+
+/* Encoding of the file mode. */
+#define S_IFMT 0170000 /* These bits determine file type. */
+
+/* File types. */
+#define S_IFDIR 0040000 /* Directory. */
+#define S_IFCHR 0020000 /* Character device. */
+#define S_IFBLK 0060000 /* Block device. */
+#define S_IFREG 0100000 /* Regular file. */
+#define S_IFIFO 0010000 /* FIFO. */
+#define S_IFLNK 0120000 /* Symbolic link. */
+#define S_IFSOCK 0140000 /* Socket. */
+
+/* Protection bits. */
+
+#define S_ISUID 04000 /* Set user ID on execution. */
+#define S_ISGID 02000 /* Set group ID on execution. */
+#define S_ISVTX 01000 /* Save swapped text after use (sticky). */
+#define S_IREAD 0400 /* Read by owner. */
+#define S_IWRITE 0200 /* Write by owner. */
+#define S_IEXEC 0100 /* Execute by owner. */
+
+
+/* Here are the definitions for some syscalls that are used
+ by the dynamic linker. The idea is that we want to be able
+ to call these before the errno symbol is dynamicly linked, so
+ we use our own version here. Note that we cannot assume any
+ dynamic linking at all, so we cannot return any error codes.
+ We just punt if there is an error. */
+
+
+#define __NR__dl_exit __NR_exit
+static inline _syscall1(void, _dl_exit, int, status);
+
+
+#define __NR__dl_close __NR_close
+static inline _syscall1(int, _dl_close, int, fd);
+
+
+#if defined(__powerpc__) || defined(__mips__) || defined(__sh__)
+/* PowerPC, MIPS and SuperH have a different calling convention for mmap(). */
+#define __NR__dl_mmap __NR_mmap
+static inline _syscall6(void *, _dl_mmap, void *, start, size_t, length,
+ int, prot, int, flags, int, fd, off_t, offset);
+#else
+#define __NR__dl_mmap_real __NR_mmap
+static inline _syscall1(void *, _dl_mmap_real, unsigned long *, buffer);
+
+static inline void * _dl_mmap(void * addr, unsigned long size, int prot,
+ int flags, int fd, unsigned long offset)
+{
+ unsigned long buffer[6];
+
+ buffer[0] = (unsigned long) addr;
+ buffer[1] = (unsigned long) size;
+ buffer[2] = (unsigned long) prot;
+ buffer[3] = (unsigned long) flags;
+ buffer[4] = (unsigned long) fd;
+ buffer[5] = (unsigned long) offset;
+ return (void *) _dl_mmap_real(buffer);
+}
+#endif
+
+#ifndef _dl_MAX_ERRNO
+#define _dl_MAX_ERRNO 4096
+#endif
+#define _dl_mmap_check_error(__res) \
+ (((int)__res) < 0 && ((int)__res) >= -_dl_MAX_ERRNO)
+#ifndef MAP_ANONYMOUS
+#ifdef __sparc__
+#define MAP_ANONYMOUS 0x20
+#else
+#error MAP_ANONYMOUS not defined and suplementary value not known
+#endif
+#endif
+
+
+#define __NR__dl_open __NR_open
+#define O_RDONLY 0x0000
+#define O_WRONLY 01
+#define O_RDWR 02
+#define O_CREAT 0100 /* not fcntl */
+static inline _syscall2(int, _dl_open, const char *, fn, int, flags);
+
+#define __NR__dl_write __NR_write
+static inline _syscall3(unsigned long, _dl_write, int, fd,
+ const void *, buf, unsigned long, count);
+
+
+#define __NR__dl_read __NR_read
+static inline _syscall3(unsigned long, _dl_read, int, fd,
+ const void *, buf, unsigned long, count);
+
+#define __NR__dl_mprotect __NR_mprotect
+static inline _syscall3(int, _dl_mprotect, const void *, addr, unsigned long, len, int, prot);
+
+
+
+#define __NR__dl_stat __NR_stat
+static inline _syscall2(int, _dl_stat, const char *, file_name, struct stat *, buf);
+
+
+#define __NR__dl_munmap __NR_munmap
+static inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length);
+
+#define __NR__dl_getuid __NR_getuid
+static inline _syscall0(uid_t, _dl_getuid);
+
+#define __NR__dl_geteuid __NR_geteuid
+static inline _syscall0(uid_t, _dl_geteuid);
+
+#define __NR__dl_getgid __NR_getgid
+static inline _syscall0(gid_t, _dl_getgid);
+
+#define __NR__dl_getegid __NR_getegid
+static inline _syscall0(gid_t, _dl_getegid);
+
+#define __NR__dl_getpid __NR_getpid
+static inline _syscall0(gid_t, _dl_getpid);
+
+/*
+ * Not an actual syscall, but we need something in assembly to say whether
+ * this is OK or not.
+ */
+static inline int _dl_suid_ok(void)
+{
+ uid_t uid, euid, gid, egid;
+
+ uid = _dl_getuid();
+ euid = _dl_geteuid();
+ gid = _dl_getgid();
+ egid = _dl_getegid();
+
+ if(uid == euid && gid == egid)
+ return 1;
+ else
+ return 0;
+}
+
+#define __NR__dl_readlink __NR_readlink
+static inline _syscall3(int, _dl_readlink, const char *, path, char *, buf, size_t, bufsiz);
+
+#endif /* _LD_SYSCALL_H_ */
+
diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h
new file mode 100644
index 000000000..b5ccbfaef
--- /dev/null
+++ b/ldso/include/ldso.h
@@ -0,0 +1,11 @@
+#include <features.h>
+/* Pull in compiler and arch stuff */
+#include <stdlib.h>
+#include <stdarg.h>
+/* Pull in the arch specific type information */
+#include <sys/types.h>
+/* Now the ldso specific headers */
+#include <ld_elf.h>
+#include <ld_syscall.h>
+#include <ld_hash.h>
+#include <ld_string.h>