summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makerules9
-rw-r--r--extra/Configs/Config.in28
-rw-r--r--ldso/include/dl-defs.h2
-rw-r--r--ldso/include/dl-elf.h50
-rw-r--r--ldso/include/dl-hash.h33
-rw-r--r--ldso/include/ldso.h9
-rw-r--r--ldso/ldso/Makefile.in8
-rw-r--r--ldso/ldso/dl-debug.c57
-rw-r--r--ldso/ldso/dl-elf.c81
-rw-r--r--ldso/ldso/dl-hash.c90
-rw-r--r--ldso/ldso/dl-startup.c41
-rw-r--r--ldso/ldso/ldso.c452
-rw-r--r--ldso/ldso/sh/elfinterp.c27
-rw-r--r--ldso/libdl/libdl.c59
-rw-r--r--libc/misc/internals/__uClibc_main.c18
15 files changed, 786 insertions, 178 deletions
diff --git a/Makerules b/Makerules
index 2e9ca05bf..435ccfd9e 100644
--- a/Makerules
+++ b/Makerules
@@ -294,6 +294,15 @@ endef
cmd_hcompile.u = $(HOSTCC) $(filter-out $(PHONY),$^) $(DEPS-$(notdir $@)) -o $@ $(BUILD_LDFLAGS) $(BUILD_LDFLAGS-$(notdir $(^D))) $(BUILD_LDFLAGS-$(notdir $@)) $(BUILD_CFLAGS) $(BUILD_CFLAGS-$(notdir $(^D))) $(BUILD_CFLAGS-$(notdir $@))
cmd_hcompile.o = $(HOSTCC) $(filter-out $(PHONY),$<) $(DEPS-$(notdir $@)) -c -o $@ $(BUILD_CFLAGS) $(BUILD_CFLAGS-$(notdir $(^D))) $(BUILD_CFLAGS-$(notdir $@))
+define create-lds
+ $(Q)$(RM) $@.lds
+ $(Q)$(CC) -nostdlib -nostartfiles -shared -Wl,-z,combreloc \
+ -Wl,-z,relro -Wl,--hash-style=gnu -Wl,-z,defs \
+ -Wl,--verbose 2>&1 | LC_ALL=C \
+ sed -e '/^=========/,/^=========/!d;/^=========/d' \
+ -e 's/\. = .* + SIZEOF_HEADERS;/& _begin = . - SIZEOF_HEADERS;/' > $@.lds
+endef
+
define link.so
$(Q)$(RM) $@ $@.$(2) $(dir $@)$(1)
@$(disp_ld)
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index e8d522d71..801669a17 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -342,6 +342,34 @@ config LDSO_BASE_FILENAME
WARNING: Changing the default prefix could cause problems with
binutils' ld !
+config LDSO_STANDALONE_SUPPORT
+ bool "Dynamic linker stand-alone mode support"
+ depends on HAVE_SHARED
+ default n
+ help
+ The dynamic linker can be run either indirectly through running some
+ dynamically linked program or library (in which case no command line
+ options to the dynamic linker can be passed and, in the ELF case, the
+ dynamic linker which is stored in the .interp section of the program
+ is executed) or directly by running:
+
+ /lib/ld-uClibc.so.* [OPTIONS] [PROGRAM [ARGUMENTS]]
+
+ Stand-alone execution is a prerequisite for adding prelink
+ capabilities to uClibc dynamic linker, as well useful for testing an
+ updated version of the dynamic linker without breaking the system.
+
+config LDSO_PRELINK_SUPPORT
+ bool "Dynamic linker prelink support"
+ depends on HAVE_SHARED
+ default n
+ select LDSO_STANDALONE_SUPPORT
+ help
+ The dynamic linker can be used in stand-alone mode by the prelink tool
+ for prelinking ELF shared libraries and binaries to speed up startup
+ time. It also is able to load and handle prelinked libraries and
+ binaries at runtime.
+
config UCLIBC_STATIC_LDCONFIG
bool "Link ldconfig statically"
depends on HAVE_SHARED
diff --git a/ldso/include/dl-defs.h b/ldso/include/dl-defs.h
index 2d6303cfe..cbbaa3cea 100644
--- a/ldso/include/dl-defs.h
+++ b/ldso/include/dl-defs.h
@@ -225,7 +225,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
diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h
index cbb2100b1..40c88b9da 100644
--- a/ldso/include/dl-elf.h
+++ b/ldso/include/dl-elf.h
@@ -15,6 +15,7 @@
/* Forward declarations for stuff defined in ld_hash.h */
struct dyn_elf;
struct elf_resolve;
+struct r_scope_elem;
#include <dl-defs.h>
#ifdef __LDSO_CACHE_SUPPORT__
@@ -30,16 +31,16 @@ static __inline__ void _dl_unmap_cache(void) { }
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);
+ struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size);
extern struct elf_resolve * _dl_load_shared_library(int secure,
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);
+ struct dyn_elf **rpnt, const char *libname);
extern struct elf_resolve *_dl_check_if_named_library_is_loaded(const char *full_libname,
int trace_loaded_objects);
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,24 +85,47 @@ 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
+
+#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[],
@@ -150,6 +174,20 @@ unsigned int __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info
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 {
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
index 34333f40f..e138e1d4b 100644
--- a/ldso/include/dl-hash.h
+++ b/ldso/include/dl-hash.h
@@ -25,6 +25,19 @@ struct dyn_elf {
struct dyn_elf * prev;
};
+struct sym_val {
+ const ElfW(Sym) *s;
+ struct elf_resolve *m;
+};
+
+/* 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. */
@@ -60,8 +73,13 @@ struct elf_resolve {
#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. */
@@ -128,6 +146,7 @@ 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;
@@ -139,17 +158,17 @@ extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
/* Only need extra arg with some configurations */
#if !((defined(USE_TLS) && USE_TLS) || defined __FDPIC__)
-# define _dl_lookup_hash(n, r, m, c, t) _dl_lookup_hash(n, r, m, c)
+# define _dl_lookup_hash(n, r, m, s, c, t) _dl_lookup_hash(n, r, m, s, c)
#endif
-extern char *_dl_lookup_hash(const char *name, struct dyn_elf *rpnt,
- struct elf_resolve *mytpnt, int type_class,
+extern char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope,
+ struct elf_resolve *mytpnt, struct sym_val *symbol, int type_class,
struct elf_resolve **tpntp);
-static __always_inline char *_dl_find_hash(const char *name, struct dyn_elf *rpnt,
- struct elf_resolve *mytpnt, int type_class,
+static __always_inline char *_dl_find_hash(const char *name, struct r_scope_elem *scope,
+ struct elf_resolve *mytpnt, struct sym_val *symbol, int type_class,
struct elf_resolve **tpntp)
{
- return _dl_lookup_hash(name, rpnt, mytpnt, type_class, tpntp);
+ return _dl_lookup_hash(name, scope, mytpnt, symbol, type_class, tpntp);
}
extern int _dl_linux_dynamic_link(void);
diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h
index 69b5dd75a..9aa610e7b 100644
--- a/ldso/include/ldso.h
+++ b/ldso/include/ldso.h
@@ -27,6 +27,7 @@
/* Pull in compiler and arch stuff */
#include <stdlib.h>
#include <stdarg.h>
+#include <stddef.h> /* for ptrdiff_t */
#define _FCNTL_H
#include <bits/fcntl.h>
#include <bits/wordsize.h>
@@ -72,6 +73,12 @@ extern char *_dl_preload; /* Things to be loaded before the libs */
extern char *_dl_ldsopath; /* Where the shared lib loader was found */
extern const char *_dl_progname; /* The name of the executable being run */
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
#if defined(USE_TLS) && USE_TLS
extern void _dl_add_to_slotinfo (struct link_map *l);
@@ -144,7 +151,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);
diff --git a/ldso/ldso/Makefile.in b/ldso/ldso/Makefile.in
index e71ae1563..c9dcebd60 100644
--- a/ldso/ldso/Makefile.in
+++ b/ldso/ldso/Makefile.in
@@ -62,8 +62,16 @@ ldso-y := $($(UCLIBC_LDSO_NAME)_OBJS:.o=.oS)
lib-so-y += $(ldso)
objclean-y += CLEAN_ldso/ldso
+ifeq ($(LDSO_PRELINK_SUPPORT),y)
+# Use a specific linker script for ld.so
+LDFLAGS-$(UCLIBC_LDSO_NAME).so += -T $(ldso:.$(ABI_VERSION)=).lds
+endif
+
$(ldso): $(ldso:.$(ABI_VERSION)=)
$(ldso:.$(ABI_VERSION)=): $($(UCLIBC_LDSO_NAME)_OUT)/$(UCLIBC_LDSO_NAME)_so.a
+ifeq ($(LDSO_PRELINK_SUPPORT),y)
+ $(call create-lds)
+endif
$(call link.so,$(ldso_FULL_NAME),$(ABI_VERSION))
$($(UCLIBC_LDSO_NAME)_OUT)/$(UCLIBC_LDSO_NAME)_so.a: $(ldso-y)
diff --git a/ldso/ldso/dl-debug.c b/ldso/ldso/dl-debug.c
index 7ce8bfbce..47b32316e 100644
--- a/ldso/ldso/dl-debug.c
+++ b/ldso/ldso/dl-debug.c
@@ -104,3 +104,60 @@ static void debug_reloc(ElfW(Sym) *symtab, char *strtab, ELF_RELOC *rpnt)
#define debug_reloc(symtab, strtab, rpnt)
#endif /* __SUPPORT_LD_DEBUG__ */
+
+#ifdef __LDSO_PRELINK_SUPPORT__
+static void
+internal_function
+_dl_debug_lookup (const char *undef_name, struct elf_resolve *undef_map,
+ const ElfW(Sym) *ref, struct sym_val *value, int type_class)
+{
+#ifdef SHARED
+ unsigned long symbol_addr;
+
+ if (_dl_trace_prelink)
+ {
+ int conflict = 0;
+ struct elf_resolve *tls_tpnt = NULL;
+ struct sym_val val = { NULL, NULL };
+
+ if ((_dl_trace_prelink_map == NULL
+ || _dl_trace_prelink_map == _dl_loaded_modules)
+ && undef_map != _dl_loaded_modules)
+ {
+ symbol_addr = (unsigned long)
+ _dl_find_hash(undef_name, &undef_map->symbol_scope,
+ undef_map, &val, type_class, &tls_tpnt);
+
+ if (val.s != value->s || val.m != value->m)
+ conflict = 1;
+ }
+
+ if (value->s
+ && (__builtin_expect (ELF_ST_TYPE(value->s->st_info)
+ == STT_TLS, 0)))
+ type_class = 4;
+
+ if (conflict
+ || _dl_trace_prelink_map == undef_map
+ || _dl_trace_prelink_map == NULL
+ || type_class == 4)
+ {
+ _dl_dprintf (1, "%s %x %x -> %x %x ",
+ conflict ? "conflict" : "lookup",
+ (size_t) undef_map->mapaddr,
+ (size_t) (((ElfW(Addr)) ref) - undef_map->mapaddr),
+ (size_t) (value->m ? value->m->mapaddr : 0),
+ (size_t) (value->s ? value->s->st_value : 0));
+ if (conflict)
+ _dl_dprintf (1, "x %x %x ",
+ (size_t) (val.m ? val.m->mapaddr : 0),
+ (size_t) (val.s ? val.s->st_value : 0));
+ _dl_dprintf (1, "/%x %s\n", type_class, undef_name);
+ }
+}
+#endif
+}
+
+#else
+#define _dl_debug_lookup(undef_name, undef_map, ref, value, type_class)
+#endif
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index 5562e0784..d72dd5ae2 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -322,7 +322,7 @@ goof:
*/
struct elf_resolve *_dl_load_elf_shared_library(int secure,
- struct dyn_elf **rpnt, char *libname)
+ struct dyn_elf **rpnt, const char *libname)
{
ElfW(Ehdr) *epnt;
unsigned long dynamic_addr = 0;
@@ -343,7 +343,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
size_t relro_size = 0;
struct stat st;
uint32_t *p32;
- DL_LOADADDR_TYPE lib_loadaddr;
+ DL_LOADADDR_TYPE lib_loadaddr = 0;
DL_INIT_LOADADDR_EXTRA_DECLS
libaddr = 0;
@@ -397,11 +397,15 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
return NULL;
}
- if ((epnt->e_type != ET_DYN) || (epnt->e_machine != MAGIC1
+ if ((epnt->e_type != ET_DYN
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ && epnt->e_type != ET_EXEC
+#endif
+ ) || (epnt->e_machine != MAGIC1
#ifdef MAGIC2
&& epnt->e_machine != MAGIC2
#endif
- ))
+ ))
{
_dl_internal_error_number =
(epnt->e_type != ET_DYN ? LD_ERROR_NOTDYN : LD_ERROR_NOTMAGIC);
@@ -426,7 +430,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
if (ppnt->p_type == PT_LOAD) {
/* See if this is a PIC library. */
- if (i == 0 && ppnt->p_vaddr > 0x1000000) {
+ if (minvma == 0xffffffff && ppnt->p_vaddr > 0x1000000) {
piclib = 0;
minvma = ppnt->p_vaddr;
}
@@ -462,14 +466,17 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
ppnt++;
}
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ if (epnt->e_type == ET_EXEC)
+ piclib = 0;
+#endif
+
DL_CHECK_LIB_TYPE (epnt, piclib, _dl_progname, libname);
maxvma = (maxvma + ADDR_ALIGN) & PAGE_ALIGN;
minvma = minvma & ~0xffffU;
flags = MAP_PRIVATE /*| MAP_DENYWRITE */ ;
- if (!piclib)
- flags |= MAP_FIXED;
if (piclib == 0 || piclib == 1) {
status = (char *) _dl_mmap((char *) (piclib ? 0 : minvma),
@@ -488,7 +495,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
/* Get the memory to store the library */
ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff];
- DL_INIT_LOADADDR(lib_loadaddr, libaddr, ppnt, epnt->e_phnum);
+ DL_INIT_LOADADDR(lib_loadaddr, libaddr - minvma, ppnt, epnt->e_phnum);
for (i = 0; i < epnt->e_phnum; i++) {
if (DL_IS_SPECIAL_SEGMENT (epnt, ppnt)) {
@@ -510,12 +517,6 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
char *tryaddr;
ssize_t size;
- /* See if this is a PIC library. */
- if (i == 0 && ppnt->p_vaddr > 0x1000000) {
- piclib = 0;
- /* flags |= MAP_FIXED; */
- }
-
if (ppnt->p_flags & PF_W) {
unsigned long map_size;
char *cpnt;
@@ -559,7 +560,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
}
tryaddr = piclib == 2 ? piclib2map
- : ((char*) (piclib ? libaddr : 0) +
+ : ((char*) (piclib ? libaddr : lib_loadaddr) +
(ppnt->p_vaddr & PAGE_ALIGN));
size = (ppnt->p_vaddr & ADDR_ALIGN)
@@ -644,7 +645,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
if (map_size < ppnt->p_vaddr + ppnt->p_memsz
&& !piclib2map) {
- tryaddr = map_size + (char*)(piclib ? libaddr : 0);
+ tryaddr = map_size + (char*)(piclib ? libaddr : lib_loadaddr);
status = (char *) _dl_mmap(tryaddr,
ppnt->p_vaddr + ppnt->p_memsz - map_size,
LXFLAGS(ppnt->p_flags), flags | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
@@ -655,7 +656,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
} else {
tryaddr = (piclib == 2 ? 0
: (char *) (ppnt->p_vaddr & PAGE_ALIGN)
- + (piclib ? libaddr : 0));
+ + (piclib ? libaddr : lib_loadaddr));
size = (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz;
status = (char *) _dl_mmap
(tryaddr, size, LXFLAGS(ppnt->p_flags),
@@ -679,8 +680,11 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
}
_dl_close(infile);
- /* For a non-PIC library, the addresses are all absolute */
- if (piclib) {
+ /*
+ * The dynamic_addr must be take into acount lib_loadaddr value, to note
+ * it is zero when the SO has been mapped to the elf's physical addr
+ */
+ if (lib_loadaddr) {
dynamic_addr = (unsigned long) DL_RELOC_ADDR(lib_loadaddr, dynamic_addr);
}
@@ -711,7 +715,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff];
for (i = 0; i < epnt->e_phnum; i++, ppnt++) {
if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) {
- _dl_mprotect((void *) ((piclib ? libaddr : 0) +
+ _dl_mprotect((void *) ((piclib ? libaddr : lib_loadaddr) +
(ppnt->p_vaddr & PAGE_ALIGN)),
(ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz,
PROT_READ | PROT_WRITE | PROT_EXEC);
@@ -727,13 +731,17 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
tpnt = _dl_add_elf_hash_table(libname, lib_loadaddr, dynamic_info,
dynamic_addr, 0);
+ tpnt->mapaddr = libaddr;
tpnt->relro_addr = relro_addr;
tpnt->relro_size = relro_size;
tpnt->st_dev = st.st_dev;
tpnt->st_ino = st.st_ino;
- tpnt->ppnt = (ElfW(Phdr) *) DL_RELOC_ADDR(tpnt->loadaddr, epnt->e_phoff);
+ tpnt->ppnt = (ElfW(Phdr) *) DL_RELOC_ADDR(tpnt->mapaddr, epnt->e_phoff);
tpnt->n_phent = epnt->e_phnum;
tpnt->rtld_flags |= rtld_flags;
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ tpnt->l_entry = epnt->e_entry;
+#endif
#if defined(USE_TLS) && USE_TLS
if (tlsppnt) {
@@ -755,7 +763,11 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
tpnt->l_tls_modid = _dl_next_tls_modid ();
/* We know the load address, so add it to the offset. */
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ if ((tpnt->l_tls_initimage != NULL) && piclib)
+#else
if (tpnt->l_tls_initimage != NULL)
+#endif
{
# ifdef __SUPPORT_LD_DEBUG_EARLY__
unsigned int tmp = (unsigned int) tpnt->l_tls_initimage;
@@ -772,7 +784,12 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
/*
* Add this object into the symbol chain
*/
- if (*rpnt) {
+ if (*rpnt
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ /* Do not create a new chain entry for the main executable */
+ && (*rpnt)->dyn
+#endif
+ ) {
(*rpnt)->next = _dl_malloc(sizeof(struct dyn_elf));
_dl_memset((*rpnt)->next, 0, sizeof(struct dyn_elf));
(*rpnt)->next->prev = (*rpnt);
@@ -789,9 +806,12 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
}
#endif
(*rpnt)->dyn = tpnt;
- tpnt->symbol_scope = _dl_symbol_tables;
tpnt->usage_count++;
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ tpnt->libtype = (epnt->e_type == ET_DYN) ? elf_lib : elf_executable;
+#else
tpnt->libtype = elf_lib;
+#endif
/*
* OK, the next thing we need to do is to insert the dynamic linker into
@@ -817,7 +837,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
}
/* now_flag must be RTLD_NOW or zero */
-int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
+int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int now_flag)
{
int goof = 0;
struct elf_resolve *tpnt;
@@ -825,7 +845,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
ElfW(Addr) reloc_addr;
if (rpnt->next)
- goof = _dl_fixup(rpnt->next, now_flag);
+ goof = _dl_fixup(rpnt->next, scope, now_flag);
if (goof)
return goof;
tpnt = rpnt->dyn;
@@ -852,10 +872,15 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
relative_count = tpnt->dynamic_info[DT_RELCONT_IDX];
if (relative_count) { /* Optimize the XX_RELATIVE relocations if possible */
reloc_size -= relative_count * sizeof(ELF_RELOC);
- elf_machine_relative(tpnt->loadaddr, reloc_addr, relative_count);
+ if (tpnt->loadaddr
+#ifdef __LDSO_PRELINK_SUPPORT__
+ || (!tpnt->dynamic_info[DT_GNU_PRELINKED_IDX])
+#endif
+ )
+ elf_machine_relative(tpnt->loadaddr, reloc_addr, relative_count);
reloc_addr += relative_count * sizeof(ELF_RELOC);
}
- goof += _dl_parse_relocation_information(rpnt,
+ goof += _dl_parse_relocation_information(rpnt, scope,
reloc_addr,
reloc_size);
tpnt->init_flag |= RELOCS_DONE;
@@ -871,7 +896,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
tpnt->dynamic_info[DT_JMPREL],
tpnt->dynamic_info [DT_PLTRELSZ]);
} else {
- goof += _dl_parse_relocation_information(rpnt,
+ goof += _dl_parse_relocation_information(rpnt, scope,
tpnt->dynamic_info[DT_JMPREL],
tpnt->dynamic_info[DT_PLTRELSZ]);
}
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
index 0048734ba..bb4c56b04 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -146,7 +146,6 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
tpnt->chains = hash_addr;
}
tpnt->loadaddr = loadaddr;
- tpnt->mapaddr = DL_RELOC_ADDR(loadaddr, 0);
for (i = 0; i < DYNAMIC_SIZE; i++)
tpnt->dynamic_info[i] = dynamic_info[i];
return tpnt;
@@ -268,72 +267,81 @@ _dl_lookup_sysv_hash(struct elf_resolve *tpnt, ElfW(Sym) *symtab, unsigned long
* This function resolves externals, and this is either called when we process
* relocations or when we call an entry in the PLT table for the first time.
*/
-char *_dl_lookup_hash(const char *name, struct dyn_elf *rpnt, struct elf_resolve *mytpnt,
- int type_class, struct elf_resolve **tpntp)
+char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope, struct elf_resolve *mytpnt,
+ struct sym_val *symbol, int type_class, struct elf_resolve **tpntp)
{
struct elf_resolve *tpnt = NULL;
ElfW(Sym) *symtab;
+ int i = 0;
unsigned long elf_hash_number = 0xffffffff;
const ElfW(Sym) *sym = NULL;
char *weak_result = NULL;
+ struct r_scope_elem *loop_scope;
#ifdef __LDSO_GNU_HASH_SUPPORT__
unsigned long gnu_hash_number = _dl_gnu_hash((const unsigned char *)name);
#endif
- for (; rpnt; rpnt = rpnt->next) {
- tpnt = rpnt->dyn;
-
- if (!(tpnt->rtld_flags & RTLD_GLOBAL) && mytpnt) {
- if (mytpnt == tpnt)
- ;
- else {
- struct init_fini_list *tmp;
-
- for (tmp = mytpnt->rtld_local; tmp; tmp = tmp->next) {
- if (tmp->tpnt == tpnt)
- break;
+ for (loop_scope = scope; loop_scope && !sym; loop_scope = loop_scope->next) {
+ for (i = 0; i < loop_scope->r_nlist; i++) {
+ tpnt = loop_scope->r_list[i];
+
+ if (!(tpnt->rtld_flags & RTLD_GLOBAL) && mytpnt) {
+ if (mytpnt == tpnt)
+ ;
+ else {
+ struct init_fini_list *tmp;
+
+ for (tmp = mytpnt->rtld_local; tmp; tmp = tmp->next) {
+ if (tmp->tpnt == tpnt)
+ break;
+ }
+ if (!tmp)
+ continue;
}
- if (!tmp)
- continue;
}
- }
- /* Don't search the executable when resolving a copy reloc. */
- if ((type_class & ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable)
- continue;
+ /* Don't search the executable when resolving a copy reloc. */
+ if ((type_class & ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable)
+ continue;
- /* If the hash table is empty there is nothing to do here. */
- if (tpnt->nbucket == 0)
- continue;
+ /* If the hash table is empty there is nothing to do here. */
+ if (tpnt->nbucket == 0)
+ continue;
- symtab = (ElfW(Sym) *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
+ symtab = (ElfW(Sym) *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
#ifdef __LDSO_GNU_HASH_SUPPORT__
- /* Prefer GNU hash style, if any */
- if (tpnt->l_gnu_bitmask) {
- sym = _dl_lookup_gnu_hash(tpnt, symtab, gnu_hash_number, name, type_class);
- if (sym != NULL)
- /* If sym has been found, do not search further */
- break;
- } else {
+ /* Prefer GNU hash style, if any */
+ if (tpnt->l_gnu_bitmask) {
+ sym = _dl_lookup_gnu_hash(tpnt, symtab, gnu_hash_number, name, type_class);
+ if (sym != NULL)
+ /* If sym has been found, do not search further */
+ break;
+ } else {
#endif
- /* Use the old SysV-style hash table */
+ /* Use the old SysV-style hash table */
- /* Calculate the old sysv hash number only once */
- if (elf_hash_number == 0xffffffff)
- elf_hash_number = _dl_elf_hash((const unsigned char *)name);
+ /* Calculate the old sysv hash number only once */
+ if (elf_hash_number == 0xffffffff)
+ elf_hash_number = _dl_elf_hash((const unsigned char *)name);
- sym = _dl_lookup_sysv_hash(tpnt, symtab, elf_hash_number, name, type_class);
- if (sym != NULL)
- break;
+ sym = _dl_lookup_sysv_hash(tpnt, symtab, elf_hash_number, name, type_class);
+ if (sym != NULL)
+ /* If sym has been found, do not search further */
+ break;
#ifdef __LDSO_GNU_HASH_SUPPORT__
- }
+ }
#endif
- } /* end of for (; rpnt; rpnt = rpnt->next) { */
+ } /* End of inner for */
+ }
if (sym) {
+ if (symbol) {
+ symbol->s = sym;
+ symbol->m = tpnt;
+ }
/* At this point we have found the requested symbol, do binding */
#if defined(USE_TLS) && USE_TLS
if (ELF_ST_TYPE(sym->st_info) == STT_TLS) {
diff --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c
index a51b583a4..4799846ee 100644
--- a/ldso/ldso/dl-startup.c
+++ b/ldso/ldso/dl-startup.c
@@ -94,6 +94,11 @@
/* Pull in all the arch specific stuff */
#include "dl-startup.h"
+#ifdef __LDSO_PRELINK_SUPPORT__
+/* These defined magically in the linker script. */
+extern char _begin[] attribute_hidden;
+#endif
+
/* Static declarations */
static int (*_dl_elf_main) (int, char **, char **);
@@ -164,11 +169,26 @@ DL_START(unsigned long args)
aux_dat += 2;
}
- /* locate the ELF header. We need this done as soon as possible
- * (esp since SEND_STDERR() needs this on some platforms... */
+ /*
+ * Locate the dynamic linker ELF header. We need this done as soon as
+ * possible (esp since SEND_STDERR() needs this on some platforms...
+ */
+
+#ifdef __LDSO_PRELINK_SUPPORT__
+ /*
+ * The `_begin' symbol created by the linker script points to ld.so ELF
+ * We use it if the kernel is not passing a valid address through the auxvt.
+ */
+
+ if (!auxvt[AT_BASE].a_un.a_val)
+ auxvt[AT_BASE].a_un.a_val = (Elf32_Addr) &_begin;
+ /* Note: if the dynamic linker itself is prelinked, the load_addr is 0 */
+ DL_INIT_LOADADDR_BOOT(load_addr, elf_machine_load_address());
+#else
if (!auxvt[AT_BASE].a_un.a_val)
auxvt[AT_BASE].a_un.a_val = elf_machine_load_address();
DL_INIT_LOADADDR_BOOT(load_addr, auxvt[AT_BASE].a_un.a_val);
+#endif
header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_val;
/* Check the ELF header to make sure everything looks ok. */
@@ -183,7 +203,7 @@ DL_START(unsigned long args)
_dl_exit(0);
}
SEND_EARLY_STDERR_DEBUG("ELF header=");
- SEND_ADDRESS_STDERR_DEBUG(DL_LOADADDR_BASE(load_addr), 1);
+ SEND_ADDRESS_STDERR_DEBUG(DL_LOADADDR_BASE(header), 1);
/* Locate the global offset table. Since this code must be PIC
* we can take advantage of the magic offset register, if we
@@ -192,7 +212,7 @@ DL_START(unsigned long args)
DL_BOOT_COMPUTE_GOT(got);
/* Now, finally, fix up the location of the dynamic stuff */
- DL_BOOT_COMPUTE_DYN(dpnt, got, load_addr);
+ DL_BOOT_COMPUTE_DYN(dpnt, got, (DL_LOADADDR_TYPE)header);
SEND_EARLY_STDERR_DEBUG("First Dynamic section entry=");
SEND_ADDRESS_STDERR_DEBUG(dpnt, 1);
@@ -258,7 +278,12 @@ DL_START(unsigned long args)
if (!indx && relative_count) {
rel_size -= relative_count * sizeof(ELF_RELOC);
- elf_machine_relative(load_addr, rel_addr, relative_count);
+ if (load_addr
+#ifdef __LDSO_PRELINK_SUPPORT__
+ || !tpnt->dynamic_info[DT_GNU_PRELINKED_IDX]
+#endif
+ )
+ elf_machine_relative(load_addr, rel_addr, relative_count);
rel_addr += relative_count * sizeof(ELF_RELOC);
}
@@ -321,12 +346,12 @@ DL_START(unsigned long args)
__rtld_stack_end = (void *)(argv - 1);
- _dl_get_ready_to_run(tpnt, load_addr, auxvt, envp, argv
- DL_GET_READY_TO_RUN_EXTRA_ARGS);
+ _dl_elf_main = (int (*)(int, char **, char **))
+ _dl_get_ready_to_run(tpnt, (DL_LOADADDR_TYPE) header, auxvt, envp, argv
+ DL_GET_READY_TO_RUN_EXTRA_ARGS);
/* Transfer control to the application. */
SEND_STDERR_DEBUG("transfering control to application @ ");
- _dl_elf_main = (int (*)(int, char **, char **)) auxvt[AT_ENTRY].a_un.a_val;
SEND_ADDRESS_STDERR_DEBUG(_dl_elf_main, 1);
#if !defined(START)
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index ea4ad0f1c..e0d323a9f 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -57,6 +57,12 @@ struct r_debug *_dl_debug_addr = NULL; /* Used to communicate with the gdb debug
void *(*_dl_malloc_function) (size_t size) = NULL;
void (*_dl_free_function) (void *p) = NULL;
+#ifdef __LDSO_PRELINK_SUPPORT__
+char *_dl_trace_prelink = NULL; /* Library for prelinking trace */
+struct elf_resolve *_dl_trace_prelink_map = NULL; /* Library module for prelinking trace */
+bool _dl_verbose = true; /* On by default */
+bool prelinked = false;
+#endif
static int _dl_secure = 1; /* Are we dealing with setuid stuff? */
#ifdef __SUPPORT_LD_DEBUG__
@@ -70,8 +76,18 @@ char *_dl_debug_bindings = NULL;
int _dl_debug_file = 2;
#endif
-/* Needed for standalone execution. */
+#if defined (__LDSO_STANDALONE_SUPPORT__) && defined (__sh__)
+/* Not hidden, needed for standalone execution. */
+/*
+ * FIXME: align dl_start for SH to other archs so that we can keep this symbol
+ * hidden and we don't need to handle in __uClibc_main
+ */
+
+unsigned long _dl_skip_args = 0;
+#else
unsigned long attribute_hidden _dl_skip_args = 0;
+#endif
+
const char *_dl_progname = UCLIBC_LDSO; /* The name of the executable being run */
#include "dl-startup.c"
#include "dl-symbols.c"
@@ -97,6 +113,7 @@ static unsigned char *_dl_malloc_addr = NULL; /* Lets _dl_malloc use the already
static unsigned char *_dl_mmap_zero = NULL; /* Also used by _dl_malloc */
static struct elf_resolve **init_fini_list;
+static struct elf_resolve **scope_elem_list;
static unsigned int nlist; /* # items in init_fini_list */
extern void _start(void);
@@ -274,20 +291,101 @@ static void __attribute__ ((destructor)) __attribute_used__ _dl_fini(void)
}
}
-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
+#ifdef __LDSO_PRELINK_SUPPORT__
+static void trace_objects(struct elf_resolve *tpnt, char *str_name)
+{
+ if (_dl_strcmp(_dl_trace_prelink, tpnt->libname) == 0)
+ _dl_trace_prelink_map = tpnt;
+ if (tpnt->libtype == elf_executable) {
+/* Main executeble */
+ _dl_dprintf(1, "\t%s => %s (%x, %x)", tpnt->libname, tpnt->libname,
+ tpnt->mapaddr, DL_LOADADDR_BASE(tpnt->loadaddr));
+ } else {
+/* Preloaded, Needed or interpreter */
+ _dl_dprintf(1, "\t%s => %s (%x, %x)", str_name, tpnt->libname,
+ tpnt->mapaddr, DL_LOADADDR_BASE(tpnt->loadaddr));
+ }
+
+ if ((tpnt->libtype != program_interpreter) && (tpnt->l_tls_modid))
+ _dl_dprintf (1, " TLS(%x, %x)\n", tpnt->l_tls_modid,
+ (size_t) tpnt->l_tls_offset);
+ else
+ _dl_dprintf (1, "\n");
+}
+#endif
+
+static struct elf_resolve * add_ldso(struct elf_resolve *tpnt,
+ DL_LOADADDR_TYPE load_addr,
+ ElfW(auxv_t) auxvt[AT_EGID + 1],
+ struct dyn_elf *rpnt)
+{
+ ElfW(Ehdr) *epnt = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_val;
+ ElfW(Phdr) *myppnt = (ElfW(Phdr) *)
+ DL_RELOC_ADDR(load_addr, epnt->e_phoff);
+ int j;
+ struct stat st;
+
+ tpnt = _dl_add_elf_hash_table(tpnt->libname, tpnt->loadaddr,
+ tpnt->dynamic_info, (unsigned long)tpnt->dynamic_addr,
+ 0);
+
+ tpnt->mapaddr = load_addr;
+ if (_dl_stat(tpnt->libname, &st) >= 0) {
+ tpnt->st_dev = st.st_dev;
+ tpnt->st_ino = st.st_ino;
+ }
+ tpnt->n_phent = epnt->e_phnum;
+ tpnt->ppnt = myppnt;
+ for (j = 0; j < epnt->e_phnum; j++, myppnt++) {
+ if (myppnt->p_type == PT_GNU_RELRO) {
+ tpnt->relro_addr = myppnt->p_vaddr;
+ tpnt->relro_size = myppnt->p_memsz;
+ break;
+ }
+ }
+ tpnt->libtype = program_interpreter;
+ if (rpnt) {
+ rpnt->next = _dl_zalloc(sizeof(struct dyn_elf));
+ rpnt->next->prev = rpnt;
+ rpnt = rpnt->next;
+ } else {
+ rpnt = _dl_zalloc(sizeof(struct dyn_elf));
+ }
+ rpnt->dyn = tpnt;
+ tpnt->rtld_flags = RTLD_NOW | RTLD_GLOBAL; /* Must not be LAZY */
+
+ return tpnt;
+}
+
+static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list,
+ struct elf_resolve *map)
+{
+ struct elf_resolve **p = list;
+ struct init_fini_list *q;
+
+ *p++ = map;
+ map->init_flag |= DL_RESERVED;
+ if (map->init_fini)
+ for (q = map->init_fini; q; q = q->next)
+ if (! (q->tpnt->init_flag & DL_RESERVED))
+ p += _dl_build_local_scope (p, q->tpnt);
+ return p - list;
+}
+
+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)
{
ElfW(Addr) app_mapaddr = 0;
ElfW(Phdr) *ppnt;
ElfW(Dyn) *dpnt;
char *lpntstr;
- unsigned int i;
+ unsigned int i, cnt, k, nscope_elem;
int unlazy = 0, trace_loaded_objects = 0;
struct dyn_elf *rpnt;
struct elf_resolve *tcurr;
struct elf_resolve *tpnt1;
+ struct elf_resolve *ldso_tpnt = NULL;
struct elf_resolve app_tpnt_tmp;
struct elf_resolve *app_tpnt = &app_tpnt_tmp;
struct r_debug *debug_addr;
@@ -295,7 +393,9 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
unsigned long *_dl_envp; /* The environment address */
ElfW(Addr) relro_addr = 0;
size_t relro_size = 0;
- struct stat st;
+ struct r_scope_elem *global_scope;
+ struct elf_resolve **local_scope;
+
#if defined(USE_TLS) && USE_TLS
void *tcbp = NULL;
#endif
@@ -327,10 +427,12 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
_dl_progname = argv[0];
}
+#ifndef __LDSO_STANDALONE_SUPPORT__
if (_start == (void *) auxvt[AT_ENTRY].a_un.a_val) {
- _dl_dprintf(_dl_debug_file, "Standalone execution is not supported yet\n");
+ _dl_dprintf(_dl_debug_file, "Standalone execution is not enabled\n");
_dl_exit(1);
}
+#endif
/* Start to build the tables of the modules that are required for
* this beast to run. We start with the basic executable, and then
@@ -382,6 +484,99 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
_dl_init_static_tls = &_dl_nothread_init_static_tls;
#endif
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ if (_start == (void *) auxvt[AT_ENTRY].a_un.a_val) {
+ char *ptmp;
+ unsigned int *aux_dat = (unsigned int *) argv;
+ int argc = aux_dat[-1];
+
+ tpnt->libname = argv[0];
+ while (argc > 1)
+ if (! _dl_strcmp (argv[1], "--library-path") && argc > 2) {
+ _dl_library_path = argv[2];
+ _dl_skip_args += 2;
+ argc -= 2;
+ argv += 2;
+ } else
+ break;
+
+ /*
+ * If we have no further argument the program was called incorrectly.
+ * Grant the user some education.
+ */
+
+ if (argc < 2) {
+ _dl_dprintf(1, "\
+Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
+You have invoked `ld.so', the helper program for shared library executables.\n\
+This program usually lives in the file `/lib/ld.so', and special directives\n\
+in executable files using ELF shared libraries tell the system's program\n\
+loader to load the helper program from this file. This helper program loads\n\
+the shared libraries needed by the program executable, prepares the program\n\
+to run, and runs it. You may invoke this helper program directly from the\n\
+command line to load and run an ELF executable file; this is like executing\n\
+that file itself, but always uses this helper program from the file you\n\
+specified, instead of the helper program file specified in the executable\n\
+file you run. This is mostly of use for maintainers to test new versions\n\
+of this helper program; chances are you did not intend to run this program.\n\
+\n\
+ --library-path PATH use given PATH instead of content of the environment\n\
+ variable LD_LIBRARY_PATH\n");
+ _dl_exit(1);
+ }
+
+ ++_dl_skip_args;
+ ++argv;
+ _dl_progname = argv[0];
+
+ _dl_symbol_tables = rpnt = _dl_zalloc(sizeof(struct dyn_elf));
+ /*
+ * It needs to load the _dl_progname and to map it
+ * Usually it is the main application launched by means of the ld.so
+ * but it could be also a shared object (when ld.so used for tracing)
+ * We keep the misleading app_tpnt name to avoid variable pollution
+ */
+ app_tpnt = _dl_load_elf_shared_library(_dl_secure, &rpnt, _dl_progname);
+ if (!app_tpnt) {
+ _dl_dprintf(_dl_debug_file, "can't load '%s'\n", _dl_progname);
+ _dl_exit(16);
+ }
+ /*
+ * FIXME: it needs to properly handle a PIE executable
+ * Usually for a main application, loadaddr is computed as difference
+ * between auxvt entry points and phdr, so if it is not 0, that it is a
+ * PIE executable. In this case instead we need to set the loadaddr to 0
+ * because we are actually mapping the ELF for the main application by
+ * ourselves. So the PIE case must be checked.
+ */
+
+ app_tpnt->rtld_flags = unlazy | RTLD_GLOBAL;
+
+ /*
+ * This is used by gdb to locate the chain of shared libraries that are
+ * currently loaded.
+ */
+ debug_addr = _dl_zalloc(sizeof(struct r_debug));
+ ppnt = (ElfW(Phdr) *)app_tpnt->ppnt;
+ for (i = 0; i < app_tpnt->n_phent; i++, ppnt++) {
+ if (ppnt->p_type == PT_DYNAMIC) {
+ dpnt = (ElfW(Dyn) *) DL_RELOC_ADDR(app_tpnt->loadaddr, ppnt->p_vaddr);
+ _dl_parse_dynamic_info(dpnt, app_tpnt->dynamic_info, debug_addr, app_tpnt->loadaddr);
+ }
+ }
+
+ /* Store the path where the shared lib loader was found
+ * for later use
+ */
+ _dl_ldsopath = _dl_strdup(tpnt->libname);
+ ptmp = _dl_strrchr(_dl_ldsopath, '/');
+ if (ptmp != _dl_ldsopath)
+ *ptmp = '\0';
+
+ _dl_debug_early("Lib Loader: (%x) %s\n", (unsigned) DL_LOADADDR_BASE(tpnt->loadaddr), tpnt->libname);
+ } else {
+#endif
+
/* At this point we are now free to examine the user application,
* and figure out which libraries are supposed to be called. Until
* we have this list, we will not be completely ready for dynamic
@@ -469,7 +664,6 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
app_tpnt->mapaddr = app_mapaddr;
app_tpnt->rtld_flags = unlazy | RTLD_GLOBAL;
app_tpnt->usage_count++;
- app_tpnt->symbol_scope = _dl_symbol_tables;
lpnt = (unsigned long *) (app_tpnt->dynamic_info[DT_PLTGOT]);
#ifdef ALLOW_ZERO_PLTGOT
if (lpnt)
@@ -530,14 +724,18 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
* case the executable is actually an ET_DYN object.
*/
if (app_tpnt->l_tls_initimage != NULL) {
+ unsigned int tmp = (unsigned int) app_tpnt->l_tls_initimage;
app_tpnt->l_tls_initimage =
(char *) app_tpnt->l_tls_initimage + app_tpnt->loadaddr;
_dl_debug_early("Relocated TLS initial image from %x to %x (size = %x)\n",
- (unsigned int)app_tpnt->l_tls_initimage,
- app_tpnt->l_tls_initimage, app_tpnt->l_tls_initimage_size);
+ tmp, app_tpnt->l_tls_initimage, app_tpnt->l_tls_initimage_size);
}
#endif
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ } /* ! ldso standalone mode */
+#endif
+
#ifdef __SUPPORT_LD_DEBUG__
_dl_debug = _dl_getenv("LD_DEBUG", envp);
if (_dl_debug) {
@@ -586,6 +784,16 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
}
#endif
+#ifdef __LDSO_PRELINK_SUPPORT__
+{
+ char *ld_warn = _dl_getenv ("LD_WARN", envp);
+
+ if (ld_warn && *ld_warn == '\0')
+ _dl_verbose = false;
+}
+ _dl_trace_prelink = _dl_getenv("LD_TRACE_PRELINKING", envp);
+#endif
+
if (_dl_getenv("LD_TRACE_LOADED_OBJECTS", envp) != NULL) {
trace_loaded_objects++;
}
@@ -639,7 +847,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
tpnt1 = _dl_load_shared_library(_dl_secure, &rpnt, NULL, str, trace_loaded_objects);
if (!tpnt1) {
#ifdef __LDSO_LDD_SUPPORT__
- if (trace_loaded_objects)
+ if (trace_loaded_objects || _dl_trace_prelink)
_dl_dprintf(1, "\t%s => not found\n", str);
else
#endif
@@ -653,7 +861,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
_dl_debug_early("Loading: (%x) %s\n", DL_LOADADDR_BASE(tpnt1->loadaddr), tpnt1->libname);
#ifdef __LDSO_LDD_SUPPORT__
- if (trace_loaded_objects &&
+ if (trace_loaded_objects && !_dl_trace_prelink &&
tpnt1->usage_count == 1) {
/* This is a real hack to make
* ldd not print the library
@@ -730,7 +938,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
tpnt1 = _dl_load_shared_library(0, &rpnt, NULL, cp2, trace_loaded_objects);
if (!tpnt1) {
# ifdef __LDSO_LDD_SUPPORT__
- if (trace_loaded_objects)
+ if (trace_loaded_objects || _dl_trace_prelink)
_dl_dprintf(1, "\t%s => not found\n", cp2);
else
# endif
@@ -744,7 +952,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
_dl_debug_early("Loading: (%x) %s\n", DL_LOADADDR_BASE(tpnt1->loadaddr), tpnt1->libname);
# ifdef __LDSO_LDD_SUPPORT__
- if (trace_loaded_objects &&
+ if (trace_loaded_objects && !_dl_trace_prelink &&
tpnt1->usage_count == 1) {
_dl_dprintf(1, "\t%s => %s (%x)\n",
cp2, tpnt1->libname,
@@ -775,14 +983,21 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
lpntstr = (char*) (tcurr->dynamic_info[DT_STRTAB] + this_dpnt->d_un.d_val);
name = _dl_get_last_path_component(lpntstr);
- if (_dl_strcmp(name, UCLIBC_LDSO) == 0)
- continue;
-
_dl_if_debug_dprint("\tfile='%s'; needed by '%s'\n", lpntstr, _dl_progname);
- if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr, trace_loaded_objects))) {
+ if (_dl_strcmp(name, UCLIBC_LDSO) == 0) {
+ if (!ldso_tpnt) {
+ /* Insert the ld.so only once */
+ ldso_tpnt = add_ldso(tpnt, load_addr, auxvt, rpnt);
+ }
+ ldso_tpnt->usage_count++;
+ tpnt1 = ldso_tpnt;
+ } else
+ tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr, trace_loaded_objects);
+
+ if (!tpnt1) {
#ifdef __LDSO_LDD_SUPPORT__
- if (trace_loaded_objects) {
+ if (trace_loaded_objects || _dl_trace_prelink) {
_dl_dprintf(1, "\t%s => not found\n", lpntstr);
continue;
} else
@@ -803,7 +1018,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
_dl_debug_early("Loading: (%x) %s\n", DL_LOADADDR_BASE(tpnt1->loadaddr), tpnt1->libname);
#ifdef __LDSO_LDD_SUPPORT__
- if (trace_loaded_objects &&
+ if (trace_loaded_objects && !_dl_trace_prelink &&
tpnt1->usage_count == 1) {
_dl_dprintf(1, "\t%s => %s (%x)\n",
lpntstr, tpnt1->libname,
@@ -815,12 +1030,18 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
}
_dl_unmap_cache();
- --nlist; /* Exclude the application. */
+ /* Keep track of the number of elements in the global scope */
+ nscope_elem = nlist;
+
+ if (_dl_loaded_modules->libtype == elf_executable) {
+ --nlist; /* Exclude the application. */
+ tcurr = _dl_loaded_modules->next;
+ } else
+ tcurr = _dl_loaded_modules;
init_fini_list = _dl_malloc(nlist * sizeof(struct elf_resolve *));
i = 0;
- for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) {
+ for (; tcurr; tcurr = tcurr->next)
init_fini_list[i++] = tcurr;
- }
/* Sort the INIT/FINI list in dependency order. */
for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) {
@@ -866,41 +1087,13 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
* functions in the dynamic linker and to relocate the interpreter
* again once all libs are loaded.
*/
- if (tpnt) {
- ElfW(Ehdr) *epnt = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_val;
- ElfW(Phdr) *myppnt = (ElfW(Phdr) *) DL_RELOC_ADDR(load_addr, epnt->e_phoff);
- int j;
-
- tpnt = _dl_add_elf_hash_table(tpnt->libname, load_addr,
- tpnt->dynamic_info,
- (unsigned long)tpnt->dynamic_addr,
- 0);
-
- if (_dl_stat(tpnt->libname, &st) >= 0) {
- tpnt->st_dev = st.st_dev;
- tpnt->st_ino = st.st_ino;
- }
- tpnt->n_phent = epnt->e_phnum;
- tpnt->ppnt = myppnt;
- for (j = 0; j < epnt->e_phnum; j++, myppnt++) {
- if (myppnt->p_type == PT_GNU_RELRO) {
- tpnt->relro_addr = myppnt->p_vaddr;
- tpnt->relro_size = myppnt->p_memsz;
- break;
- }
- }
- tpnt->libtype = program_interpreter;
+ if (!ldso_tpnt) {
+ tpnt = add_ldso(tpnt, load_addr, auxvt, rpnt);
tpnt->usage_count++;
- tpnt->symbol_scope = _dl_symbol_tables;
- if (rpnt) {
- rpnt->next = _dl_zalloc(sizeof(struct dyn_elf));
- rpnt->next->prev = rpnt;
- rpnt = rpnt->next;
- } else {
- rpnt = _dl_zalloc(sizeof(struct dyn_elf));
- }
- rpnt->dyn = tpnt;
- tpnt->rtld_flags = RTLD_NOW | RTLD_GLOBAL; /* Must not be LAZY */
+ nscope_elem++;
+ } else
+ tpnt = ldso_tpnt;
+
#ifdef RERELOCATE_LDSO
/* Only rerelocate functions for now. */
tpnt->init_flag = RELOCS_DONE;
@@ -913,16 +1106,43 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
tpnt->init_flag = RELOCS_DONE | JMP_RELOCS_DONE;
#endif
tpnt = NULL;
+
+ /*
+ * Allocate the global scope array.
+ */
+ scope_elem_list = (struct elf_resolve **) _dl_malloc(nscope_elem * sizeof(struct elf_resolve *));
+
+ for (i = 0, tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next)
+ scope_elem_list[i++] = tcurr;
+
+ _dl_loaded_modules->symbol_scope.r_list = scope_elem_list;
+ _dl_loaded_modules->symbol_scope.r_nlist = nscope_elem;
+ /*
+ * The symbol scope of the application, that is the first entry of the
+ * _dl_loaded_modules list, is just the global scope to be used for the
+ * symbol lookup.
+ */
+ global_scope = &_dl_loaded_modules->symbol_scope;
+
+ /* Build the local scope for each loaded modules. */
+ local_scope = _dl_malloc(nscope_elem * sizeof(struct elf_resolve *));
+ i = 1;
+ for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) {
+ cnt = _dl_build_local_scope(local_scope, scope_elem_list[i++]);
+ tcurr->symbol_scope.r_list = _dl_malloc(cnt * sizeof(struct elf_resolve *));
+ tcurr->symbol_scope.r_nlist = cnt;
+ _dl_memcpy (tcurr->symbol_scope.r_list, local_scope, cnt * sizeof (struct elf_resolve *));
+ /* Restoring the init_flag.*/
+ for (k = 1; k < nscope_elem; k++)
+ scope_elem_list[k]->init_flag &= ~DL_RESERVED;
}
+ _dl_free(local_scope);
+
#ifdef __LDSO_LDD_SUPPORT__
- /* End of the line for ldd.... */
- if (trace_loaded_objects) {
- _dl_dprintf(1, "\t%s => %s (%x)\n",
- rpnt->dyn->libname + _dl_strlen(_dl_ldsopath) + 1,
- rpnt->dyn->libname, DL_LOADADDR_BASE(rpnt->dyn->loadaddr));
+ /* Exit if LD_TRACE_LOADED_OBJECTS is on. */
+ if (trace_loaded_objects && !_dl_trace_prelink)
_dl_exit(0);
- }
#endif
#if defined(USE_TLS) && USE_TLS
@@ -952,6 +1172,90 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
# endif
#endif
+#ifdef __LDSO_PRELINK_SUPPORT__
+ if (_dl_trace_prelink) {
+
+ unsigned int nscope_trace = ldso_tpnt ? nscope_elem : (nscope_elem - 1);
+
+ for (i = 0; i < nscope_trace; i++)
+ trace_objects(scope_elem_list[i],
+ _dl_get_last_path_component(scope_elem_list[i]->libname));
+
+ if (_dl_verbose)
+ /* Warn about undefined symbols. */
+ if (_dl_symbol_tables)
+ if (_dl_fixup(_dl_symbol_tables, global_scope, unlazy))
+ _dl_exit(-1);
+ _dl_exit(0);
+ }
+
+ if (_dl_loaded_modules->dynamic_info[DT_GNU_LIBLIST_IDX]) {
+ ElfW(Lib) *liblist, *liblistend;
+ struct elf_resolve **r_list, **r_listend, *l;
+ const char *strtab = (const char *)_dl_loaded_modules->dynamic_info[DT_STRTAB];
+
+ _dl_assert (_dl_loaded_modules->dynamic_info[DT_GNU_LIBLISTSZ_IDX] != 0);
+ liblist = (ElfW(Lib) *) _dl_loaded_modules->dynamic_info[DT_GNU_LIBLIST_IDX];
+ liblistend = (ElfW(Lib) *)
+ ((char *) liblist + _dl_loaded_modules->dynamic_info[DT_GNU_LIBLISTSZ_IDX]);
+ r_list = _dl_loaded_modules->symbol_scope.r_list;
+ r_listend = r_list + nscope_elem;
+
+ for (; r_list < r_listend && liblist < liblistend; r_list++) {
+ l = *r_list;
+
+ if (l == _dl_loaded_modules)
+ continue;
+
+ /* If the library is not mapped where it should, fail. */
+ if (l->loadaddr)
+ break;
+
+ /* Next, check if checksum matches. */
+ if (l->dynamic_info[DT_CHECKSUM_IDX] == 0 ||
+ l->dynamic_info[DT_CHECKSUM_IDX] != liblist->l_checksum)
+ break;
+
+ if (l->dynamic_info[DT_GNU_PRELINKED_IDX] == 0 ||
+ (l->dynamic_info[DT_GNU_PRELINKED_IDX] != liblist->l_time_stamp))
+ break;
+
+ if (_dl_strcmp(strtab + liblist->l_name, _dl_get_last_path_component(l->libname)) != 0)
+ break;
+
+ ++liblist;
+ }
+
+
+ if (r_list == r_listend && liblist == liblistend)
+ prelinked = true;
+
+ }
+
+ _dl_debug_early ("\nprelink checking: %s\n", prelinked ? "ok" : "failed");
+
+ if (prelinked) {
+ if (_dl_loaded_modules->dynamic_info[DT_GNU_CONFLICT_IDX]) {
+ ELF_RELOC *conflict;
+ unsigned long conflict_size;
+
+ _dl_assert (_dl_loaded_modules->dynamic_info[DT_GNU_CONFLICTSZ_IDX] != 0);
+ conflict = (ELF_RELOC *) _dl_loaded_modules->dynamic_info[DT_GNU_CONFLICT_IDX];
+ conflict_size = _dl_loaded_modules->dynamic_info[DT_GNU_CONFLICTSZ_IDX];
+ _dl_parse_relocation_information(_dl_symbol_tables, global_scope,
+ (unsigned long) conflict, conflict_size);
+ }
+
+ /* Mark all the objects so we know they have been already relocated. */
+ for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
+ tpnt->init_flag |= RELOCS_DONE;
+ if (tpnt->relro_size)
+ _dl_protect_relro (tpnt);
+ }
+ } else
+#endif
+
+ {
_dl_debug_early("Beginning relocation fixups\n");
@@ -970,13 +1274,14 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
* order so that COPY directives work correctly.
*/
if (_dl_symbol_tables)
- if (_dl_fixup(_dl_symbol_tables, unlazy))
+ if (_dl_fixup(_dl_symbol_tables, global_scope, unlazy))
_dl_exit(-1);
for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
if (tpnt->relro_size)
_dl_protect_relro (tpnt);
}
+ } /* not prelinked */
#if defined(USE_TLS) && USE_TLS
if (!was_tls_init_tp_called && _dl_tls_max_dtv_idx > 0)
@@ -1007,7 +1312,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
* ld.so.1, so we have to look up each symbol individually.
*/
- _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "__environ", _dl_symbol_tables, NULL, 0, NULL);
+ _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "__environ", global_scope, NULL, NULL, 0, NULL);
if (_dl_envp)
*_dl_envp = (unsigned long) envp;
@@ -1063,27 +1368,34 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
/* Find the real malloc function and make ldso functions use that from now on */
_dl_malloc_function = (void* (*)(size_t)) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "malloc",
- _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+ global_scope, NULL, NULL, ELF_RTYPE_CLASS_PLT, NULL);
#if defined(USE_TLS) && USE_TLS
/* Find the real functions and make ldso functions use them from now on */
_dl_calloc_function = (void* (*)(size_t, size_t)) (intptr_t)
- _dl_find_hash(__C_SYMBOL_PREFIX__ "calloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+ _dl_find_hash(__C_SYMBOL_PREFIX__ "calloc", global_scope, NULL, NULL, ELF_RTYPE_CLASS_PLT, NULL);
_dl_realloc_function = (void* (*)(void *, size_t)) (intptr_t)
- _dl_find_hash(__C_SYMBOL_PREFIX__ "realloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+ _dl_find_hash(__C_SYMBOL_PREFIX__ "realloc", global_scope, NULL, NULL, ELF_RTYPE_CLASS_PLT, NULL);
_dl_free_function = (void (*)(void *)) (intptr_t)
- _dl_find_hash(__C_SYMBOL_PREFIX__ "free", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+ _dl_find_hash(__C_SYMBOL_PREFIX__ "free", global_scope, NULL, NULL, ELF_RTYPE_CLASS_PLT, NULL);
_dl_memalign_function = (void* (*)(size_t, size_t)) (intptr_t)
- _dl_find_hash(__C_SYMBOL_PREFIX__ "memalign", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+ _dl_find_hash(__C_SYMBOL_PREFIX__ "memalign", global_scope, NULL, NULL, ELF_RTYPE_CLASS_PLT, NULL);
#endif
/* Notify the debugger that all objects are now mapped in. */
_dl_debug_addr->r_state = RT_CONSISTENT;
_dl_debug_state();
+
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ if (_start == (void *) auxvt[AT_ENTRY].a_un.a_val)
+ return (void *) app_tpnt->l_entry;
+ else
+#endif
+ return (void *) auxvt[AT_ENTRY].a_un.a_val;
}
#include "dl-hash.c"
diff --git a/ldso/ldso/sh/elfinterp.c b/ldso/ldso/sh/elfinterp.c
index 756f6c443..928a84b40 100644
--- a/ldso/ldso/sh/elfinterp.c
+++ b/ldso/ldso/sh/elfinterp.c
@@ -69,7 +69,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
got_addr = (char **) instr_addr;
/* Get the address of the GOT entry */
- new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
+ new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, NULL, ELF_RTYPE_CLASS_PLT, NULL);
if (unlikely(!new_addr)) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
@@ -95,9 +95,9 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
static int
-_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
unsigned long rel_addr, unsigned long rel_size,
- int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
+ int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
{
unsigned int i;
@@ -148,7 +148,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
static int
-_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
+_dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
{
int reloc_type;
@@ -161,6 +161,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
#endif
struct elf_resolve *tls_tpnt = NULL;
+ struct sym_val current_value = { NULL, NULL };
reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
reloc_type = ELF32_R_TYPE(rpnt->r_info);
@@ -170,9 +171,9 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
if (symtab_index) {
symname = strtab + symtab[symtab_index].st_name;
if (ELF32_ST_VISIBILITY(symtab[symtab_index].st_other)
- != STV_PROTECTED) {
- symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
- elf_machine_type_class(reloc_type), &tls_tpnt);
+ != STV_PROTECTED) {
+ symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt, &current_value,
+ elf_machine_type_class(reloc_type), &tls_tpnt);
/*
* We want to allow undefined references to weak symbols - this might
* have been intentional. We should not be linking local symbols
@@ -183,7 +184,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
&& (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS)
&& (ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
- _dl_progname, strtab + symtab[symtab_index].st_name);
+ _dl_progname, strtab + symtab[symtab_index].st_name);
/* Let the caller to handle the error: it may be non fatal if called from dlopen */
return 1;
@@ -192,6 +193,10 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
/* Resolve protected symbols locally */
symbol_addr = DL_FIND_HASH_VALUE(tpnt, elf_machine_type_class(reloc_type),
&symtab[symtab_index]);
+
+ if (_dl_trace_prelink)
+ _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
+ &current_value, elf_machine_type_class(reloc_type));
}
#if defined (__SUPPORT_LD_DEBUG__)
@@ -257,7 +262,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
static int
-_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
{
int reloc_type;
@@ -299,7 +304,7 @@ void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
}
int _dl_parse_relocation_information(struct dyn_elf *rpnt,
- unsigned long rel_addr, unsigned long rel_size)
+ struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size)
{
- return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
+ return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
}
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index 3957e846f..3b49216d4 100644
--- a/ldso/libdl/libdl.c
+++ b/ldso/libdl/libdl.c
@@ -55,7 +55,7 @@ extern struct link_map *_dl_update_slotinfo(unsigned long int req_modid);
extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **,
struct elf_resolve *, char *, int);
-extern int _dl_fixup(struct dyn_elf *rpnt, int lazy);
+extern int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int lazy);
extern void _dl_protect_relro(struct elf_resolve * tpnt);
extern int _dl_errno;
extern struct dyn_elf *_dl_symbol_tables;
@@ -271,6 +271,21 @@ void dl_cleanup(void)
}
}
+static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list,
+ struct elf_resolve *map)
+{
+ struct elf_resolve **p = list;
+ struct init_fini_list *q;
+
+ *p++ = map;
+ map->init_flag |= DL_RESERVED;
+ if (map->init_fini)
+ for (q = map->init_fini; q; q = q->next)
+ if (! (q->tpnt->init_flag & DL_RESERVED))
+ p += _dl_build_local_scope (p, q->tpnt);
+ return p - list;
+}
+
void *dlopen(const char *libname, int flag)
{
struct elf_resolve *tpnt, *tfrom;
@@ -283,6 +298,8 @@ void *dlopen(const char *libname, int flag)
unsigned int nlist, i;
struct elf_resolve **init_fini_list;
static bool _dl_init;
+ struct elf_resolve **local_scope;
+ struct r_scope_elem *ls;
#if defined(USE_TLS) && USE_TLS
bool any_tls = false;
#endif
@@ -458,6 +475,23 @@ void *dlopen(const char *libname, int flag)
}
}
+ /* Build the local scope for the dynamically loaded modules. */
+ local_scope = _dl_malloc(nlist * sizeof(struct elf_resolve *)); /* Could it allocated on stack? */
+ for (i = 0; i < nlist; i++)
+ if (init_fini_list[i]->symbol_scope.r_nlist == 0) {
+ int k, cnt;
+ cnt = _dl_build_local_scope(local_scope, init_fini_list[i]);
+ init_fini_list[i]->symbol_scope.r_list = _dl_malloc(cnt * sizeof(struct elf_resolve *));
+ init_fini_list[i]->symbol_scope.r_nlist = cnt;
+ _dl_memcpy (init_fini_list[i]->symbol_scope.r_list, local_scope,
+ cnt * sizeof (struct elf_resolve *));
+ /* Restoring the init_flag.*/
+ for (k = 0; k < nlist; k++)
+ init_fini_list[k]->init_flag &= ~DL_RESERVED;
+ }
+
+ _dl_free(local_scope);
+
/* Sort the INIT/FINI list in dependency order. */
for (runp2 = dep_list; runp2; runp2 = runp2->next) {
unsigned int j, k;
@@ -505,8 +539,13 @@ void *dlopen(const char *libname, int flag)
*/
_dl_perform_mips_global_got_relocations(tpnt, !now_flag);
#endif
+ /* Get the tail of the list */
+ for (ls = &_dl_loaded_modules->symbol_scope; ls && ls->next; ls = ls->next);
- if (_dl_fixup(dyn_chain, now_flag))
+ /* Extend the global scope by adding the local scope of the dlopened DSO. */
+ ls->next = &dyn_chain->dyn->symbol_scope;
+
+ if (_dl_fixup(dyn_chain, &_dl_loaded_modules->symbol_scope, now_flag))
goto oops;
if (relro_ptr) {
@@ -667,7 +706,7 @@ void *dlsym(void *vhandle, const char *name)
tpnt = NULL;
if (handle == _dl_symbol_tables)
tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
- ret = _dl_find_hash(name2, handle, NULL, 0, &tls_tpnt);
+ ret = _dl_find_hash(name2, &handle->dyn->symbol_scope, NULL, NULL, 0, &tls_tpnt);
#if defined(USE_TLS) && USE_TLS && defined SHARED
if (tls_tpnt) {
@@ -708,6 +747,7 @@ static int do_dlclose(void *vhandle, int need_fini)
struct dyn_elf *handle;
unsigned int end;
unsigned int i, j;
+ struct r_scope_elem *ls;
#if defined(USE_TLS) && USE_TLS
bool any_tls = false;
size_t tls_free_start = NO_TLS_OFFSET;
@@ -873,7 +913,7 @@ static int do_dlclose(void *vhandle, int need_fini)
}
#endif
- DL_LIB_UNMAP (tpnt, end);
+ DL_LIB_UNMAP (tpnt, end - tpnt->mapaddr);
/* Free elements in RTLD_LOCAL scope list */
for (runp = tpnt->rtld_local; runp; runp = tmp) {
tmp = runp->next;
@@ -897,6 +937,16 @@ static int do_dlclose(void *vhandle, int need_fini)
}
}
+ if (handle->dyn == tpnt) {
+ /* Unlink the local scope from global one */
+ for (ls = &_dl_loaded_modules->symbol_scope; ls; ls = ls->next)
+ if (ls->next->r_list[0] == tpnt) {
+ _dl_if_debug_print("removing symbol_scope: %s\n", tpnt->libname);
+ break;
+ }
+ ls->next = ls->next->next;
+ }
+
/* Next, remove tpnt from the global symbol table list */
if (_dl_symbol_tables) {
if (_dl_symbol_tables->dyn == tpnt) {
@@ -918,6 +968,7 @@ static int do_dlclose(void *vhandle, int need_fini)
}
}
free(tpnt->libname);
+ free(tpnt->symbol_scope.r_list);
free(tpnt);
}
}
diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c
index 58f6643b2..36c0c6c63 100644
--- a/libc/misc/internals/__uClibc_main.c
+++ b/libc/misc/internals/__uClibc_main.c
@@ -153,6 +153,10 @@ extern void (*__fini_array_end []) (void) attribute_hidden;
# endif
#endif
+#if defined (__LDSO_STANDALONE_SUPPORT__) && defined (SHARED) && defined __sh__
+extern unsigned long _dl_skip_args;
+#endif
+
attribute_hidden const char *__uclibc_progname = "";
#ifdef __UCLIBC_HAS_PROGRAM_INVOCATION_NAME__
const char *program_invocation_short_name = "";
@@ -341,11 +345,23 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,
__rtld_fini = rtld_fini;
+#if defined __LDSO_STANDALONE_SUPPORT__ && defined SHARED && defined __sh__
+ /*
+ * Skip ld.so and its arguments
+ * Other archs except for SH do this in _dl_start before passing
+ * control to the application.
+ * FIXME: align SH _dl_start to other archs and remove this from here,
+ * so that we can keep the visibility hidden.
+ */
+ argc -= _dl_skip_args;
+ argv += _dl_skip_args;
+#endif
+
/* The environment begins right after argv. */
__environ = &argv[argc + 1];
/* If the first thing after argv is the arguments
- * the the environment is empty. */
+ * then the environment is empty. */
if ((char *) __environ == *argv) {
/* Make __environ point to the NULL at argv[argc] */
__environ = &argv[argc];