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.h18
-rw-r--r--ldso/include/ldso.h9
-rw-r--r--ldso/ldso/Makefile.in8
-rw-r--r--ldso/ldso/arm/elfinterp.c17
-rw-r--r--ldso/ldso/avr32/elfinterp.c15
-rw-r--r--ldso/ldso/bfin/elfinterp.c17
-rw-r--r--ldso/ldso/cris/elfinterp.c16
-rw-r--r--ldso/ldso/dl-debug.c56
-rw-r--r--ldso/ldso/dl-elf.c81
-rw-r--r--ldso/ldso/dl-hash.c88
-rw-r--r--ldso/ldso/dl-startup.c41
-rw-r--r--ldso/ldso/frv/elfinterp.c14
-rw-r--r--ldso/ldso/i386/elfinterp.c17
-rw-r--r--ldso/ldso/ldso.c462
-rw-r--r--ldso/ldso/m68k/elfinterp.c18
-rw-r--r--ldso/ldso/mips/elfinterp.c25
-rw-r--r--ldso/ldso/powerpc/elfinterp.c15
-rw-r--r--ldso/ldso/sh/elfinterp.c17
-rw-r--r--ldso/ldso/sh64/elfinterp.c17
-rw-r--r--ldso/ldso/sparc/elfinterp.c19
-rw-r--r--ldso/ldso/x86_64/elfinterp.c17
-rw-r--r--ldso/ldso/xtensa/elfinterp.c16
-rw-r--r--ldso/libdl/libdl.c61
-rw-r--r--libc/misc/internals/__uClibc_main.c18
28 files changed, 903 insertions, 268 deletions
diff --git a/Makerules b/Makerules
index f045e527f..8d60a6201 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 8628f28f6..8cbe31847 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -349,6 +349,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 be0a81da3..d387c0bb9 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 7fbb373b4..908cb63ce 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 d8b3e3ef4..c7effc588 100644
--- a/ldso/include/dl-hash.h
+++ b/ldso/include/dl-hash.h
@@ -30,6 +30,14 @@ struct symbol_ref {
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. */
@@ -65,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. */
@@ -133,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;
@@ -142,7 +156,7 @@ 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_find_hash(const char *name, struct dyn_elf *rpnt,
+extern char *_dl_find_hash(const char *name, struct r_scope_elem *scope,
struct elf_resolve *mytpnt, int type_class,
struct symbol_ref *symbol);
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 7a9ffa643..ad8edbb65 100644
--- a/ldso/ldso/Makefile.in
+++ b/ldso/ldso/Makefile.in
@@ -63,8 +63,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/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c
index 707b31743..5ae85dd2e 100644
--- a/ldso/ldso/arm/elfinterp.c
+++ b/ldso/ldso/arm/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,
+ new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope,
tpnt, ELF_RTYPE_CLASS_PLT, NULL);
if (unlikely(!new_addr)) {
_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
@@ -99,9 +99,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))
{
int i;
@@ -181,7 +181,7 @@ fix_bad_pc24 (unsigned long *const reloc_addr, unsigned long value)
#endif
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;
@@ -216,6 +216,9 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
return 1;
}
+ if (_dl_trace_prelink)
+ _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
+ &sym_ref, elf_machine_type_class(reloc_type));
def_mod = sym_ref.tpnt;
} else {
/*
@@ -308,7 +311,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;
@@ -347,8 +350,8 @@ 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/ldso/avr32/elfinterp.c b/ldso/ldso/avr32/elfinterp.c
index 2d0dbf366..c3c5b4907 100644
--- a/ldso/ldso/avr32/elfinterp.c
+++ b/ldso/ldso/avr32/elfinterp.c
@@ -51,7 +51,8 @@ unsigned long _dl_linux_resolver(unsigned long got_offset, unsigned long *got)
symname = strtab + sym->st_name;
new_addr = (unsigned long) _dl_find_hash(symname,
- tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
+ &_dl_loaded_modules->symbol_scope, tpnt,
+ ELF_RTYPE_CLASS_PLT, NULL);
entry = (unsigned long *)(got + local_gotno + sym_index - gotsym);
*entry = new_addr;
@@ -62,9 +63,9 @@ unsigned long _dl_linux_resolver(unsigned long got_offset, unsigned long *got)
}
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_func)(struct elf_resolve *tpnt, struct dyn_elf *scope,
+ int (*reloc_func)(struct elf_resolve *tpnt, struct r_scope_elem *scope,
Elf32_Rela *rpnt, Elf32_Sym *symtab, char *strtab))
{
Elf32_Sym *symtab;
@@ -115,7 +116,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
return 0;
}
-static int _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
+static int _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
Elf32_Rela *rpnt, Elf32_Sym *symtab, char *strtab)
{
int reloc_type;
@@ -148,6 +149,9 @@ static int _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
_dl_progname, symname);
return 0;
}
+ if (_dl_trace_prelink)
+ _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
+ &sym_ref, elf_machine_type_class(reloc_type));
}
#if defined(__SUPPORT_LD_DEBUG__)
@@ -186,9 +190,10 @@ void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
}
int _dl_parse_relocation_information(struct dyn_elf *rpnt,
+ 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,
+ return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size,
_dl_do_reloc);
}
diff --git a/ldso/ldso/bfin/elfinterp.c b/ldso/ldso/bfin/elfinterp.c
index 48470d50b..42c113c50 100644
--- a/ldso/ldso/bfin/elfinterp.c
+++ b/ldso/ldso/bfin/elfinterp.c
@@ -67,7 +67,7 @@ _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
got_entry = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
/* Get the address to be used to fill in the GOT entry. */
- new_addr = _dl_find_hash(symname, tpnt->symbol_scope, NULL, 0, &sym_ref);
+ new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, NULL, 0, &sym_ref);
if (!new_addr) {
new_addr = _dl_find_hash(symname, NULL, NULL, 0, &sym_ref);
if (!new_addr) {
@@ -101,9 +101,9 @@ _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, ElfW(Sym) *symtab, char *strtab))
{
unsigned int i;
@@ -152,7 +152,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, ElfW(Sym) *symtab, char *strtab)
{
int reloc_type;
@@ -197,6 +197,9 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
_dl_progname, symname);
_dl_exit (1);
}
+ if (_dl_trace_prelink)
+ _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
+ &sym_ref, elf_machine_type_class(reloc_type));
symbol_tpnt = sym_ref.tpnt;
}
@@ -281,7 +284,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 __attribute__((unused)),
+ struct r_scope_elem *scope __attribute__((unused)),
ELF_RELOC *rpnt, ElfW(Sym) *symtab __attribute__((unused)),
char *strtab __attribute__((unused)))
{
@@ -327,9 +330,9 @@ _dl_parse_lazy_relocation_information
int
_dl_parse_relocation_information
-(struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
+(struct dyn_elf *rpnt, 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);
}
/* We don't have copy relocs. */
diff --git a/ldso/ldso/cris/elfinterp.c b/ldso/ldso/cris/elfinterp.c
index 3cb8297e1..c3af90b99 100644
--- a/ldso/ldso/cris/elfinterp.c
+++ b/ldso/ldso/cris/elfinterp.c
@@ -66,7 +66,7 @@ _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, ELF_RTYPE_CLASS_PLT, NULL);
if (unlikely(!new_addr)) {
_dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname, symname);
_dl_exit(1);
@@ -91,9 +91,9 @@ _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))
{
int symtab_index;
@@ -150,7 +150,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;
@@ -186,6 +186,9 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
}
symbol_addr += rpnt->r_addend;
+ if (_dl_trace_prelink)
+ _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
+ &sym_ref, elf_machine_type_class(reloc_type));
}
#if defined (__SUPPORT_LD_DEBUG__)
@@ -230,7 +233,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;
@@ -282,8 +285,9 @@ _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
int
_dl_parse_relocation_information(struct dyn_elf *rpnt,
+ 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/ldso/dl-debug.c b/ldso/ldso/dl-debug.c
index 7ce8bfbce..1758bc387 100644
--- a/ldso/ldso/dl-debug.c
+++ b/ldso/ldso/dl-debug.c
@@ -104,3 +104,59 @@ 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 symbol_ref *value, int type_class)
+{
+#ifdef SHARED
+ unsigned long symbol_addr;
+
+ if (_dl_trace_prelink)
+ {
+ int conflict = 0;
+ struct symbol_ref val = { ref, 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, type_class, &val);
+
+ if (val.sym != value->sym || val.tpnt != value->tpnt)
+ conflict = 1;
+ }
+
+ if (value->sym
+ && (__builtin_expect (ELF_ST_TYPE(value->sym->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->tpnt ? value->tpnt->mapaddr : 0),
+ (size_t) (value->sym ? value->sym->st_value : 0));
+ if (conflict)
+ _dl_dprintf (1, "x %x %x ",
+ (size_t) (val.tpnt ? val.tpnt->mapaddr : 0),
+ (size_t) (val.sym ? val.sym->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 505247e6f..a881b7df7 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 & ~ADDR_ALIGN;
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;