Skip to content

Commit

Permalink
ldso: Rework global scope handling and symbol lookup mechanism
Browse files Browse the repository at this point in the history
Global symbol scope is implemented as a linked list of
local scope, that dynamically grows and shrinks when dlopen/
dlclose are called. Each local scope is implemented as an array
of pointer to struct elf_resolve.
This will help to detect conflict when LD_TRACE_PRELINKING option
will be implemented.

Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono@st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
  • Loading branch information
Filippo Arcidiacono authored and amorosoc committed Sep 17, 2010
1 parent 637e2b2 commit 94cc6ed
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 75 deletions.
2 changes: 1 addition & 1 deletion ldso/include/dl-defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions ldso/include/dl-elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand All @@ -30,7 +31,7 @@ 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);
Expand All @@ -39,7 +40,7 @@ extern struct elf_resolve * _dl_load_elf_shared_library(int secure,
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);

/*
Expand Down
19 changes: 15 additions & 4 deletions ldso/include/dl-hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ struct dyn_elf {
struct dyn_elf * prev;
};


/* 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. */
Expand Down Expand Up @@ -65,7 +74,8 @@ struct elf_resolve {
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. */
Expand Down Expand Up @@ -132,6 +142,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;
Expand All @@ -145,15 +156,15 @@ extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
#if !((defined(USE_TLS) && USE_TLS) || defined __FDPIC__)
# define _dl_lookup_hash(n, r, m, c, t) _dl_lookup_hash(n, r, m, c)
#endif
extern char *_dl_lookup_hash(const char *name, struct dyn_elf *rpnt,
extern char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope,
struct elf_resolve *mytpnt, int type_class,
struct elf_resolve **tpntp);

static __always_inline char *_dl_find_hash(const char *name, struct dyn_elf *rpnt,
static __always_inline char *_dl_find_hash(const char *name, struct r_scope_elem *scope,
struct elf_resolve *mytpnt, int type_class,
struct elf_resolve **tpntp)
{
return _dl_lookup_hash(name, rpnt, mytpnt, type_class, tpntp);
return _dl_lookup_hash(name, scope, mytpnt, type_class, tpntp);
}

extern int _dl_linux_dynamic_link(void);
Expand Down
1 change: 1 addition & 0 deletions ldso/include/ldso.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
9 changes: 4 additions & 5 deletions ldso/ldso/dl-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,6 @@ 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;
Expand Down Expand Up @@ -846,15 +845,15 @@ 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;
ElfW(Word) reloc_size, relative_count;
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;
Expand Down Expand Up @@ -884,7 +883,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
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;
Expand All @@ -900,7 +899,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]);
}
Expand Down
83 changes: 44 additions & 39 deletions ldso/ldso/dl-hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,70 +268,75 @@ _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,
char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope, struct elf_resolve *mytpnt,
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) {
/* At this point we have found the requested symbol, do binding */
Expand Down
2 changes: 1 addition & 1 deletion ldso/ldso/dl-startup.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,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);
Expand Down
Loading

0 comments on commit 94cc6ed

Please sign in to comment.