summaryrefslogtreecommitdiff
path: root/ldso/ldso/ldso.c
diff options
context:
space:
mode:
authorFilippo Arcidiacono <filippo.arcidiacono@st.com>2009-07-31 14:56:38 +0200
committerCarmelo Amoroso <carmelo.amoroso@st.com>2010-09-17 13:06:58 +0200
commit637e2b2440f69e22932edd71bd2f0b1210dc32ea (patch)
tree24d396c7f3730ad50426bfffcd113186265d18b2 /ldso/ldso/ldso.c
parentef65e97083363ffaeeb5fcf3a37d074b74eafb0d (diff)
ldso: Add implementation of ld.so standalone execution
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 whole system. Currently supported option: --library-path PATH use given PATH instead of content of the environment variable LD_LIBRARY_PATH (Mandatory for prelinking) Not supported options: --list list all dependencies and how they are resolved --verify verify that given object really is a dynamically linked object we can handle --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names in LIST This feature can be enabled by setting LDSO_STANDALONE_SUPPORT=y 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.c128
1 files changed, 123 insertions, 5 deletions
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index ea4ad0f1c..bb394714f 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -70,8 +70,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"
@@ -274,9 +284,8 @@ 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
+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;
@@ -327,10 +336,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 +393,102 @@ 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;
+
+ if (app_tpnt->libtype == elf_executable)
+ app_tpnt->loadaddr = 0;
+
+ /*
+ * 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
@@ -538,6 +645,10 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
}
#endif
+#ifdef __LDSO_STANDALONE_SUPPORT__
+ } /* ! ldso standalone mode */
+#endif
+
#ifdef __SUPPORT_LD_DEBUG__
_dl_debug = _dl_getenv("LD_DEBUG", envp);
if (_dl_debug) {
@@ -1084,6 +1195,13 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
/* 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"