aboutsummaryrefslogtreecommitdiffstats
path: root/src/rtld/rtld.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rtld/rtld.c')
-rw-r--r--src/rtld/rtld.c1425
1 files changed, 1425 insertions, 0 deletions
diff --git a/src/rtld/rtld.c b/src/rtld/rtld.c
new file mode 100644
index 0000000..82ba4b2
--- /dev/null
+++ b/src/rtld/rtld.c
@@ -0,0 +1,1425 @@
+/* Copyright (C) 2003 MontaVista Software, Inc.
+ Written by Daniel Jacobowitz <drow@mvista.com>, 2003
+
+ Copyright (C) 2011 Wind River Systems, Inc.
+ Significantly updated by Mark Hatle <mark.hatle@windriver.com>, 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <ctype.h>
+#include <error.h>
+#include <errno.h>
+#include <argp.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#include <inttypes.h>
+
+#include "prelinktab.h"
+#include "reloc.h"
+#include "reloc-info.h"
+
+#include "rtld.h"
+
+unsigned int static_binary = 0;
+
+unsigned int _dl_debug_mask = 0;
+
+/* LD_DYNAMIC_WEAK option. Default is off, changing to 1
+ is equivalent to setting LD_DYNAMIC_WEAK. */
+unsigned int _dl_dynamic_weak = 0;
+#define MAX_PRELOADED_LIBS 20
+
+struct search_path
+{
+ int maxlen, count, allocated;
+ char **dirs;
+};
+
+struct search_path ld_dirs, ld_library_search_path;
+int host_paths;
+
+char * dst_ORIGIN;
+char * dst_PLATFORM = ""; /* undefined */
+char * dst_LIB = "lib";
+char * ld_preload = NULL;
+
+
+void string_to_path (struct search_path *path, const char *string);
+
+const char *argp_program_version = PRELINK_RTLD_PROG PKGVERSION " 1.0";
+
+const char *argp_program_bug_address = REPORT_BUGS_TO;
+
+static char argp_doc[] = PRELINK_RTLD_PROG " -- program to simulate the runtime linker";
+
+#define OPT_SYSROOT 0x8c
+#define OPT_LIBRARY_PATH 0x8e
+#define OPT_TARGET_PATHS 0x8f
+#define OPT_LD_PRELOAD 0x90
+
+static struct argp_option options[] = {
+ {"library-path", OPT_LIBRARY_PATH, "LIBRARY_PATH", 0, "Set library search path to LIBRARY_PATH" },
+ {"root", OPT_SYSROOT, "ROOT_PATH", 0, "Prefix all paths with ROOT_PATH" },
+ {"target-paths", OPT_TARGET_PATHS, 0, 0, "Specified paths are based on ROOT_PATH" },
+ {"ld-preload", OPT_LD_PRELOAD, "PATHLIST", 0, "List of LD_PRELOAD libraries"},
+ { 0 }
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case OPT_SYSROOT:
+ sysroot = arg;
+ break;
+ case OPT_LIBRARY_PATH:
+ string_to_path(&ld_library_search_path, arg);
+ break;
+ case OPT_TARGET_PATHS:
+ host_paths = 0;
+ break;
+ case OPT_LD_PRELOAD:
+ ld_preload = arg;
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* This function returns the same constants expected by glibc's
+ symbol lookup routines. This is slightly different from the
+ equivalent routines in prelink. It should return PLT for any
+ relocation where an undefined symbol in the application should
+ be ignored: typically, this means any jump slot or TLS relocations,
+ but not copy relocations. Don't return the prelinker's
+ RTYPE_CLASS_TLS. */
+
+/* The following needs to be kept in sync with the
+ sysdeps/.../dl-machine.h: elf_machine_type_class macro */
+
+/* From glibc-2.22: sysdeps/i386/dl-machine.h */
+# define i386_elf_machine_type_class(type) \
+ ((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32 \
+ || (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32 \
+ || (type) == R_386_TLS_TPOFF || (type) == R_386_TLS_DESC) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_386_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_386)))
+
+/* From glibc-2.22: sysdeps/x86_64/dl-machine.h */
+# define x86_64_elf_machine_type_class(type) \
+ ((((type) == R_X86_64_JUMP_SLOT \
+ || (type) == R_X86_64_DTPMOD64 \
+ || (type) == R_X86_64_DTPOFF64 \
+ || (type) == R_X86_64_TPOFF64 \
+ || (type) == R_X86_64_TLSDESC) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_X86_64_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_X86_64_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_X86_64)))
+
+/* From glibc-2.22: ports/sysdeps/arm/dl-machine.h */
+# define arm_elf_machine_type_class(type) \
+ ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32 \
+ || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32 \
+ || (type) == R_ARM_TLS_DESC) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_ARM_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_ARM)))
+
+/* From glibc-2.22: ports/sysdeps/aarch64/dl-machine.h */
+# define aarch64_elf_machine_type_class(type) \
+ ((((type) == R_AARCH64_JUMP_SLOT || \
+ (type) == R_AARCH64_TLS_DTPMOD || \
+ (type) == R_AARCH64_TLS_DTPREL || \
+ (type) == R_AARCH64_TLS_TPREL || \
+ (type) == R_AARCH64_TLSDESC) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_AARCH64_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_AARCH64)))
+
+/* From glibc-2.22: sysdeps/sh/dl-machine.h */
+# define sh_elf_machine_type_class(type) \
+ ((((type) == R_SH_JMP_SLOT || (type) == R_SH_TLS_DTPMOD32 \
+ || (type) == R_SH_TLS_DTPOFF32 || (type) == R_SH_TLS_TPOFF32) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/powerpc/powerpc32/dl-machine.h */
+#define powerpc32_elf_machine_type_class(type) \
+ ((((type) == R_PPC_JMP_SLOT \
+ || (type) == R_PPC_REL24 \
+ || ((type) >= R_PPC_DTPMOD32 /* contiguous TLS */ \
+ && (type) <= R_PPC_DTPREL32) \
+ || (type) == R_PPC_ADDR24) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_PPC_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/powerpc/powerpc64/dl-machine.h */
+/* we only support ELFv2 at this point */
+#define IS_PPC64_TLS_RELOC(R) \
+ (((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) \
+ || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA))
+
+#define powerpc64_elf_machine_type_class(type) \
+ ((((type) == R_PPC64_JMP_SLOT \
+ || (type) == R_PPC64_ADDR24 \
+ || IS_PPC64_TLS_RELOC (type)) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/mips/dl-machine.h */
+#define ELF_MACHINE_JMP_SLOT R_MIPS_JUMP_SLOT
+#define mips_elf_machine_type_class(type) \
+ ((((type) == ELF_MACHINE_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/sparc/sparc32/dl-machine.h */
+#define sparc_elf_machine_type_class(type) \
+ ((((type) == R_SPARC_JMP_SLOT \
+ || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64)) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/sparc/sparc64/dl-machine.h */
+# define sparc64_elf_machine_type_class(type) \
+ ((((type) == R_SPARC_JMP_SLOT \
+ || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64)) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/nios2/dl-machine.h */
+# define nios2_elf_machine_type_class(type) \
+ ((((type) == R_NIOS2_JUMP_SLOT \
+ || (type) == R_NIOS2_TLS_DTPMOD \
+ || (type) == R_NIOS2_TLS_DTPREL \
+ || (type) == R_NIOS2_TLS_TPREL) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_NIOS2_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_NIOS2_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_ALTERA_NIOS2)))
+
+int
+elf_machine_type_class (int type, int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ return i386_elf_machine_type_class(type);
+ case EM_X86_64:
+ return x86_64_elf_machine_type_class(type);
+ case EM_ARM:
+ return arm_elf_machine_type_class(type);
+ case EM_AARCH64:
+ return aarch64_elf_machine_type_class(type);
+ case EM_SH:
+ return sh_elf_machine_type_class(type);
+ case EM_PPC:
+ return powerpc32_elf_machine_type_class(type);
+ case EM_PPC64:
+ return powerpc64_elf_machine_type_class(type);
+ case EM_MIPS:
+ return mips_elf_machine_type_class(type);
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ return sparc_elf_machine_type_class(type);
+ case EM_SPARCV9:
+ return sparc64_elf_machine_type_class(type);
+ case EM_ALTERA_NIOS2:
+ return nios2_elf_machine_type_class(type);
+
+ default:
+ printf ("Unknown architecture!\n");
+ exit (1);
+ return 0;
+ }
+}
+
+int
+extern_protected_data(int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ case EM_X86_64:
+ case EM_ARM:
+ case EM_AARCH64:
+ case EM_ALTERA_NIOS2:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+int
+machine_no_rela (int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ case EM_X86_64:
+ case EM_ARM:
+ case EM_AARCH64:
+ case EM_SH:
+ case EM_PPC:
+ case EM_PPC64:
+ case EM_MIPS:
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ case EM_ALTERA_NIOS2:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+int
+machine_no_rel (int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ case EM_MIPS:
+ case EM_ARM:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+int
+is_ldso_soname (const char *soname)
+{
+ if ( ! strcmp (soname, "ld-linux.so.2")
+ || ! strcmp (soname, "ld-linux.so.3")
+ || ! strcmp (soname, "ld.so.1")
+ || ! strcmp (soname, "ld-linux-ia64.so.2")
+ || ! strcmp (soname, "ld-linux-x86-64.so.2")
+ || ! strcmp (soname, "ld64.so.2")
+ || ! strcmp (soname, "ld-linux-armhf.so.3")
+ || ! strcmp (soname, "ld-linux-aarch64.so.1")
+ || ! strcmp (soname, "ld-linux-aarch64_be.so.1")
+ || ! strcmp (soname, "ld-linux-nios2.so.1")
+ )
+ return 1;
+ return 0;
+}
+
+static int dso_open_error = 0;
+
+static void
+free_needed (struct needed_list *p)
+{
+ struct needed_list *old_p = p;
+ while (old_p)
+ {
+ old_p = p->next;
+ free (p);
+ p = old_p;
+ }
+}
+
+static struct dso_list *
+in_dso_list (struct dso_list *dso_list, const char *soname, const char *filename)
+{
+ while (dso_list != NULL)
+ {
+ if (dso_list->dso != NULL)
+ {
+ if (strcmp (dso_list->dso->soname, soname) == 0)
+ return dso_list;
+ }
+
+ if (strcmp (dso_list->name, soname) == 0)
+ return dso_list;
+
+ if (filename && dso_list->canon_filename
+ && strcmp (dso_list->canon_filename, filename) == 0)
+ return dso_list;
+
+ dso_list = dso_list->next;
+ }
+ return NULL;
+}
+
+static int
+in_needed_list (struct needed_list *needed_list, const char *soname)
+{
+ while (needed_list != NULL)
+ {
+ if (needed_list->ent->dso != NULL
+ && strcmp (needed_list->ent->dso->soname, soname) == 0)
+ return 1;
+ needed_list = needed_list->next;
+ }
+ return 0;
+}
+
+
+/****/
+
+void
+add_dir (struct search_path *path, const char *dir, int dirlen)
+{
+ if (path->allocated == 0)
+ {
+ path->allocated = 5;
+ path->dirs = malloc (sizeof (char *) * 5);
+ }
+ else if (path->count == path->allocated)
+ {
+ path->allocated *= 2;
+ path->dirs = realloc (path->dirs, sizeof (char *) * path->allocated);
+ }
+ path->dirs[path->count] = malloc (dirlen + 1);
+ memcpy (path->dirs[path->count], dir, dirlen);
+ path->dirs[path->count++][dirlen] = 0;
+
+ if (path->maxlen < dirlen)
+ path->maxlen = dirlen;
+}
+
+void
+free_path (struct search_path *path)
+{
+ if (path->allocated)
+ {
+ int i;
+ for (i = 0; i < path->count; i++)
+ free (path->dirs[i]);
+ free (path->dirs);
+ }
+}
+
+void
+load_ld_so_conf (int use_64bit, int use_mipsn32)
+{
+ int fd;
+ FILE *conf;
+ char buf[1024];
+
+ memset (&ld_dirs, 0, sizeof (ld_dirs));
+
+ /* Only use the correct machine, to prevent mismatches if we
+ have both /lib/ld.so and /lib64/ld.so on x86-64. */
+ if (use_64bit)
+ {
+ dst_LIB = "lib64";
+ add_dir (&ld_dirs, "/lib64/tls", strlen ("/lib64/tls"));
+ add_dir (&ld_dirs, "/lib64", strlen ("/lib64"));
+ add_dir (&ld_dirs, "/usr/lib64/tls", strlen ("/usr/lib64/tls"));
+ add_dir (&ld_dirs, "/usr/lib64", strlen ("/usr/lib64"));
+ }
+ else if (use_mipsn32)
+ {
+ dst_LIB = "lib32";
+ add_dir (&ld_dirs, "/lib32/tls", strlen ("/lib32/tls"));
+ add_dir (&ld_dirs, "/lib32", strlen ("/lib32"));
+ add_dir (&ld_dirs, "/usr/lib32/tls", strlen ("/usr/lib32/tls"));
+ add_dir (&ld_dirs, "/usr/lib32", strlen ("/usr/lib32"));
+ }
+ else
+ {
+ dst_LIB = "lib";
+ add_dir (&ld_dirs, "/lib/tls", strlen ("/lib/tls"));
+ add_dir (&ld_dirs, "/lib", strlen ("/lib"));
+ add_dir (&ld_dirs, "/usr/lib/tls", strlen ("/usr/lib/tls"));
+ add_dir (&ld_dirs, "/usr/lib", strlen ("/usr/lib"));
+ }
+
+ fd = wrap_open ("/etc/ld.so.conf", O_RDONLY);
+ if (fd == -1)
+ return;
+ conf = fdopen (fd, "r");
+ while (fgets (buf, 1024, conf) != NULL)
+ {
+ int len;
+ char *p;
+
+ p = strchr (buf, '#');
+ if (p)
+ *p = 0;
+ len = strlen (buf);
+ while (len > 0 && isspace (buf[len - 1]))
+ buf[--len] = 0;
+
+ if (len > 0)
+ add_dir (&ld_dirs, buf, len);
+ }
+ fclose (conf);
+}
+
+void
+string_to_path (struct search_path *path, const char *string)
+{
+ const char *start, *end, *end_tmp;
+
+ start = string;
+ while (1) {
+ end = start;
+ while (*end && *end != ':' && *end != ';')
+ end ++;
+
+ /* Eliminate any trailing '/' characters, but be sure to leave a
+ leading slash if someeone wants / in their RPATH. */
+ end_tmp = end;
+ while (end_tmp > start + 1 && end_tmp[-1] == '/')
+ end_tmp --;
+
+ add_dir (path, start, end_tmp - start);
+
+ if (*end == 0)
+ break;
+
+ /* Skip the separator. */
+ start = end + 1;
+ }
+}
+
+char *
+find_lib_in_path (struct search_path *path, const char *soname,
+ int elfclass, int machine)
+{
+ char *ret = NULL;
+ int i;
+ int alt_machine;
+
+ switch (machine)
+ {
+ case EM_SPARC:
+ alt_machine = EM_SPARC32PLUS;
+ break;
+ case EM_SPARC32PLUS:
+ alt_machine = EM_SPARC;
+ break;
+ default:
+ alt_machine = machine;
+ break;
+ }
+
+ for (i = 0; i < path->count; i++)
+ {
+ char * fixup_path, * path_string;
+
+ path_string = fixup_path = strdup(path->dirs[i]);
+
+ while ((path_string = strchr (path_string, '$')))
+ {
+ char * replace = NULL;
+ size_t len = 0;
+
+ if (strncmp("$ORIGIN", path_string, 7) == 0) {
+ replace = dst_ORIGIN;
+ len = 7;
+ } else if (strncmp("${ORIGIN}", path_string, 9) == 0) {
+ replace = dst_ORIGIN;
+ len = 9;
+ } else if (strncmp("$PLATFORM", path_string, 9) == 0) {
+ replace = dst_PLATFORM;
+ len = 9;
+ } else if (strncmp("${PLATFORM}", path_string, 11) == 0) {
+ replace = dst_PLATFORM;
+ len = 11;
+ } else if (strncmp("$LIB", path_string, 4) == 0) {
+ replace = dst_LIB;
+ len = 4;
+ } else if (strncmp("${LIB}", path_string, 6) == 0) {
+ replace = dst_LIB;
+ len = 6;
+ } else {
+ /* Not a defined item, so we skip to the next character */
+ path_string += 1;
+ }
+
+ if (replace) {
+ size_t new_path_len = strlen(fixup_path) - len + strlen(replace) + 1;
+ char * new_path = malloc(new_path_len);
+
+ /* Calculate the new path_string position based on the old position */
+ size_t new_path_pos = (path_string - fixup_path) + strlen(replace);
+
+ snprintf(new_path, new_path_len, "%.*s%s%s", (int)(path_string-fixup_path),
+ fixup_path, replace, path_string + len);
+
+ free(fixup_path);
+
+ fixup_path = new_path;
+ path_string = fixup_path + new_path_pos;
+ }
+ }
+
+ ret = malloc (strlen (soname) + 2 + strlen(fixup_path));
+ sprintf (ret, "%s/%s", fixup_path, soname);
+
+ if (wrap_access (ret, F_OK) == 0)
+ {
+ DSO *dso = open_dso (ret);
+ int dso_class, dso_machine;
+
+ if (dso == NULL)
+ continue;
+
+ dso_class = gelf_getclass (dso->elf);
+ dso_machine = (dso_class == ELFCLASS32) ?
+ elf32_getehdr (dso->elf)->e_machine :
+ elf64_getehdr (dso->elf)->e_machine;
+
+ /* Skip 32-bit libraries when looking for 64-bit. Also
+ skip libraries for alternative machines. */
+ if (gelf_getclass (dso->elf) != elfclass
+ || (dso_machine != machine && dso_machine != alt_machine))
+ {
+ close_dso (dso);
+ continue;
+ }
+
+ close_dso (dso);
+ return ret;
+ }
+ }
+
+ free (ret);
+ return NULL;
+}
+
+char *
+find_lib_by_soname (const char *soname, struct dso_list *loader,
+ int elfclass, int machine)
+{
+ char *ret;
+
+ if (strchr (soname, '/'))
+ return strdup (soname);
+
+ if (is_ldso_soname (soname))
+ /* For dynamic linker, pull the path out of PT_INTERP header.
+ When loading an executable the dynamic linker creates an entry for
+ itself under the name stored in PT_INTERP, and the name that we
+ record in .gnu.liblist should match that exactly. */
+ {
+ struct dso_list *loader_p = loader;
+
+ while (loader_p)
+ {
+ if (loader_p->dso->ehdr.e_type == ET_EXEC)
+ {
+ int i;
+
+ for (i = 0; i < loader_p->dso->ehdr.e_phnum; ++i)
+ if (loader_p->dso->phdr[i].p_type == PT_INTERP)
+ {
+ const char *interp;
+ interp = get_data (loader_p->dso,
+ loader_p->dso->phdr[i].p_vaddr,
+ NULL, NULL);
+ return strdup (interp);
+ }
+ }
+ loader_p = loader_p->loader;
+ }
+ }
+
+ if (loader->dso->info[DT_RUNPATH] == 0)
+ {
+ /* Search DT_RPATH all the way up. */
+ struct dso_list *loader_p = loader;
+ while (loader_p)
+ {
+ if (loader_p->dso->info[DT_RPATH])
+ {
+ struct search_path r_path;
+ const char *rpath = get_data (loader_p->dso,
+ loader_p->dso->info[DT_STRTAB]
+ + loader_p->dso->info[DT_RPATH],
+ NULL, NULL);
+ memset (&r_path, 0, sizeof (r_path));
+ string_to_path (&r_path, rpath);
+ ret = find_lib_in_path (&r_path, soname, elfclass, machine);
+ free_path (&r_path);
+ if (ret)
+ return ret;
+ }
+ loader_p = loader_p->loader;
+ }
+ }
+
+ ret = find_lib_in_path (&ld_library_search_path, soname, elfclass, machine);
+ if (ret)
+ return ret;
+
+ if (loader->dso->info[DT_RUNPATH])
+ {
+ struct search_path r_path;
+ const char *rpath = get_data (loader->dso,
+ loader->dso->info[DT_STRTAB]
+ + loader->dso->info[DT_RUNPATH],
+ NULL, NULL);
+ memset (&r_path, 0, sizeof (r_path));
+ string_to_path (&r_path, rpath);
+ ret = find_lib_in_path (&r_path, soname, elfclass, machine);
+ free_path (&r_path);
+ if (ret)
+ return ret;
+ }
+
+ ret = find_lib_in_path (&ld_dirs, soname, elfclass, machine);
+ if (ret)
+ return ret;
+
+ return NULL;
+}
+
+static struct dso_list *
+load_dsos (DSO *dso, int host_paths)
+{
+ struct dso_list *dso_list, *dso_list_tail, *cur_dso_ent, *new_dso_ent;
+ struct stat64 st;
+ int total_preload = 0;
+ char * libname[MAX_PRELOADED_LIBS] = {NULL};
+
+ /* Assume it's static unless we find DT_NEEDED entries */
+ static_binary = 1;
+
+ dso_list = malloc (sizeof (struct dso_list));
+ dso_list->dso = dso;
+ dso_list->map = NULL;
+ dso_list->next = NULL;
+ dso_list->prev = NULL;
+ dso_list->needed = NULL;
+ dso_list->name = dso->filename;
+ dso_list->loader = NULL;
+
+ if (host_paths)
+ dso_list->canon_filename = canonicalize_file_name (dso->filename);
+ else
+ dso_list->canon_filename = prelink_canonicalize (dso->filename, &st);
+
+ if (dso_list->canon_filename == NULL)
+ dso_list->canon_filename = strdup (dso->filename);
+
+ cur_dso_ent = dso_list_tail = dso_list;
+
+ if(dso->ehdr.e_type == ET_EXEC && ld_preload) {
+ char *next_lib = ld_preload;
+ libname[total_preload] = ld_preload;
+ total_preload++;
+ next_lib=strchr(ld_preload,':');
+ while(next_lib!=NULL){
+ *next_lib = '\0';
+ next_lib++;
+ libname[total_preload] = next_lib;
+ total_preload++;
+ next_lib=strchr(next_lib,':');
+ }
+ }
+ else {
+ total_preload = 0;
+ }
+ while (cur_dso_ent != NULL)
+ {
+ DSO *cur_dso, *new_dso;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Dyn dyn;
+
+ cur_dso = cur_dso_ent->dso;
+ if (cur_dso == NULL)
+ {
+ cur_dso_ent = cur_dso_ent->next;
+ continue;
+ }
+
+ scn = cur_dso->scn[cur_dso->dynamic];
+ data = NULL;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+ maxndx = data->d_size / cur_dso->shdr[cur_dso->dynamic].sh_entsize;
+ for (ndx = 0; ndx < maxndx + total_preload; ++ndx)
+ {
+
+ if(ndx - total_preload >= 0) {
+ gelfx_getdyn (cur_dso->elf, data, ndx - total_preload, &dyn);
+ }
+ else {
+ dyn.d_tag = DT_NEEDED;
+ }
+
+ if (dyn.d_tag == DT_NULL)
+ break;
+ if (dyn.d_tag == DT_NEEDED)
+ {
+ /* Not static... */
+ static_binary = 0;
+
+ char *new_name=NULL, *new_canon_name=NULL;
+ const char * soname = NULL;
+ if(ndx - total_preload >= 0) {
+ soname = get_data (cur_dso,
+ cur_dso->info[DT_STRTAB]
+ + dyn.d_un.d_val,
+ NULL, NULL);
+ }
+ else {
+ soname = libname[ndx];
+ }
+
+ new_dso_ent = in_dso_list (dso_list, soname, NULL);
+ if (new_dso_ent == NULL)
+ {
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
+ _dl_debug_printf ("file=%s [0]; needed by %s [0]\n",
+ soname, cur_dso->filename);
+
+ int machine;
+ int class = gelf_getclass (dso->elf);
+ machine = (class == ELFCLASS32) ?
+ elf32_getehdr (dso->elf)->e_machine :
+ elf64_getehdr (dso->elf)->e_machine;
+ new_name = find_lib_by_soname (soname, cur_dso_ent,
+ class, machine);
+ if (new_name == 0 || wrap_access (new_name, R_OK) < 0)
+ {
+ dso_open_error ++;
+
+ new_dso_ent = malloc (sizeof (struct dso_list));
+ dso_list_tail->next = new_dso_ent;
+ dso_list_tail->next->prev = dso_list_tail;
+ dso_list_tail = dso_list_tail->next;
+ dso_list_tail->next = NULL;
+ dso_list_tail->dso = NULL;
+ dso_list_tail->map = NULL;
+ dso_list_tail->needed = NULL;
+ dso_list_tail->name = soname;
+ dso_list_tail->loader = NULL;
+ dso_list_tail->canon_filename = strdup(soname);
+ dso_list_tail->err_no = errno;
+
+ continue;
+ }
+
+ /* See if the filename we found has already been
+ opened (possibly under a different SONAME via
+ some symlink). */
+ new_canon_name = prelink_canonicalize (new_name, NULL);
+ if (new_canon_name == NULL)
+ new_canon_name = strdup (new_name);
+ new_dso_ent = in_dso_list (dso_list, soname, new_canon_name);
+ }
+ else if (new_dso_ent->dso == NULL)
+ continue;
+
+ if (new_dso_ent == NULL)
+ {
+ new_dso = open_dso (new_name);
+ free (new_name);
+ new_dso_ent = malloc (sizeof (struct dso_list));
+ dso_list_tail->next = new_dso_ent;
+ dso_list_tail->next->prev = dso_list_tail;
+ dso_list_tail = dso_list_tail->next;
+ dso_list_tail->next = NULL;
+ dso_list_tail->dso = new_dso;
+ dso_list_tail->map = NULL;
+ dso_list_tail->needed = NULL;
+ dso_list_tail->loader = cur_dso_ent;
+ dso_list_tail->canon_filename = new_canon_name;
+ dso_list_tail->err_no = 0;
+
+ if (is_ldso_soname (new_dso->soname))
+ dso_list_tail->name = new_dso->filename;
+ else if (strcmp (new_dso->soname, new_dso->filename) == 0)
+ /* new_dso->soname might be a full path if the library
+ had no SONAME. Use the original SONAME instead. */
+ dso_list_tail->name = soname;
+ else
+ /* Use the new SONAME if possible, in case some library
+ links to this one using an incorrect SONAME. */
+ dso_list_tail->name = new_dso->soname;
+ }
+
+ if (!cur_dso_ent->needed)
+ {
+ cur_dso_ent->needed = malloc (sizeof (struct needed_list));
+ cur_dso_ent->needed_tail = cur_dso_ent->needed;
+ cur_dso_ent->needed_tail->ent = new_dso_ent;
+ cur_dso_ent->needed_tail->next = NULL;
+ }
+ else if (!in_needed_list (cur_dso_ent->needed, soname))
+ {
+ cur_dso_ent->needed_tail->next = malloc (sizeof (struct needed_list));
+ cur_dso_ent->needed_tail = cur_dso_ent->needed_tail->next;
+ cur_dso_ent->needed_tail->ent = new_dso_ent;
+ cur_dso_ent->needed_tail->next = NULL;
+ }
+
+ continue;
+ }
+ if (dyn.d_tag == DT_FILTER || dyn.d_tag == DT_AUXILIARY)
+ {
+ // big fat warning;
+ }
+ }
+ }
+ cur_dso_ent = cur_dso_ent->next;
+ }
+ return dso_list;
+}
+
+struct
+{
+ void *symptr;
+ int rtypeclass;
+} cache;
+
+void
+do_reloc (DSO *dso, struct link_map *map, struct r_scope_elem *scope[],
+ GElf_Word sym, GElf_Word type)
+{
+ struct r_found_version *ver;
+ int rtypeclass;
+ void *symptr;
+ const char *name;
+ Elf64_Word st_name;
+
+ if (map->l_versyms)
+ {
+ int vernum = map->l_versyms[sym] & 0x7fff;
+ ver = &map->l_versions[vernum];
+
+ /* Memory was allocated for the hash table, but it's empty! */
+ if (ver && (ver->name == NULL || ver->hash == 0))
+ ver = NULL;
+ }
+ else
+ ver = NULL;
+
+ rtypeclass = elf_machine_type_class (type, dso->ehdr.e_machine);
+
+ if (gelf_getclass (dso->elf) == ELFCLASS32)
+ {
+ Elf32_Sym *sym32 = &((Elf32_Sym *)map->l_info[DT_SYMTAB])[sym];
+
+ if (ELF32_ST_BIND (sym32->st_info) == STB_LOCAL)
+ return;
+ symptr = sym32;
+ st_name = sym32->st_name;
+ }
+ else
+ {
+ Elf64_Sym *sym64 = &((Elf64_Sym *)map->l_info[DT_SYMTAB])[sym];
+
+ if (ELF64_ST_BIND (sym64->st_info) == STB_LOCAL)
+ return;
+ symptr = sym64;
+ st_name = sym64->st_name;
+ }
+
+ if (cache.symptr == symptr && cache.rtypeclass == rtypeclass)
+ return;
+ cache.symptr = symptr;
+ cache.rtypeclass = rtypeclass;
+
+ name = ((const char *)map->l_info[DT_STRTAB]) + st_name;
+
+ if (gelf_getclass (dso->elf) == ELFCLASS32)
+ {
+ const Elf32_Sym *sym32 = symptr;
+ rtld_lookup_symbol_x32 (name, map, &sym32, scope, ver, rtypeclass,
+ 0, NULL);
+ symptr = (void *) sym32;
+ }
+ else
+ {
+ const Elf64_Sym *sym64 = symptr;
+ rtld_lookup_symbol_x64 (name, map, &sym64, scope, ver, rtypeclass,
+ 0, NULL);
+ symptr = (void *) sym64;
+ }
+}
+
+void
+do_rel_section (DSO *dso, struct link_map *map,
+ struct r_scope_elem *scope[],
+ int tag, int section)
+{
+ Elf_Data *data;
+ int ndx, maxndx, sym, type;
+
+ data = elf_getdata (dso->scn[section], NULL);
+ maxndx = data->d_size / dso->shdr[section].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ndx++)
+ {
+ if (tag == DT_REL)
+ {
+ GElf_Rel rel;
+ gelfx_getrel (dso->elf, data, ndx, &rel);
+ sym = reloc_r_sym (dso, rel.r_info);
+ type = reloc_r_type (dso, rel.r_info);
+ }
+ else
+ {
+ GElf_Rela rela;
+ gelfx_getrela (dso->elf, data, ndx, &rela);
+ sym = reloc_r_sym (dso, rela.r_info);
+ type = reloc_r_type (dso, rela.r_info);
+ }
+ if (sym != 0)
+ do_reloc (dso, map, scope, sym, type);
+ }
+}
+
+void
+do_relocs (DSO *dso, struct link_map *map, struct r_scope_elem *scope[], int tag)
+{
+ GElf_Addr rel_start, rel_end;
+ GElf_Addr pltrel_start, pltrel_end;
+ int first, last;
+
+ /* Load the DT_REL or DT_RELA section. */
+ if (dso->info[tag] != 0)
+ {
+ rel_start = dso->info[tag];
+ rel_end = rel_start + dso->info[tag == DT_REL ? DT_RELSZ : DT_RELASZ];
+ first = addr_to_sec (dso, rel_start);
+ last = addr_to_sec (dso, rel_end - 1);
+ while (first <= last)
+ do_rel_section (dso, map, scope, tag, first++);
+
+ /* If the DT_JMPREL relocs are of the same type and not included,
+ load them too. Assume they overlap completely or not at all,
+ and are in at most a single section. They also need to be adjacent. */
+ if (dso->info[DT_PLTREL] == tag)
+ {
+ pltrel_start = dso->info[DT_JMPREL];
+ pltrel_end = pltrel_start + dso->info[DT_PLTRELSZ];
+ if (pltrel_start < rel_start || pltrel_end >= rel_end)
+ do_rel_section (dso, map, scope, tag, addr_to_sec (dso, pltrel_start));
+ }
+ }
+ else if (dso->info[DT_PLTREL] == tag)
+ do_rel_section (dso, map, scope, tag, addr_to_sec (dso, dso->info[DT_JMPREL]));
+}
+
+/* MIPS GOTs are not handled by normal relocations. Instead, entry X
+ in the global GOT is associated with symbol DT_MIPS_GOTSYM + X.
+ For the purposes of symbol lookup and conflict resolution, we need
+ to act as though entry X had a dynamic relocation against symbol
+ DT_MIPS_GOTSYM + X. */
+
+void
+do_mips_global_got_relocs (DSO *dso, struct link_map *map,
+ struct r_scope_elem *scope[])
+{
+ GElf_Word i;
+
+ for (i = dso->info_DT_MIPS_GOTSYM; i < dso->info_DT_MIPS_SYMTABNO; i++)
+ do_reloc (dso, map, scope, i, R_MIPS_REL32);
+}
+
+void
+handle_relocs_in_entry (struct dso_list *entry, struct dso_list *dso_list)
+{
+ do_relocs (entry->dso, entry->map, dso_list->map->l_local_scope, DT_REL);
+ do_relocs (entry->dso, entry->map, dso_list->map->l_local_scope, DT_RELA);
+ if (entry->dso->ehdr.e_machine == EM_MIPS)
+ do_mips_global_got_relocs (entry->dso, entry->map,
+ dso_list->map->l_local_scope);
+}
+
+void
+handle_relocs (DSO *dso, struct dso_list *dso_list)
+{
+ struct dso_list *ldso, *tail;
+
+ /* do them all last to first.
+ skip the dynamic linker; then do it last
+ in glibc this is conditional on the opencount; but every binary
+ should be linked to libc and thereby have an opencount for ld.so...
+ besides, that's the only way it would get on our dso list. */
+
+ tail = dso_list;
+ while (tail->next)
+ tail = tail->next;
+
+ ldso = NULL;
+ while (tail)
+ {
+ if (is_ldso_soname (tail->dso->soname))
+ ldso = tail;
+ else
+ handle_relocs_in_entry (tail, dso_list);
+ tail = tail->prev;
+ }
+
+ if (ldso)
+ handle_relocs_in_entry (ldso, dso_list);
+}
+
+void
+add_to_scope (struct r_scope_elem *scope[], struct dso_list *ent)
+{
+ struct needed_list *n;
+ int i;
+
+ for (i = 0; i < scope[0]->r_nlist; i++)
+ if (scope[0]->r_list[i] == ent->map)
+ return;
+
+ scope[0]->r_list[scope[0]->r_nlist++] = ent->map;
+ n = ent->needed;
+ while (n)
+ {
+ add_to_scope (scope, n->ent);
+ n = n->next;
+ }
+}
+
+void
+build_local_scope (struct dso_list *ent, int max)
+{
+ ent->map->l_local_scope[0] = malloc (sizeof (struct r_scope_elem));
+ ent->map->l_local_scope[0]->r_list = malloc (sizeof (struct link_map *) * max);
+ ent->map->l_local_scope[0]->r_nlist = 0;
+ add_to_scope (ent->map->l_local_scope, ent);
+}
+
+static struct argp argp = { options, parse_opt, "[FILES]", argp_doc };
+
+struct link_map *requested_map = NULL;
+
+static void process_one_dso (DSO *dso, int host_paths);
+
+int
+main(int argc, char **argv)
+{
+ int remaining;
+ int multiple = 0;
+ host_paths = 1;
+
+ char * debug = NULL;
+
+ sysroot = getenv ("PRELINK_SYSROOT");
+#ifdef DEFAULT_SYSROOT
+ if (sysroot == NULL)
+ {
+ extern char *make_relative_prefix (const char *, const char *, const char *);
+ sysroot = make_relative_prefix (argv[0], BINDIR, DEFAULT_SYSROOT);
+ }
+#endif
+
+ elf_version (EV_CURRENT);
+
+ argp_parse (&argp, argc, argv, 0, &remaining, 0);
+
+ if (sysroot)
+ sysroot = canonicalize_file_name (sysroot);
+
+ if (remaining == argc)
+ error (1, 0, "missing file arguments\nTry `%s: --help' for more information.", argv[0]);
+
+ if ((argc-remaining) >= 2)
+ multiple = 1;
+
+ /* More simplistic then glibc, one option only... */
+ debug = getenv ("RTLD_DEBUG");
+ if (debug && (!strcmp(debug, "files") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_FILES;
+
+ if (debug && (!strcmp(debug, "symbols") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_SYMBOLS;
+
+ if (debug && (!strcmp(debug, "versions") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_VERSIONS;
+
+ if (debug && (!strcmp(debug, "bindings") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_BINDINGS;
+
+ while (remaining < argc)
+ {
+ DSO *dso = NULL;
+ int i, fd;
+
+ struct stat64 st;
+
+ if (host_paths)
+ fd = open (argv[remaining], O_RDONLY);
+ else
+ fd = wrap_open (argv[remaining], O_RDONLY);
+
+ if (fd >= 0 && fstat64(fd, &st) == 0)
+ if (!S_ISREG(st.st_mode))
+ {
+ error (0, 0, "%s: %s",
+ argv[remaining],
+ "not regular file");
+ goto exit;
+ }
+
+ if (fd >= 0) {
+ dso = fdopen_dso (fd, argv[remaining]);
+ dst_ORIGIN = dirname(strdup(dso->filename));
+ }
+
+ if (dso == NULL)
+ {
+ error (0, 0, "%s: %s",
+ argv[remaining],
+ strerror(errno));
+ goto exit;
+ }
+
+ load_ld_so_conf (gelf_getclass (dso->elf) == ELFCLASS64,
+ ( dso->ehdr.e_machine == EM_MIPS) && ( dso->ehdr.e_flags & EF_MIPS_ABI2 ) );
+
+ if (multiple)
+ printf ("%s:\n", argv[remaining]);
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_INTERP)
+ break;
+
+ /* If there are no PT_INTERP segments, it is statically linked. */
+ if (dso->ehdr.e_type == ET_EXEC && i == dso->ehdr.e_phnum)
+ printf ("\tnot a dynamic executable\n");
+ else
+ {
+ int j;
+ Elf_Data *data;
+ j = addr_to_sec (dso, dso->phdr[i].p_vaddr);
+ if (j != -1)
+ {
+ data = elf_getdata (dso->scn[j], NULL);
+ if (data != NULL)
+ {
+ i = strnlen (data->d_buf, data->d_size);
+ if (i == data->d_size)
+ {
+ rtld_signal_error (0, dso->filename, NULL, ".interp section not zero terminated", 0);
+ }
+ else
+ {
+ rtld_progname = strdup (data->d_buf);
+ }
+ }
+ }
+ process_one_dso (dso, host_paths);
+ }
+
+exit:
+ remaining++;
+ }
+
+ return 0;
+}
+
+/* If you run ldd /lib/ld.so you get:
+ \tstatically linked
+
+ The prelink-rtld does not do this, and returns blank...
+ */
+static void
+process_one_dso (DSO *dso, int host_paths)
+{
+ struct dso_list *dso_list, *cur_dso_ent, *old_dso_ent;
+ const char *req;
+ int i;
+ int ld_warn = 1;
+
+ if ((req = getenv ("RTLD_TRACE_PRELINKING")) != NULL)
+ _dl_debug_mask |= DL_DEBUG_PRELINK;
+
+ /* Close enough. Really it's if LD_WARN is "" and RTLD_TRACE_PRELINKING. */
+ if (getenv ("RTLD_WARN") == NULL)
+ ld_warn = 0;
+
+ /* Initialize unique symtable list */
+ _ns_unique_sym_table = calloc(sizeof (struct unique_sym_table), 1);
+
+ dso_list = load_dsos (dso, host_paths);
+
+ cur_dso_ent = dso_list;
+ i = 0;
+ while (cur_dso_ent)
+ {
+ if (cur_dso_ent->dso)
+ {
+ create_map_object_from_dso_ent (cur_dso_ent);
+ if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) && strcmp (req, cur_dso_ent->dso->filename) == 0)
+ requested_map = cur_dso_ent->map;
+ }
+ else
+ {
+ /* This is a dummy entry, we couldn't find the object */
+ cur_dso_ent->map = _dl_new_object(cur_dso_ent->name, cur_dso_ent->canon_filename, lt_library);
+ }
+ i++;
+ cur_dso_ent = cur_dso_ent->next;
+ }
+ dso_list->map->l_local_scope[0] = malloc (sizeof (struct r_scope_elem));
+ dso_list->map->l_local_scope[0]->r_list = malloc (sizeof (struct link_map *) * i);
+ dso_list->map->l_local_scope[0]->r_nlist = i;
+ cur_dso_ent = dso_list;
+ i = 0;
+ while (cur_dso_ent)
+ {
+ if (cur_dso_ent->map)
+ {
+ dso_list->map->l_local_scope[0]->r_list[i] = cur_dso_ent->map;
+ if (cur_dso_ent != dso_list)
+ build_local_scope (cur_dso_ent, dso_list->map->l_local_scope[0]->r_nlist);
+
+ i++;
+ }
+ cur_dso_ent = cur_dso_ent->next;
+ }
+
+ cur_dso_ent = dso_list;
+
+ for (i = 0; i < cur_dso_ent->map->l_local_scope[0]->r_nlist; ++i)
+ if (cur_dso_ent->map->l_local_scope[0]->r_list[i]->l_versions == NULL)
+ _dl_check_map_versions (cur_dso_ent->map->l_local_scope[0]->r_list[i], 0, 0);
+
+ rtld_determine_tlsoffsets (dso->ehdr.e_machine, dso_list->map->l_local_scope[0]);
+
+ cur_dso_ent = dso_list;
+
+ /* In ldd mode, do not show the application. Note that we do show it
+ in list-loaded-objects RTLD_TRACE_PRELINK mode. */
+ if (!(GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) && cur_dso_ent)
+ {
+ /* Based on the presence of DT_NEEDED, see load_dsos */
+ if (static_binary)
+ {
+ printf ("\tstatically linked\n");
+ }
+ cur_dso_ent = cur_dso_ent->next;
+ }
+ while (cur_dso_ent)
+ {
+ char *filename;
+
+ if (host_paths && sysroot && cur_dso_ent->dso)
+ {
+ const char *rooted_filename;
+
+ if (cur_dso_ent->dso->filename[0] == '/')
+ rooted_filename = cur_dso_ent->dso->filename;
+ else
+ rooted_filename = cur_dso_ent->canon_filename;
+
+ filename = malloc (strlen (rooted_filename) + strlen (sysroot) + 1);
+ strcpy (filename, sysroot);
+ strcat (filename, rooted_filename);
+ }
+ else if (cur_dso_ent->dso)
+ filename = strdup (cur_dso_ent->dso->filename);
+ else
+ filename = NULL;
+
+ int size_pointer = 16;
+ if (cur_dso_ent && cur_dso_ent->dso && gelf_getclass (cur_dso_ent->dso->elf) == ELFCLASS32)
+ size_pointer = 8;
+
+ /* The difference between the two numbers must be dso->base,
+ and the first number must be unique. */
+ if (dso_open_error && ld_warn && (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK))
+ {
+ if (cur_dso_ent->dso == NULL)
+ rtld_signal_error(cur_dso_ent->err_no, cur_dso_ent->name, NULL, "cannot open shared object file", 0);
+ }
+ else if (cur_dso_ent->dso == NULL)
+ printf ("\t%s => not found\n", cur_dso_ent->name);
+ else if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
+ {
+ struct link_map * l = cur_dso_ent->map;
+ if (size_pointer == 16)
+ printf ("\t%s => %s (0x%016"PRIx64", 0x%016"PRIx64")",
+ cur_dso_ent->name ? cur_dso_ent->name
+ : rtld_progname ?: "<main program>",
+ filename ? filename
+ : rtld_progname ?: "<main program>",
+ (uint64_t) l->l_map_start,
+ (uint64_t) (l->l_map_start == cur_dso_ent->dso->base ? 0 : l->l_map_start));
+ else
+ printf ("\t%s => %s (0x%08"PRIx32", 0x%08"PRIx32")",
+ cur_dso_ent->name ? cur_dso_ent->name
+ : rtld_progname ?: "<main program>",
+ filename ? filename
+ : rtld_progname ?: "<main program>",
+ (uint32_t) l->l_map_start,
+ (uint32_t) (l->l_map_start == cur_dso_ent->dso->base ? 0 : l->l_map_start));
+
+ if (l->l_tls_modid)
+ if (size_pointer == 16)
+ printf (" TLS(0x%"PRIx64", 0x%016"PRIx64")\n",
+ (uint64_t) l->l_tls_modid,
+ (uint64_t) l->l_tls_offset);
+ else
+ printf (" TLS(0x%"PRIx32", 0x%08"PRIx32")\n",
+ (uint32_t) l->l_tls_modid,
+ (uint32_t) l->l_tls_offset);
+ else
+ printf ("\n");
+ }
+ else
+ {
+ struct link_map * l = cur_dso_ent->map;
+ if (!(GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) && strcmp (cur_dso_ent->name, filename) == 0)
+ if (size_pointer == 16)
+ printf ("\t%s (0x%016"PRIx64")\n", cur_dso_ent->name,
+ (uint64_t) l->l_map_start);
+ else
+ printf ("\t%s (0x%08"PRIx32")\n", cur_dso_ent->name,
+ (uint32_t) l->l_map_start);
+ else
+ if (size_pointer == 16)
+ printf ("\t%s => %s (0x%016"PRIx64")\n", cur_dso_ent->name,
+ filename,
+ (uint64_t) l->l_map_start);
+ else
+ printf ("\t%s => %s (0x%08"PRIx32")\n", cur_dso_ent->name,
+ filename,
+ (uint32_t) l->l_map_start);
+ }
+
+ if (filename)
+ free (filename);
+
+ cur_dso_ent = cur_dso_ent->next;
+ }
+
+ if (dso_open_error)
+ exit (127);
+
+ if (!ld_warn && (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK))
+ handle_relocs (dso_list->dso, dso_list);
+
+ cur_dso_ent = dso_list;
+ while (cur_dso_ent)
+ {
+ if (cur_dso_ent->dso)
+ close_dso (cur_dso_ent->dso);
+ old_dso_ent = cur_dso_ent;
+ cur_dso_ent = cur_dso_ent->next;
+ if (old_dso_ent->needed)
+ free_needed (old_dso_ent->needed);
+ free (old_dso_ent);
+ }
+}