summaryrefslogtreecommitdiff
path: root/ldso/ldso/ldso.c
diff options
context:
space:
mode:
authorFilippo Arcidiacono <filippo.arcidiacono@st.com>2010-08-02 17:23:35 +0200
committerCarmelo Amoroso <carmelo.amoroso@st.com>2010-09-17 16:13:17 +0200
commita33796043bdef5345bc00a528c942f91a87af8e9 (patch)
treed69b340439feac78601648c29efb34d9b889e5e8 /ldso/ldso/ldso.c
parent02f56b3ae9f620528c3c1bb42662b4499d19f383 (diff)
ldso: Add runtime prelink support
Added runtime prelink support to be able to run a prelinked application; at process startup only the conflicts will be relocated. This speed up the startup time. Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono@st.com> Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
Diffstat (limited to 'ldso/ldso/ldso.c')
-rw-r--r--ldso/ldso/ldso.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index 4a7b6398f..b056f8af2 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -61,6 +61,7 @@ void (*_dl_free_function) (void *p) = NULL;
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? */
@@ -1189,8 +1190,75 @@ of this helper program; chances are you did not intend to run this program.\n\
_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");
#ifdef __mips__
@@ -1215,6 +1283,7 @@ of this helper program; chances are you did not intend to run this program.\n\
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)