diff options
Diffstat (limited to 'ldso/include')
-rw-r--r-- | ldso/include/.cvsignore | 4 | ||||
-rw-r--r-- | ldso/include/dl-elf.h | 91 | ||||
-rw-r--r-- | ldso/include/dl-hash.h | 118 | ||||
-rw-r--r-- | ldso/include/dl-string.h | 281 | ||||
-rw-r--r-- | ldso/include/dl-syscall.h | 157 | ||||
-rw-r--r-- | ldso/include/dlfcn.h | 22 | ||||
-rw-r--r-- | ldso/include/ld_elf.h | 91 | ||||
-rw-r--r-- | ldso/include/ld_hash.h | 118 | ||||
-rw-r--r-- | ldso/include/ld_string.h | 281 | ||||
-rw-r--r-- | ldso/include/ld_syscall.h | 157 | ||||
-rw-r--r-- | ldso/include/ldso.h | 11 |
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> |