summaryrefslogtreecommitdiff
path: root/ldso/include
diff options
context:
space:
mode:
Diffstat (limited to 'ldso/include')
-rw-r--r--ldso/include/dl-defs.h49
-rw-r--r--ldso/include/dl-elf.h118
-rw-r--r--ldso/include/dl-hash.h102
-rw-r--r--ldso/include/dl-string.h95
-rw-r--r--ldso/include/dl-syscall.h211
-rw-r--r--ldso/include/dlfcn.h4
-rw-r--r--ldso/include/inline-hashtab.h265
-rw-r--r--ldso/include/ldso.h77
-rw-r--r--ldso/include/ldsodefs.h154
-rw-r--r--ldso/include/tlsdeschtab.h121
10 files changed, 966 insertions, 230 deletions
diff --git a/ldso/include/dl-defs.h b/ldso/include/dl-defs.h
index 791d068bb..bedfa977e 100644
--- a/ldso/include/dl-defs.h
+++ b/ldso/include/dl-defs.h
@@ -5,8 +5,8 @@
* GNU Lesser General Public License version 2.1 or later.
*/
-#ifndef _LD_DEFS_H
-#define _LD_DEFS_H
+#ifndef _DL_DEFS_H
+#define _DL_DEFS_H
#define FLAG_ANY -1
#define FLAG_TYPE_MASK 0x00ff
@@ -72,6 +72,13 @@ typedef struct {
#endif
+#ifdef _LIBC
+#ifndef __ARCH_HAS_NO_SHARED__
+/* arch specific defines */
+#include <dl-sysdep.h>
+#endif
+#endif
+
/* Provide a means for a port to pass additional arguments to the _dl_start
function. */
#ifndef DL_START
@@ -99,7 +106,7 @@ typedef struct {
* from DL_START, so additional arguments passed to it may be referenced. */
#ifndef DL_BOOT_COMPUTE_DYN
#define DL_BOOT_COMPUTE_DYN(DPNT, GOT, LOAD_ADDR) \
- ((DPNT) = ((ElfW(Dyn) *) DL_RELOC_ADDR(load_addr, got)))
+ ((DPNT) = ((ElfW(Dyn) *) DL_RELOC_ADDR(LOAD_ADDR, GOT)))
#endif
/* Initialize the location of the global offset table. This is only called
@@ -179,6 +186,14 @@ typedef struct {
#define DL_LOOKUP_ADDRESS(ADDRESS) (ADDRESS)
#endif
+/* On some architectures dladdr can't use st_size of all symbols this way. */
+#define DL_ADDR_SYM_MATCH(SYM_ADDR, SYM, MATCHSYM, ADDR) \
+ ((ADDR) >= (SYM_ADDR) \
+ && ((((SYM)->st_shndx == SHN_UNDEF || (SYM)->st_size == 0) \
+ && (ADDR) == (SYM_ADDR)) \
+ || (ADDR) < (SYM_ADDR) + (SYM)->st_size) \
+ && (!(MATCHSYM) || MATCHSYM < (SYM_ADDR)))
+
/* Use this macro to convert a pointer to a function's entry point to
* a pointer to function. The pointer is assumed to have already been
* relocated. LOADADDR is passed because it may contain additional
@@ -212,7 +227,7 @@ typedef struct {
_dl_find_hash for this reloc TYPE. TPNT is the module in which the
matching SYM was found. */
#ifndef DL_FIND_HASH_VALUE
-# define DL_FIND_HASH_VALUE(TPNT, TYPE, SYM) (DL_RELOC_ADDR ((SYM)->st_value, (TPNT)->loadaddr))
+# define DL_FIND_HASH_VALUE(TPNT, TYPE, SYM) (DL_RELOC_ADDR ((TPNT)->loadaddr, (SYM)->st_value))
#endif
/* Unmap all previously-mapped segments accumulated in LOADADDR.
@@ -225,7 +240,7 @@ typedef struct {
/* Similar to DL_LOADADDR_UNMAP, but used for libraries that have been
dlopen()ed successfully, when they're dlclose()d. */
#ifndef DL_LIB_UNMAP
-# define DL_LIB_UNMAP(LIB, LEN) (DL_LOADADDR_UNMAP ((LIB)->loadaddr, (LEN)))
+# define DL_LIB_UNMAP(LIB, LEN) (DL_LOADADDR_UNMAP ((LIB)->mapaddr, (LEN)))
#endif
/* Define this to verify that a library named LIBNAME, whose ELF
@@ -251,4 +266,26 @@ typedef struct {
# define DL_MAP_SEGMENT(EPNT, PPNT, INFILE, FLAGS) 0
#endif
-#endif /* _LD_DEFS_H */
+/* Define this to declare the library offset. */
+#ifndef DL_DEF_LIB_OFFSET
+# define DL_DEF_LIB_OFFSET static unsigned long _dl_library_offset
+#endif
+
+/* Define this to get the library offset. */
+#ifndef DL_GET_LIB_OFFSET
+# define DL_GET_LIB_OFFSET() _dl_library_offset
+#endif
+
+/* Define this to set the library offset as difference beetwen the mapped
+ library address and the smallest virtual address of the first PT_LOAD
+ segment. */
+#ifndef DL_SET_LIB_OFFSET
+# define DL_SET_LIB_OFFSET(offset) (_dl_library_offset = (offset))
+#endif
+
+/* Define this to get the real object's runtime address. */
+#ifndef DL_GET_RUN_ADDR
+# define DL_GET_RUN_ADDR(loadaddr, mapaddr) (mapaddr)
+#endif
+
+#endif /* _DL_DEFS_H */
diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h
index 076678cfc..80625fd5b 100644
--- a/ldso/include/dl-elf.h
+++ b/ldso/include/dl-elf.h
@@ -5,18 +5,22 @@
* GNU Lesser General Public License version 2.1 or later.
*/
-#ifndef LINUXELF_H
-#define LINUXELF_H
+#ifndef _DL_ELF_H
+#define _DL_ELF_H
+#include <features.h>
+#include <bits/wordsize.h>
#include <dl-string.h> /* before elf.h to get ELF_USES_RELOCA right */
#include <elf.h>
#include <link.h>
+#include <dl-defs.h>
+#include <dlfcn.h>
-/* Forward declarations for stuff defined in ld_hash.h */
+/* Forward declarations for stuff defined in dl-hash.h */
struct dyn_elf;
struct elf_resolve;
+struct r_scope_elem;
-#include <dl-defs.h>
#ifdef __LDSO_CACHE_SUPPORT__
extern int _dl_map_cache(void);
extern int _dl_unmap_cache(void);
@@ -25,21 +29,18 @@ static __inline__ void _dl_map_cache(void) { }
static __inline__ void _dl_unmap_cache(void) { }
#endif
-
-/* Function prototypes for non-static stuff in readelflib1.c */
+/* Function prototypes for non-static stuff in elfinterp.c */
extern void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
unsigned long rel_addr, unsigned long rel_size);
extern int _dl_parse_relocation_information(struct dyn_elf *rpnt,
- unsigned long rel_addr, unsigned long rel_size);
-extern struct elf_resolve * _dl_load_shared_library(int secure,
+ struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size);
+extern struct elf_resolve * _dl_load_shared_library(unsigned int rflags,
struct dyn_elf **rpnt, struct elf_resolve *tpnt, char *full_libname,
int trace_loaded_objects);
-extern struct elf_resolve * _dl_load_elf_shared_library(int secure,
- struct dyn_elf **rpnt, char *libname);
-extern struct elf_resolve *_dl_check_if_named_library_is_loaded(const char *full_libname,
- int trace_loaded_objects);
+extern struct elf_resolve * _dl_load_elf_shared_library(unsigned int rflags,
+ struct dyn_elf **rpnt, const char *libname);
extern int _dl_linux_resolve(void);
-extern int _dl_fixup(struct dyn_elf *rpnt, int flag);
+extern int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int flag);
extern void _dl_protect_relro (struct elf_resolve *l);
/*
@@ -84,33 +85,58 @@ extern void _dl_protect_relro (struct elf_resolve *l);
#endif
/* OS and/or GNU dynamic extensions */
+
+#define OS_NUM_BASE 1 /* for DT_RELOCCOUNT */
+
#ifdef __LDSO_GNU_HASH_SUPPORT__
-# define OS_NUM 2 /* for DT_RELOCCOUNT and DT_GNU_HASH entries */
+# define OS_NUM_GNU_HASH 1 /* for DT_GNU_HASH entry */
+#else
+# define OS_NUM_GNU_HASH 0
+#endif
+
+#ifdef __LDSO_PRELINK_SUPPORT__
+# define OS_NUM_PRELINK 6 /* for DT_GNU_PRELINKED entry */
#else
-# define OS_NUM 1 /* for DT_RELOCCOUNT entry */
+# define OS_NUM_PRELINK 0
#endif
+#define OS_NUM (OS_NUM_BASE + OS_NUM_GNU_HASH + OS_NUM_PRELINK)
+
#ifndef ARCH_DYNAMIC_INFO
/* define in arch specific code, if needed */
# define ARCH_NUM 0
#endif
-#define DYNAMIC_SIZE (DT_NUM+OS_NUM+ARCH_NUM)
+#define DYNAMIC_SIZE (DT_NUM + OS_NUM + ARCH_NUM)
/* Keep ARCH specific entries into dynamic section at the end of the array */
#define DT_RELCONT_IDX (DYNAMIC_SIZE - OS_NUM - ARCH_NUM)
#ifdef __LDSO_GNU_HASH_SUPPORT__
/* GNU hash comes just after the relocation count */
# define DT_GNU_HASH_IDX (DT_RELCONT_IDX + 1)
+#else
+# define DT_GNU_HASH_IDX DT_RELCONT_IDX
#endif
-extern void _dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[],
- void *debug_addr, DL_LOADADDR_TYPE load_off);
+#ifdef __LDSO_PRELINK_SUPPORT__
+/* GNU prelink comes just after the GNU hash if present */
+#define DT_GNU_PRELINKED_IDX (DT_GNU_HASH_IDX + 1)
+#define DT_GNU_CONFLICT_IDX (DT_GNU_HASH_IDX + 2)
+#define DT_GNU_CONFLICTSZ_IDX (DT_GNU_HASH_IDX + 3)
+#define DT_GNU_LIBLIST_IDX (DT_GNU_HASH_IDX + 4)
+#define DT_GNU_LIBLISTSZ_IDX (DT_GNU_HASH_IDX + 5)
+#define DT_CHECKSUM_IDX (DT_GNU_HASH_IDX + 6)
+#endif
+
+extern unsigned int _dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[],
+ void *debug_addr, DL_LOADADDR_TYPE load_off);
static __always_inline
-void __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[],
- void *debug_addr, DL_LOADADDR_TYPE load_off)
+unsigned int __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[],
+ void *debug_addr, DL_LOADADDR_TYPE load_off)
{
+ unsigned int rtld_flags = 0;
+
for (; dpnt->d_tag; dpnt++) {
if (dpnt->d_tag < DT_NUM) {
dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
@@ -138,13 +164,30 @@ void __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[],
} else if (dpnt->d_tag < DT_LOPROC) {
if (dpnt->d_tag == DT_RELOCCOUNT)
dynamic_info[DT_RELCONT_IDX] = dpnt->d_un.d_val;
- if (dpnt->d_tag == DT_FLAGS_1 &&
- (dpnt->d_un.d_val & DF_1_NOW))
- dynamic_info[DT_BIND_NOW] = 1;
+ if (dpnt->d_tag == DT_FLAGS_1) {
+ if (dpnt->d_un.d_val & DF_1_NOW)
+ dynamic_info[DT_BIND_NOW] = 1;
+ if (dpnt->d_un.d_val & DF_1_NODELETE)
+ rtld_flags |= RTLD_NODELETE;
+ }
#ifdef __LDSO_GNU_HASH_SUPPORT__
if (dpnt->d_tag == DT_GNU_HASH)
dynamic_info[DT_GNU_HASH_IDX] = dpnt->d_un.d_ptr;
#endif
+#ifdef __LDSO_PRELINK_SUPPORT__
+ if (dpnt->d_tag == DT_GNU_PRELINKED)
+ dynamic_info[DT_GNU_PRELINKED_IDX] = dpnt->d_un.d_val;
+ if (dpnt->d_tag == DT_GNU_CONFLICT)
+ dynamic_info[DT_GNU_CONFLICT_IDX] = dpnt->d_un.d_ptr;
+ if (dpnt->d_tag == DT_GNU_CONFLICTSZ)
+ dynamic_info[DT_GNU_CONFLICTSZ_IDX] = dpnt->d_un.d_val;
+ if (dpnt->d_tag == DT_GNU_LIBLIST)
+ dynamic_info[DT_GNU_LIBLIST_IDX] = dpnt->d_un.d_ptr;
+ if (dpnt->d_tag == DT_GNU_LIBLISTSZ)
+ dynamic_info[DT_GNU_LIBLISTSZ_IDX] = dpnt->d_un.d_val;
+ if (dpnt->d_tag == DT_CHECKSUM)
+ dynamic_info[DT_CHECKSUM_IDX] = dpnt->d_un.d_val;
+#endif
}
#ifdef ARCH_DYNAMIC_INFO
else {
@@ -157,16 +200,29 @@ void __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[],
if (dynamic_info[tag]) \
dynamic_info[tag] = (unsigned long) DL_RELOC_ADDR(load_off, dynamic_info[tag]); \
} while (0)
- ADJUST_DYN_INFO(DT_HASH, load_off);
- ADJUST_DYN_INFO(DT_PLTGOT, load_off);
- ADJUST_DYN_INFO(DT_STRTAB, load_off);
- ADJUST_DYN_INFO(DT_SYMTAB, load_off);
- ADJUST_DYN_INFO(DT_RELOC_TABLE_ADDR, load_off);
- ADJUST_DYN_INFO(DT_JMPREL, load_off);
+ /* Don't adjust .dynamic unnecessarily. For FDPIC targets,
+ we'd have to walk all the loadsegs to find out if it was
+ actually unnecessary, so skip this optimization. */
+#if !defined __FRV_FDPIC__ && !defined __BFIN_FDPIC__ && !defined __DSBT__
+ if (load_off != 0)
+#endif
+ {
+ ADJUST_DYN_INFO(DT_HASH, load_off);
+ ADJUST_DYN_INFO(DT_PLTGOT, load_off);
+ ADJUST_DYN_INFO(DT_STRTAB, load_off);
+ ADJUST_DYN_INFO(DT_SYMTAB, load_off);
+ ADJUST_DYN_INFO(DT_RELOC_TABLE_ADDR, load_off);
+ ADJUST_DYN_INFO(DT_JMPREL, load_off);
#ifdef __LDSO_GNU_HASH_SUPPORT__
- ADJUST_DYN_INFO(DT_GNU_HASH_IDX, load_off);
+ ADJUST_DYN_INFO(DT_GNU_HASH_IDX, load_off);
+#endif
+ }
+#ifdef __DSBT__
+ /* Get the mapped address of the DSBT base. */
+ ADJUST_DYN_INFO(DT_DSBT_BASE_IDX, load_off);
#endif
#undef ADJUST_DYN_INFO
+ return rtld_flags;
}
/* Reloc type classes as returned by elf_machine_type_class().
@@ -196,4 +252,4 @@ void __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[],
(((X) & PF_X) ? PROT_EXEC : 0))
-#endif /* LINUXELF_H */
+#endif /* _DL_ELF_H */
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
index 9b87783fa..d6282bb0c 100644
--- a/ldso/include/dl-hash.h
+++ b/ldso/include/dl-hash.h
@@ -5,8 +5,8 @@
* GNU Lesser General Public License version 2.1 or later.
*/
-#ifndef _LD_HASH_H_
-#define _LD_HASH_H_
+#ifndef _DL_HASH_H
+#define _DL_HASH_H
#ifndef RTLD_NEXT
#define RTLD_NEXT ((void*)-1)
@@ -25,6 +25,19 @@ struct dyn_elf {
struct dyn_elf * prev;
};
+struct symbol_ref {
+ const ElfW(Sym) *sym;
+ struct elf_resolve *tpnt;
+};
+
+/* Structure to describe a single list of scope elements. The lookup
+ functions get passed an array of pointers to such structures. */
+struct r_scope_elem {
+ struct elf_resolve **r_list; /* Array of maps for the scope. */
+ unsigned int r_nlist; /* Number of entries in the scope. */
+ struct r_scope_elem *next;
+};
+
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. */
@@ -34,9 +47,41 @@ struct elf_resolve {
struct elf_resolve * next;
struct elf_resolve * prev;
/* Nothing after this address is used by gdb. */
- ElfW(Addr) mapaddr; /* Address at which ELF segments (either main app and DSO) are mapped into */
+
+#if defined(USE_TLS) && USE_TLS
+ /* Thread-local storage related info. */
+
+ /* Start of the initialization image. */
+ void *l_tls_initimage;
+ /* Size of the initialization image. */
+ size_t l_tls_initimage_size;
+ /* Size of the TLS block. */
+ size_t l_tls_blocksize;
+ /* Alignment requirement of the TLS block. */
+ size_t l_tls_align;
+ /* Offset of first byte module alignment. */
+ size_t l_tls_firstbyte_offset;
+# ifndef NO_TLS_OFFSET
+# define NO_TLS_OFFSET 0
+# endif
+ /* For objects present at startup time: offset in the static TLS block. */
+ ptrdiff_t l_tls_offset;
+ /* Index of the module in the dtv array. */
+ size_t l_tls_modid;
+ /* Nonzero if _dl_init_static_tls should be called for this module */
+ unsigned int l_need_tls_init:1;
+ /* Address of TLS descriptor hash table. */
+ void *l_tlsdesc_table;
+#endif
+
+ ElfW(Addr) mapaddr;
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ /* Store the entry point from the ELF header (e_entry) */
+ ElfW(Addr) l_entry;
+#endif
enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
- struct dyn_elf * symbol_scope;
+ /* This is the local scope of the shared object */
+ struct r_scope_elem symbol_scope;
unsigned short usage_count;
unsigned short int init_flag;
unsigned long rtld_flags; /* RTLD_GLOBAL, RTLD_NOW etc. */
@@ -90,12 +135,18 @@ struct elf_resolve {
unsigned long data_words;
#endif
-#ifdef __FDPIC__
+#if defined(__FRV_FDPIC__) || defined(__BFIN_FDPIC__)
/* Every loaded module holds a hashtable of function descriptors of
functions defined in it, such that it's easy to release the
memory when the module is dlclose()d. */
struct funcdesc_ht *funcdesc_ht;
#endif
+#ifdef __DSBT__
+ /* Information for DSBT */
+ void **dsbt_table;
+ unsigned long dsbt_size;
+ unsigned long dsbt_index;
+#endif
};
#define RELOCS_DONE 0x000001
@@ -103,43 +154,21 @@ struct elf_resolve {
#define INIT_FUNCS_CALLED 0x000004
#define FINI_FUNCS_CALLED 0x000008
#define DL_OPENED 0x000010
+#define DL_RESERVED 0x000020
extern struct dyn_elf * _dl_symbol_tables;
extern struct elf_resolve * _dl_loaded_modules;
-extern struct dyn_elf * _dl_handles;
+extern struct dyn_elf * _dl_handles;
extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
DL_LOADADDR_TYPE loadaddr, unsigned long * dynamic_info,
unsigned long dynamic_addr, unsigned long dynamic_size);
-extern char * _dl_lookup_hash(const char * name, struct dyn_elf * rpnt,
- struct elf_resolve *mytpnt, int type_class
-#ifdef __FDPIC__
- , struct elf_resolve **tpntp
-#endif
- );
-
-static __always_inline char *_dl_find_hash(const char *name, struct dyn_elf *rpnt,
- struct elf_resolve *mytpnt, int type_class)
-{
-#ifdef __FDPIC__
- return _dl_lookup_hash(name, rpnt, mytpnt, type_class, NULL);
-#else
- return _dl_lookup_hash(name, rpnt, mytpnt, type_class);
-#endif
-}
-
-extern int _dl_linux_dynamic_link(void);
+extern char *_dl_find_hash(const char *name, struct r_scope_elem *scope,
+ struct elf_resolve *mytpnt, int type_class,
+ struct symbol_ref *symbol);
extern char * _dl_library_path;
-extern char * _dl_not_lazy;
-
-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
@@ -148,8 +177,9 @@ static __inline__ int _dl_symbol(char * name)
#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
+#define LD_ERROR_TLS_FAILED 8
+#define LD_WRONG_RELOCS 9
+#define LD_BAD_HANDLE 10
+#define LD_NO_SYMBOL 11
-#endif /* _LD_HASH_H_ */
+#endif /* _DL_HASH_H */
diff --git a/ldso/include/dl-string.h b/ldso/include/dl-string.h
index 746bd91c6..14ae617c3 100644
--- a/ldso/include/dl-string.h
+++ b/ldso/include/dl-string.h
@@ -5,12 +5,16 @@
* GNU Lesser General Public License version 2.1 or later.
*/
-#ifndef _LINUX_STRING_H_
-#define _LINUX_STRING_H_
+#ifndef _DL_STRING_H
+#define _DL_STRING_H
-#include <dl-sysdep.h> /* for do_rem */
#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))
@@ -19,26 +23,8 @@
# define do_div_10(result, remain) ((result) /= 10)
#endif
-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 __always_inline size_t _dl_strlen(const char * str)
+#ifdef IS_IN_rtld
+static __always_inline size_t _dl_strlen(const char *str)
{
register const char *ptr = (char *) str-1;
while (*++ptr)
@@ -59,7 +45,7 @@ static __always_inline char * _dl_strcat(char *dst, const char *src)
return dst;
}
-static __always_inline char * _dl_strcpy(char * dst,const char *src)
+static __always_inline char * _dl_strcpy(char *dst, const char *src)
{
register char *ptr = dst;
@@ -70,7 +56,7 @@ static __always_inline char * _dl_strcpy(char * dst,const char *src)
return ptr;
}
-static __always_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--;
@@ -84,23 +70,7 @@ static __always_inline int _dl_strcmp(const char * s1,const char * s2)
return c1 - c2;
}
-static __always_inline int _dl_strncmp(const char * s1,const char * s2,size_t len)
-{
- register unsigned char c1 = '\0';
- register unsigned char c2 = '\0';
-
- s1--;s2--;
- while (len > 0) {
- c1 = (unsigned char) *++s1;
- c2 = (unsigned char) *++s2;
- if (c1 == '\0' || c1 != c2)
- return c1 - c2;
- len--;
- }
- return c1 - c2;
-}
-
-static __always_inline char * _dl_strchr(const char * str,int c)
+static __always_inline char * _dl_strchr(const char *str, int c)
{
register char ch;
str--;
@@ -147,7 +117,7 @@ static __always_inline char * _dl_strstr(const char *s1, const char *s2)
} while (1);
}
-static __always_inline void * _dl_memcpy(void * dst, const void * src, size_t len)
+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;
@@ -159,7 +129,7 @@ static __always_inline void * _dl_memcpy(void * dst, const void * src, size_t le
return dst;
}
-static __always_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-1;
unsigned char *c2 = (unsigned char *)s2-1;
@@ -172,7 +142,7 @@ static __always_inline int _dl_memcmp(const void * s1,const void * s2,size_t len
return 0;
}
-#if defined(powerpc)
+#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)
{
@@ -200,7 +170,7 @@ lessthan4:
return to;
}
#else
-static __always_inline void * _dl_memset(void * str,int c,size_t len)
+static __always_inline void * _dl_memset(void *str, int c, size_t len)
{
register char *a = str;
@@ -228,11 +198,25 @@ static __always_inline char * _dl_get_last_path_component(char *path)
;/* 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_strchr strchr
+# define _dl_strrchr strrchr
+# define _dl_strstr strstr
+# 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. Avoid using mod
* or using long division */
-static __always_inline char * _dl_simple_ltoa(char * local, unsigned long i)
+static __always_inline char * _dl_simple_ltoa(char *local, unsigned long i)
{
/* 20 digits plus a null terminator should be good for
* 64-bit or smaller ints (2^64 - 1)*/
@@ -246,8 +230,10 @@ static __always_inline char * _dl_simple_ltoa(char * local, unsigned long i)
} while (i > 0);
return p;
}
+#endif
-static __always_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)
{
/* 16 digits plus a leading "0x" plus a null terminator,
* should be good for 64-bit or smaller ints */
@@ -266,9 +252,6 @@ static __always_inline char * _dl_simple_ltoahex(char * local, unsigned long i)
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 */
@@ -285,8 +268,8 @@ static __always_inline char * _dl_simple_ltoahex(char * local, unsigned long i)
/* 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(__mips__) || defined(__sh__) || defined(__powerpc__) || \
- defined(__avr32__) || defined(__xtensa__)
+ 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
@@ -362,4 +345,6 @@ static __always_inline char * _dl_simple_ltoahex(char * local, unsigned long i)
# define SEND_ADDRESS_STDERR_DEBUG(X, add_a_newline)
#endif
-#endif
+#endif /* IS_IN_rtld */
+
+#endif /* _DL_STRING_H */
diff --git a/ldso/include/dl-syscall.h b/ldso/include/dl-syscall.h
index 1cbbbad0f..5528ba6a0 100644
--- a/ldso/include/dl-syscall.h
+++ b/ldso/include/dl-syscall.h
@@ -5,51 +5,40 @@
* GNU Lesser General Public License version 2.1 or later.
*/
-#ifndef _LD_SYSCALL_H_
-#define _LD_SYSCALL_H_
+#ifndef _DL_SYSCALL_H
+#define _DL_SYSCALL_H
+
+/* We can't use the real errno in ldso, since it has not yet
+ * been dynamicly linked in yet. */
+#include "sys/syscall.h"
+extern int _dl_errno;
+#undef __set_errno
+#define __set_errno(X) {(_dl_errno) = (X);}
/* Pull in the arch specific syscall implementation */
#include <dl-syscalls.h>
/* For MAP_ANONYMOUS -- differs between platforms */
#define _SYS_MMAN_H 1
#include <bits/mman.h>
+
+#ifdef __ARCH_HAS_DEPRECATED_SYSCALLS__
/* 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... */
-#if defined(__sparc_v9__) && (__WORDSIZE == 64)
-#define kernel_stat64 stat
-#else
#define kernel_stat stat
-#endif
#include <bits/kernel_stat.h>
#include <bits/kernel_types.h>
-/* _dl_open() parameters */
-#define O_RDONLY 00
-#define O_WRONLY 01
-#define O_RDWR 02
-#define O_CREAT 0100
-
-/* 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. */
+#else
+/* 1. common-generic ABI doesn't need kernel_stat translation
+ * 3. S_IS?ID already provided by stat.h
+ */
+#include <sys/stat.h>
+#endif
/* Here are the definitions for some syscalls that are used
@@ -59,107 +48,140 @@
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 __always_inline _syscall1(void, _dl_exit, int, status);
+static __always_inline attribute_noreturn __cold void _dl_exit(int status)
+{
+ INLINE_SYSCALL(_dl_exit, 1, status);
+#if __GNUC_PREREQ(4, 5)
+ __builtin_unreachable(); /* shut up warning: 'noreturn' function does return*/
+#else
+ while (1);
+#endif
+}
#define __NR__dl_close __NR_close
-static __always_inline _syscall1(int, _dl_close, int, fd);
+static __always_inline _syscall1(int, _dl_close, int, fd)
-#define __NR__dl_open __NR_open
+#if defined __NR_openat && !defined __NR_open
+static __always_inline int _dl_open(const char *fn,
+ int flags, __kernel_mode_t mode)
+{
+ return INLINE_SYSCALL(openat, 4, AT_FDCWD, fn, flags, mode);
+}
+
+#elif defined __NR_open
+# define __NR__dl_open __NR_open
static __always_inline _syscall3(int, _dl_open, const char *, fn, int, flags,
- __kernel_mode_t, mode);
+ __kernel_mode_t, mode)
+#endif
#define __NR__dl_write __NR_write
static __always_inline _syscall3(unsigned long, _dl_write, int, fd,
- const void *, buf, unsigned long, count);
+ const void *, buf, unsigned long, count)
#define __NR__dl_read __NR_read
static __always_inline _syscall3(unsigned long, _dl_read, int, fd,
- const void *, buf, unsigned long, count);
+ const void *, buf, unsigned long, count)
#define __NR__dl_mprotect __NR_mprotect
static __always_inline _syscall3(int, _dl_mprotect, const void *, addr,
- unsigned long, len, int, prot);
+ unsigned long, len, int, prot)
-#define __NR__dl_stat __NR_stat
+#if defined __NR_fstatat64 && !defined __NR_stat
+# define __NR__dl_fstatat64 __NR_fstatat64
+static __always_inline _syscall4(int, _dl_fstatat64, int, fd, const char *,
+ fn, struct stat *, stat, int, flags)
+
+static __always_inline int _dl_stat(const char *file_name,
+ struct stat *buf)
+{
+ return _dl_fstatat64(AT_FDCWD, file_name, buf, 0);
+}
+#elif defined __NR_stat
+# define __NR__dl_stat __NR_stat
static __always_inline _syscall2(int, _dl_stat, const char *, file_name,
- struct stat *, buf);
+ struct stat *, buf)
+#endif
-#define __NR__dl_fstat __NR_fstat
-static __always_inline _syscall2(int, _dl_fstat, int, fd, struct stat *, buf);
+#if defined __NR_fstat64 && !defined __NR_fstat
+# define __NR__dl_fstat __NR_fstat64
+#elif defined __NR_fstat
+# define __NR__dl_fstat __NR_fstat
+#endif
+static __always_inline _syscall2(int, _dl_fstat, int, fd, struct stat *, buf)
#define __NR__dl_munmap __NR_munmap
-static __always_inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length);
+static __always_inline _syscall2(int, _dl_munmap, void *, start, unsigned long, length)
#ifdef __NR_getxuid
# define __NR_getuid __NR_getxuid
#endif
#define __NR__dl_getuid __NR_getuid
-static __always_inline _syscall0(uid_t, _dl_getuid);
+static __always_inline _syscall0(uid_t, _dl_getuid)
#ifndef __NR_geteuid
# define __NR_geteuid __NR_getuid
#endif
#define __NR__dl_geteuid __NR_geteuid
-static __always_inline _syscall0(uid_t, _dl_geteuid);
+static __always_inline _syscall0(uid_t, _dl_geteuid)
#ifdef __NR_getxgid
# define __NR_getgid __NR_getxgid
#endif
#define __NR__dl_getgid __NR_getgid
-static __always_inline _syscall0(gid_t, _dl_getgid);
+static __always_inline _syscall0(gid_t, _dl_getgid)
#ifndef __NR_getegid
# define __NR_getegid __NR_getgid
#endif
#define __NR__dl_getegid __NR_getegid
-static __always_inline _syscall0(gid_t, _dl_getegid);
+static __always_inline _syscall0(gid_t, _dl_getegid)
#ifdef __NR_getxpid
# define __NR_getpid __NR_getxpid
#endif
#define __NR__dl_getpid __NR_getpid
-static __always_inline _syscall0(gid_t, _dl_getpid);
+static __always_inline _syscall0(gid_t, _dl_getpid)
+
+#if defined __NR_readlinkat
+# define __NR__dl_readlink __NR_readlinkat
+static __always_inline _syscall4(int, _dl_readlink, int, id, const char *, path,
+ char *, buf, size_t, bufsiz)
+#endif
-#define __NR__dl_readlink __NR_readlink
-static __always_inline _syscall3(int, _dl_readlink, const char *, path, char *, buf,
- size_t, bufsiz);
+#ifdef __NR_pread64
+#define __NR___syscall_pread __NR_pread64
+static __always_inline _syscall5(ssize_t, __syscall_pread, int, fd, void *, buf,
+ size_t, count, off_t, offset_hi, off_t, offset_lo)
+
+static __always_inline ssize_t
+_dl_pread(int fd, void *buf, size_t count, off_t offset)
+{
+ return __syscall_pread(fd, buf, count, offset, offset >> 31);
+}
+#elif defined __NR_pread
+#define __NR___syscall_pread __NR_pread
+static __always_inline _syscall5(ssize_t, __syscall_pread, int, fd, void *, buf,
+ size_t, count, off_t, offset_hi, off_t, offset_lo)
+
+static __always_inline ssize_t
+_dl_pread(int fd, void *buf, size_t count, off_t offset)
+{
+ return __syscall_pread(fd, buf, count, __LONG_LONG_PAIR(offset >> 31, offset));
+}
+#endif
#ifdef __UCLIBC_HAS_SSP__
# include <sys/time.h>
# define __NR__dl_gettimeofday __NR_gettimeofday
static __always_inline _syscall2(int, _dl_gettimeofday, struct timeval *, tv,
# ifdef __USE_BSD
- struct timezone *, tz);
+ struct timezone *
# else
- void *, tz);
+ void *
# endif
+ , tz)
#endif
-
-/* handle all the fun mmap intricacies */
-#if (defined(__UCLIBC_MMAP_HAS_6_ARGS__) && defined(__NR_mmap)) || !defined(__NR_mmap2)
-# define _dl_MAX_ERRNO 4096
-# define _dl_mmap_check_error(__res) \
- (((long)__res) < 0 && ((long)__res) >= -_dl_MAX_ERRNO)
-#else
-# define MAP_FAILED ((void *) -1)
-# define _dl_mmap_check_error(X) (((void *)X) == MAP_FAILED)
-#endif
-
-/* first try mmap(), syscall6() style */
-#if defined(__UCLIBC_MMAP_HAS_6_ARGS__) && defined(__NR_mmap)
-
-# define __NR__dl_mmap __NR_mmap
-static __always_inline _syscall6(void *, _dl_mmap, void *, start, size_t, length,
- int, prot, int, flags, int, fd, off_t, offset);
-
-/* then try mmap2() */
-#elif defined(__NR_mmap2)
-
-# define __NR___syscall_mmap2 __NR_mmap2
-static __always_inline _syscall6(__ptr_t, __syscall_mmap2, __ptr_t, addr, size_t, len,
- int, prot, int, flags, int, fd, off_t, offset);
-
/* Some architectures always use 12 as page shift for mmap2() eventhough the
* real PAGE_SHIFT != 12. Other architectures use the same value as
* PAGE_SHIFT...
@@ -168,36 +190,41 @@ static __always_inline _syscall6(__ptr_t, __syscall_mmap2, __ptr_t, addr, size_t
# define MMAP2_PAGE_SHIFT 12
#endif
-static __always_inline void * _dl_mmap(void * addr, unsigned long size, int prot,
- int flags, int fd, unsigned long offset)
+#define MAP_FAILED ((void *) -1)
+#define _dl_mmap_check_error(X) (((void *)X) == MAP_FAILED)
+
+static __always_inline
+void *_dl_mmap(void *addr, unsigned long size, int prot,
+ int flags, int fd, unsigned long offset)
{
+#if defined(__UCLIBC_MMAP_HAS_6_ARGS__) && defined(__NR_mmap)
+ /* first try mmap(), syscall6() style */
+ return (void *)INLINE_SYSCALL(mmap, 6, addr, size, prot, flags, fd, offset);
+
+#elif defined(__NR_mmap2) && !defined (__mcoldfire__)
+ /* then try mmap2() */
+ unsigned long shifted;
+
if (offset & ((1 << MMAP2_PAGE_SHIFT) - 1))
return MAP_FAILED;
- return __syscall_mmap2(addr, size, prot, flags,
- fd, (off_t) (offset >> MMAP2_PAGE_SHIFT));
-}
-/* finally, fall back to mmap(), syscall1() style */
-#elif defined(__NR_mmap)
+ /* gcc needs help with putting things onto the stack */
+ shifted = offset >> MMAP2_PAGE_SHIFT;
+ return (void *)INLINE_SYSCALL(mmap2, 6, addr, size, prot, flags, fd, shifted);
-# define __NR__dl_mmap_real __NR_mmap
-static __always_inline _syscall1(void *, _dl_mmap_real, unsigned long *, buffer);
-static __always_inline void * _dl_mmap(void * addr, unsigned long size, int prot,
- int flags, int fd, unsigned long offset)
-{
+#elif defined(__NR_mmap)
+ /* finally, fall back to mmap(), syscall1() style */
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);
-}
-
+ return (void *)INLINE_SYSCALL(mmap, 1, buffer);
#else
# error "Your architecture doesn't seem to provide mmap() !?"
#endif
+}
-#endif /* _LD_SYSCALL_H_ */
+#endif /* _DL_SYSCALL_H */
diff --git a/ldso/include/dlfcn.h b/ldso/include/dlfcn.h
index 03afd34fb..5cdd6be53 100644
--- a/ldso/include/dlfcn.h
+++ b/ldso/include/dlfcn.h
@@ -19,9 +19,9 @@
`dladdr'. */
typedef struct
{
- __const char *dli_fname; /* File name of defining object. */
+ 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. */
+ const char *dli_sname; /* Name of nearest symbol. */
void *dli_saddr; /* Exact value of nearest symbol. */
} Dl_info;
diff --git a/ldso/include/inline-hashtab.h b/ldso/include/inline-hashtab.h
new file mode 100644
index 000000000..4a4812027
--- /dev/null
+++ b/ldso/include/inline-hashtab.h
@@ -0,0 +1,265 @@
+/*
+ * The hashcode handling code below is heavily inspired in libiberty's
+ * hashtab code, but with most adaptation points and support for
+ * deleting elements removed.
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ * Contributed by Vladimir Makarov (vmakarov@cygnus.com).
+ */
+
+#ifndef INLINE_HASHTAB_H
+# define INLINE_HASHTAB_H 1
+
+static __always_inline unsigned long
+higher_prime_number(unsigned long n)
+{
+ /* These are primes that are near, but slightly smaller than, a power of two. */
+ static const unsigned long primes[] = {
+ 7,
+ 13,
+ 31,
+ 61,
+ 127,
+ 251,
+ 509,
+ 1021,
+ 2039,
+ 4093,
+ 8191,
+ 16381,
+ 32749,
+ 65521,
+ 131071,
+ 262139,
+ 524287,
+ 1048573,
+ 2097143,
+ 4194301,
+ 8388593,
+ 16777213,
+ 33554393,
+ 67108859,
+ 134217689,
+ 268435399,
+ 536870909,
+ 1073741789,
+ /* 4294967291 */
+ ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
+ };
+ const unsigned long *low = &primes[0];
+ const unsigned long *high = &primes[ARRAY_SIZE(primes)];
+
+ while (low != high) {
+ const unsigned long *mid = low + (high - low) / 2;
+ if (n > *mid)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+
+#if 0
+ /* If we've run out of primes, abort. */
+ if (n > *low) {
+ fprintf(stderr, "Cannot find prime bigger than %lu\n", n);
+ abort();
+ }
+#endif
+
+ return *low;
+}
+
+struct funcdesc_ht
+{
+ /* Table itself */
+ void **entries;
+
+ /* Current size (in entries) of the hash table */
+ size_t size;
+
+ /* Current number of elements */
+ size_t n_elements;
+};
+
+static __always_inline struct funcdesc_ht *
+htab_create(void)
+{
+ struct funcdesc_ht *ht = _dl_malloc(sizeof(*ht));
+ size_t ent_size;
+
+ if (!ht)
+ return NULL;
+ ht->size = 3;
+ ent_size = sizeof(void *) * ht->size;
+ ht->entries = _dl_malloc(ent_size);
+ if (!ht->entries)
+ return NULL;
+
+ ht->n_elements = 0;
+ _dl_memset(ht->entries, 0, ent_size);
+
+ return ht;
+}
+
+/*
+ * This is only called from _dl_loadaddr_unmap, so it's safe to call
+ * _dl_free(). See the discussion below.
+ */
+static __always_inline void
+htab_delete(struct funcdesc_ht *htab)
+{
+ size_t i;
+
+ for (i = htab->size - 1; i >= 0; i--)
+ if (htab->entries[i])
+ _dl_free(htab->entries[i]);
+
+ _dl_free(htab->entries);
+ _dl_free(htab);
+}
+
+/*
+ * Similar to htab_find_slot, but without several unwanted side effects:
+ * - Does not call htab->eq_f when it finds an existing entry.
+ * - Does not change the count of elements/searches/collisions in the
+ * hash table.
+ * This function also assumes there are no deleted entries in the table.
+ * HASH is the hash value for the element to be inserted.
+ */
+static __always_inline void **
+find_empty_slot_for_expand(struct funcdesc_ht *htab, int hash)
+{
+ size_t size = htab->size;
+ unsigned int index = hash % size;
+ void **slot = htab->entries + index;
+ int hash2;
+
+ if (!*slot)
+ return slot;
+
+ hash2 = 1 + hash % (size - 2);
+ for (;;) {
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ slot = htab->entries + index;
+ if (!*slot)
+ return slot;
+ }
+}
+
+/*
+ * The following function changes size of memory allocated for the
+ * entries and repeatedly inserts the table elements. The occupancy
+ * of the table after the call will be about 50%. Naturally the hash
+ * table must already exist. Remember also that the place of the
+ * table entries is changed. If memory allocation failures are allowed,
+ * this function will return zero, indicating that the table could not be
+ * expanded. If all goes well, it will return a non-zero value.
+ */
+static __always_inline int
+htab_expand(struct funcdesc_ht *htab, int (*hash_fn) (void *))
+{
+ void **oentries;
+ void **olimit;
+ void **p;
+ void **nentries;
+ size_t nsize;
+
+ oentries = htab->entries;
+ olimit = oentries + htab->size;
+
+ /*
+ * Resize only when table after removal of unused elements is either
+ * too full or too empty.
+ */
+ if (htab->n_elements * 2 > htab->size)
+ nsize = higher_prime_number(htab->n_elements * 2);
+ else
+ nsize = htab->size;
+
+ nentries = _dl_malloc(sizeof(*nentries) * nsize);
+ _dl_memset(nentries, 0, sizeof(*nentries) * nsize);
+ if (nentries == NULL)
+ return 0;
+ htab->entries = nentries;
+ htab->size = nsize;
+
+ p = oentries;
+ do {
+ if (*p)
+ *find_empty_slot_for_expand(htab, hash_fn(*p)) = *p;
+ p++;
+ } while (p < olimit);
+
+#if 0
+ /*
+ * We can't tell whether this was allocated by the _dl_malloc()
+ * built into ld.so or malloc() in the main executable or libc,
+ * and calling free() for something that wasn't malloc()ed could
+ * do Very Bad Things (TM). Take the conservative approach
+ * here, potentially wasting as much memory as actually used by
+ * the hash table, even if multiple growths occur. That's not
+ * so bad as to require some overengineered solution that would
+ * enable us to keep track of how it was allocated.
+ */
+ _dl_free(oentries);
+#endif
+ return 1;
+}
+
+/*
+ * This function searches for a hash table slot containing an entry
+ * equal to the given element. To delete an entry, call this with
+ * INSERT = 0, then call htab_clear_slot on the slot returned (possibly
+ * after doing some checks). To insert an entry, call this with
+ * INSERT = 1, then write the value you want into the returned slot.
+ * When inserting an entry, NULL may be returned if memory allocation
+ * fails.
+ */
+static __always_inline void **
+htab_find_slot(struct funcdesc_ht *htab, void *ptr, int insert,
+ int (*hash_fn)(void *), int (*eq_fn)(void *, void *))
+{
+ unsigned int index;
+ int hash, hash2;
+ size_t size;
+ void **entry;
+
+ if (htab->size * 3 <= htab->n_elements * 4 &&
+ htab_expand(htab, hash_fn) == 0)
+ return NULL;
+
+ hash = hash_fn(ptr);
+
+ size = htab->size;
+ index = hash % size;
+
+ entry = &htab->entries[index];
+ if (!*entry)
+ goto empty_entry;
+ else if (eq_fn(*entry, ptr))
+ return entry;
+
+ hash2 = 1 + hash % (size - 2);
+ for (;;) {
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ entry = &htab->entries[index];
+ if (!*entry)
+ goto empty_entry;
+ else if (eq_fn(*entry, ptr))
+ return entry;
+ }
+
+ empty_entry:
+ if (!insert)
+ return NULL;
+
+ htab->n_elements++;
+ return entry;
+}
+
+#endif
diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h
index 35a72fc5e..e237885b9 100644
--- a/ldso/include/ldso.h
+++ b/ldso/include/ldso.h
@@ -5,8 +5,8 @@
* GNU Lesser General Public License version 2.1 or later.
*/
-#ifndef _LDSO_H_
-#define _LDSO_H_
+#ifndef _LDSO_H
+#define _LDSO_H
#include <features.h>
@@ -27,18 +27,46 @@
/* Pull in compiler and arch stuff */
#include <stdlib.h>
#include <stdarg.h>
+#include <stddef.h> /* for ptrdiff_t */
+#include <stdbool.h>
+#define _FCNTL_H
+/* We need this if arch has only new syscalls defined */
+#ifndef AT_FDCWD
+#define AT_FDCWD -100
+#endif /* AT_FDCWD */
+#include <bits/fcntl.h>
#include <bits/wordsize.h>
/* Pull in the arch specific type information */
#include <sys/types.h>
/* Pull in the arch specific page size */
#include <bits/uClibc_page.h>
+/* Pull in the MIN macro */
+#include <sys/param.h>
/* Pull in the ldso syscalls and string functions */
+#ifndef __ARCH_HAS_NO_SHARED__
#include <dl-syscall.h>
#include <dl-string.h>
/* Now the ldso specific headers */
#include <dl-elf.h>
+#ifdef __UCLIBC_HAS_TLS__
+/* Defines USE_TLS */
+#include <tls.h>
+#endif
#include <dl-hash.h>
+/* common align masks, if not specified by sysdep headers */
+#ifndef ADDR_ALIGN
+#define ADDR_ALIGN (_dl_pagesize - 1)
+#endif
+
+#ifndef PAGE_ALIGN
+#define PAGE_ALIGN (~ADDR_ALIGN)
+#endif
+
+#ifndef OFFS_ALIGN
+#define OFFS_ALIGN (PAGE_ALIGN & ~(1ul << (sizeof(_dl_pagesize) * 8 - 1)))
+#endif
+
/* For INIT/FINI dependency sorting. */
struct init_fini_list {
struct init_fini_list *next;
@@ -48,10 +76,25 @@ struct init_fini_list {
/* Global variables used within the shared library loader */
extern char *_dl_library_path; /* Where we look for libraries */
extern char *_dl_preload; /* Things to be loaded before the libs */
-extern char *_dl_ldsopath; /* Where the shared lib loader was found */
+#ifdef __LDSO_SEARCH_INTERP_PATH__
+extern const char *_dl_ldsopath; /* Where the shared lib loader was found */
+#endif
extern const char *_dl_progname; /* The name of the executable being run */
-extern int _dl_secure; /* Are we dealing with setuid stuff? */
extern size_t _dl_pagesize; /* Store the page size for use later */
+#ifdef __LDSO_PRELINK_SUPPORT__
+extern char *_dl_trace_prelink; /* Library for prelinking trace */
+extern struct elf_resolve *_dl_trace_prelink_map; /* Library map for prelinking trace */
+#else
+#define _dl_trace_prelink 0
+#endif
+#ifdef __DSBT__
+extern void **_dl_ldso_dsbt;
+#endif
+
+#if defined(USE_TLS) && USE_TLS
+extern void _dl_add_to_slotinfo (struct link_map *l);
+extern void ** __attribute__ ((const)) _dl_initial_error_catch_tsd (void);
+#endif
#ifdef __SUPPORT_LD_DEBUG__
extern char *_dl_debug;
@@ -63,13 +106,14 @@ extern char *_dl_debug_nofixups;
extern char *_dl_debug_bindings;
extern int _dl_debug_file;
# define __dl_debug_dprint(fmt, args...) \
- _dl_dprintf(_dl_debug_file, "%s:%i: " fmt, __FUNCTION__, __LINE__, ## args);
+ _dl_dprintf(_dl_debug_file, "%s:%i: " fmt, __func__, __LINE__, ## args);
# define _dl_if_debug_dprint(fmt, args...) \
do { if (_dl_debug) __dl_debug_dprint(fmt, ## args); } while (0)
#else
# define __dl_debug_dprint(fmt, args...) do {} while (0)
# define _dl_if_debug_dprint(fmt, args...) do {} while (0)
-# define _dl_debug_file 2
+/* disabled on purpose, _dl_debug_file should be guarded by __SUPPORT_LD_DEBUG__
+# define _dl_debug_file 2*/
#endif /* __SUPPORT_LD_DEBUG__ */
#ifdef IS_IN_rtld
@@ -100,11 +144,24 @@ extern int _dl_debug_file;
#endif
extern void *_dl_malloc(size_t size);
+extern void *_dl_calloc(size_t __nmemb, size_t __size);
+extern void *_dl_realloc(void *__ptr, size_t __size);
extern void _dl_free(void *);
extern char *_dl_getenv(const char *symbol, char **envp);
extern void _dl_unsetenv(const char *symbol, char **envp);
+#ifdef IS_IN_rtld
extern char *_dl_strdup(const char *string);
extern void _dl_dprintf(int, const char *, ...);
+#else
+# include <string.h>
+# define _dl_strdup strdup
+# include <stdio.h>
+# ifdef __USE_GNU
+# define _dl_dprintf dprintf
+# else
+# define _dl_dprintf(fd, fmt, args...) fprintf(stderr, fmt, ## args)
+# endif
+#endif
#ifndef DL_GET_READY_TO_RUN_EXTRA_PARMS
# define DL_GET_READY_TO_RUN_EXTRA_PARMS
@@ -113,7 +170,7 @@ extern void _dl_dprintf(int, const char *, ...);
# define DL_GET_READY_TO_RUN_EXTRA_ARGS
#endif
-extern void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
+extern void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
ElfW(auxv_t) auxvt[AT_EGID + 1], char **envp, char **argv
DL_GET_READY_TO_RUN_EXTRA_PARMS);
@@ -121,4 +178,8 @@ extern void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load
#include <dl-inlines.h>
#endif
-#endif /* _LDSO_H_ */
+#else /* __ARCH_HAS_NO_SHARED__ */
+#include <dl-defs.h>
+#endif
+
+#endif /* _LDSO_H */
diff --git a/ldso/include/ldsodefs.h b/ldso/include/ldsodefs.h
new file mode 100644
index 000000000..9ae645c60
--- /dev/null
+++ b/ldso/include/ldsodefs.h
@@ -0,0 +1,154 @@
+#ifndef _LDSODEFS_H
+#define _LDSODEFS_H 1
+
+#include <bits/kernel-features.h>
+
+#include <features.h>
+#include <tls.h>
+
+#ifdef __mips__
+/* The MIPS ABI specifies that the dynamic section has to be read-only. */
+
+#define DL_RO_DYN_SECTION 1
+
+/* TODO: Import in 64-bit relocations from glibc. */
+#endif
+
+#ifndef SHARED
+# define EXTERN extern
+#else
+# ifdef IS_IN_rtld
+# define EXTERN
+# else
+# define EXTERN extern
+# endif
+#endif
+
+/* Non-shared code has no support for multiple namespaces. */
+#ifdef SHARED
+# define DL_NNS 16
+#else
+# define DL_NNS 1
+#endif
+
+#define GL(x) _##x
+#define GLRO(x) _##x
+
+/* Variable pointing to the end of the stack (or close to it). This value
+ must be constant over the runtime of the application. Some programs
+ might use the variable which results in copy relocations on some
+ platforms. But this does not matter, ld.so can always use the local
+ copy. */
+extern void *__libc_stack_end;
+
+/* Determine next available module ID. */
+extern size_t _dl_next_tls_modid (void) internal_function attribute_hidden;
+
+/* Calculate offset of the TLS blocks in the static TLS block. */
+extern void _dl_determine_tlsoffset (void) internal_function attribute_hidden;
+
+/* Set up the data structures for TLS, when they were not set up at startup.
+ Returns nonzero on malloc failure.
+ This is called from _dl_map_object_from_fd or by libpthread. */
+extern int _dl_tls_setup (void) internal_function;
+rtld_hidden_proto (_dl_tls_setup)
+
+/* Allocate memory for static TLS block (unless MEM is nonzero) and dtv. */
+extern void *_dl_allocate_tls (void *mem) internal_function;
+
+/* Get size and alignment requirements of the static TLS block. */
+extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
+ internal_function;
+
+extern void _dl_allocate_static_tls (struct link_map *map)
+ internal_function attribute_hidden;
+extern int _dl_try_allocate_static_tls (struct link_map* map)
+ internal_function attribute_hidden;
+
+/* Taken from glibc/elf/dl-reloc.c */
+#define CHECK_STATIC_TLS(sym_map) \
+ do { \
+ if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET, 0)) \
+ _dl_allocate_static_tls (sym_map); \
+ } while (0)
+#define TRY_STATIC_TLS(sym_map) \
+ (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \
+ || _dl_try_allocate_static_tls (sym_map) == 0)
+
+/* These are internal entry points to the two halves of _dl_allocate_tls,
+ only used within rtld.c itself at startup time. */
+extern void *_dl_allocate_tls_storage (void)
+ internal_function attribute_hidden;
+extern void *_dl_allocate_tls_init (void *) internal_function;
+
+/* Deallocate memory allocated with _dl_allocate_tls. */
+extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
+
+extern void _dl_nothread_init_static_tls (struct link_map *) attribute_hidden;
+
+/* Highest dtv index currently needed. */
+EXTERN size_t _dl_tls_max_dtv_idx;
+/* Flag signalling whether there are gaps in the module ID allocation. */
+EXTERN bool _dl_tls_dtv_gaps;
+/* Information about the dtv slots. */
+EXTERN struct dtv_slotinfo_list
+{
+ size_t len;
+ struct dtv_slotinfo_list *next;
+ struct dtv_slotinfo
+ {
+ size_t gen;
+ bool is_static;
+ struct link_map *map;
+ } slotinfo[0];
+} *_dl_tls_dtv_slotinfo_list;
+/* Number of modules in the static TLS block. */
+EXTERN size_t _dl_tls_static_nelem;
+/* Size of the static TLS block. */
+EXTERN size_t _dl_tls_static_size;
+/* Size actually allocated in the static TLS block. */
+EXTERN size_t _dl_tls_static_used;
+/* Alignment requirement of the static TLS block. */
+EXTERN size_t _dl_tls_static_align;
+/* Function pointer for catching TLS errors. */
+#if 1 /* def _LIBC_REENTRANT */
+EXTERN void **(*_dl_error_catch_tsd) (void) __attribute__ ((const));
+#endif
+
+/* Number of additional entries in the slotinfo array of each slotinfo
+ list element. A large number makes it almost certain take we never
+ have to iterate beyond the first element in the slotinfo list. */
+# define TLS_SLOTINFO_SURPLUS (62)
+
+/* Number of additional slots in the dtv allocated. */
+# define DTV_SURPLUS (14)
+
+/* Initial dtv of the main thread, not allocated with normal malloc. */
+EXTERN void *_dl_initial_dtv;
+/* Generation counter for the dtv. */
+EXTERN size_t _dl_tls_generation;
+
+EXTERN void (*_dl_init_static_tls) (struct link_map *);
+
+/* We have the auxiliary vector. */
+#define HAVE_AUX_VECTOR
+
+/* We can assume that the kernel always provides the AT_UID, AT_EUID,
+ AT_GID, and AT_EGID values in the auxiliary vector from 2.4.0 or so on. */
+#if __ASSUME_AT_XID
+# define HAVE_AUX_XID
+#endif
+
+/* We can assume that the kernel always provides the AT_SECURE value
+ in the auxiliary vector from 2.5.74 or so on. */
+#if __ASSUME_AT_SECURE
+# define HAVE_AUX_SECURE
+#endif
+
+/* Starting with one of the 2.4.0 pre-releases the Linux kernel passes
+ up the page size information. */
+#if __ASSUME_AT_PAGESIZE
+# define HAVE_AUX_PAGESIZE
+#endif
+
+#endif
diff --git a/ldso/include/tlsdeschtab.h b/ldso/include/tlsdeschtab.h
new file mode 100644
index 000000000..056f859b7
--- /dev/null
+++ b/ldso/include/tlsdeschtab.h
@@ -0,0 +1,121 @@
+/* Hash table for TLS descriptors.
+ Copyright (C) 2005-2013 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Alexandre Oliva <aoliva@redhat.com>
+
+ uClibc port by Baruch Siach <baruch@tkos.co.il>
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef TLSDESCHTAB_H
+# define TLSDESCHTAB_H 1
+
+# ifdef SHARED
+
+# include <inline-hashtab.h>
+
+inline static int
+hash_tlsdesc (void *p)
+{
+ struct tlsdesc_dynamic_arg *td = p;
+
+ /* We know all entries are for the same module, so ti_offset is the
+ only distinguishing entry. */
+ return td->tlsinfo.ti_offset;
+}
+
+inline static int
+eq_tlsdesc (void *p, void *q)
+{
+ struct tlsdesc_dynamic_arg *tdp = p, *tdq = q;
+
+ return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset;
+}
+
+inline static int
+map_generation (struct link_map *map)
+{
+ size_t idx = map->l_tls_modid;
+ struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+
+ /* Find the place in the dtv slotinfo list. */
+ do
+ {
+ /* Does it fit in the array of this list element? */
+ if (idx < listp->len)
+ {
+ /* We should never get here for a module in static TLS, so
+ we can assume that, if the generation count is zero, we
+ still haven't determined the generation count for this
+ module. */
+ if (listp->slotinfo[idx].gen)
+ return listp->slotinfo[idx].gen;
+ else
+ break;
+ }
+ idx -= listp->len;
+ listp = listp->next;
+ }
+ while (listp != NULL);
+
+ /* If we get to this point, the module still hasn't been assigned an
+ entry in the dtv slotinfo data structures, and it will when we're
+ done with relocations. At that point, the module will get a
+ generation number that is one past the current generation, so
+ return exactly that. */
+ return GL(dl_tls_generation) + 1;
+}
+
+void *
+internal_function
+_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
+{
+ struct funcdesc_ht *ht;
+ void **entry;
+ struct tlsdesc_dynamic_arg *td, test;
+
+ ht = map->l_tlsdesc_table;
+ if (! ht)
+ {
+ ht = htab_create ();
+ if (! ht)
+ return 0;
+ map->l_tlsdesc_table = ht;
+ }
+
+ test.tlsinfo.ti_module = map->l_tls_modid;
+ test.tlsinfo.ti_offset = ti_offset;
+ entry = htab_find_slot (ht, &test, 1, hash_tlsdesc, eq_tlsdesc);
+ if (entry == NULL)
+ _dl_exit(1);
+ if (*entry)
+ {
+ td = *entry;
+ return td;
+ }
+
+ *entry = td = _dl_malloc (sizeof (struct tlsdesc_dynamic_arg));
+ /* This may be higher than the map's generation, but it doesn't
+ matter much. Worst case, we'll have one extra DTV update per
+ thread. */
+ td->gen_count = map_generation (map);
+ td->tlsinfo = test.tlsinfo;
+
+ return td;
+}
+
+# endif /* SHARED */
+
+#endif