summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/ld/emultempl/elf32.em
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/ld/emultempl/elf32.em')
-rw-r--r--contrib/binutils/ld/emultempl/elf32.em244
1 files changed, 198 insertions, 46 deletions
diff --git a/contrib/binutils/ld/emultempl/elf32.em b/contrib/binutils/ld/emultempl/elf32.em
index f02775e..c4debe2 100644
--- a/contrib/binutils/ld/emultempl/elf32.em
+++ b/contrib/binutils/ld/emultempl/elf32.em
@@ -7,7 +7,7 @@ cat >e${EMULATION_NAME}.c <<EOF
/* This file is is generated by a shell script. DO NOT EDIT! */
/* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME}
- Copyright (C) 1991, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1991, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
Written by Steve Chamberlain <sac@cygnus.com>
ELF support by Ian Lance Taylor <ian@cygnus.com>
@@ -54,8 +54,10 @@ static void gld${EMULATION_NAME}_check_needed
static void gld${EMULATION_NAME}_stat_needed
PARAMS ((lang_input_statement_type *));
static boolean gld${EMULATION_NAME}_search_needed
- PARAMS ((const char *, const char *));
-static boolean gld${EMULATION_NAME}_try_needed PARAMS ((const char *));
+ PARAMS ((const char *, const char *, int));
+static boolean gld${EMULATION_NAME}_try_needed PARAMS ((const char *, int));
+static void gld${EMULATION_NAME}_vercheck
+ PARAMS ((lang_input_statement_type *));
static void gld${EMULATION_NAME}_before_allocation PARAMS ((void));
static void gld${EMULATION_NAME}_find_statement_assignment
PARAMS ((lang_statement_union_type *));
@@ -143,11 +145,13 @@ cat >>e${EMULATION_NAME}.c <<EOF
in which we may find shared libraries. /etc/ld.so.conf is really
only meaningful on Linux, but we check it on other systems anyhow. */
-static boolean gld${EMULATION_NAME}_check_ld_so_conf PARAMS ((const char *));
+static boolean gld${EMULATION_NAME}_check_ld_so_conf
+ PARAMS ((const char *, int));
static boolean
-gld${EMULATION_NAME}_check_ld_so_conf (name)
+gld${EMULATION_NAME}_check_ld_so_conf (name, force)
const char *name;
+ int force;
{
static boolean initialized;
static char *ld_so_conf;
@@ -215,7 +219,7 @@ gld${EMULATION_NAME}_check_ld_so_conf (name)
if (ld_so_conf == NULL)
return false;
- return gld${EMULATION_NAME}_search_needed (ld_so_conf, name);
+ return gld${EMULATION_NAME}_search_needed (ld_so_conf, name, force);
}
EOF
@@ -224,11 +228,13 @@ fi
cat >>e${EMULATION_NAME}.c <<EOF
/* These variables are required to pass information back and forth
- between after_open and check_needed and stat_needed. */
+ between after_open and check_needed and stat_needed and vercheck. */
static struct bfd_link_needed_list *global_needed;
static struct stat global_stat;
static boolean global_found;
+static struct bfd_link_needed_list *global_vercheck_needed;
+static boolean global_vercheck_failed;
/* This is called after all the input files have been opened. */
@@ -254,9 +260,7 @@ gld${EMULATION_NAME}_after_open ()
for (l = needed; l != NULL; l = l->next)
{
struct bfd_link_needed_list *ll;
- const char *lib_path;
- size_t len;
- search_dirs_type *search;
+ int force;
/* If we've already seen this file, skip it. */
for (ll = needed; ll != l; ll = ll->next)
@@ -277,55 +281,71 @@ gld${EMULATION_NAME}_after_open ()
linker will search. That means that we want to use
rpath_link, rpath, then the environment variable
LD_LIBRARY_PATH (native only), then the linker script
- LIB_SEARCH_DIRS. We do not search using the -L arguments. */
- if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
- l->name))
- continue;
- if (gld${EMULATION_NAME}_search_needed (command_line.rpath, l->name))
- continue;
- if (command_line.rpath_link == NULL
- && command_line.rpath == NULL)
+ LIB_SEARCH_DIRS. We do not search using the -L arguments.
+
+ We search twice. The first time, we skip objects which may
+ introduce version mismatches. The second time, we force
+ their use. See gld${EMULATION_NAME}_vercheck comment. */
+ for (force = 0; force < 2; force++)
{
- lib_path = (const char *) getenv ("LD_RUN_PATH");
- if (gld${EMULATION_NAME}_search_needed (lib_path, l->name))
- continue;
- }
+ const char *lib_path;
+ size_t len;
+ search_dirs_type *search;
+
+ if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
+ l->name, force))
+ break;
+ if (gld${EMULATION_NAME}_search_needed (command_line.rpath,
+ l->name, force))
+ break;
+ if (command_line.rpath_link == NULL
+ && command_line.rpath == NULL)
+ {
+ lib_path = (const char *) getenv ("LD_RUN_PATH");
+ if (gld${EMULATION_NAME}_search_needed (lib_path, l->name,
+ force))
+ break;
+ }
EOF
if [ "x${host}" = "x${target}" ] ; then
if [ "x${DEFAULT_EMULATION}" = "x${EMULATION_NAME}" ] ; then
cat >>e${EMULATION_NAME}.c <<EOF
- lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
- if (gld${EMULATION_NAME}_search_needed (lib_path, l->name))
- continue;
+ lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
+ if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force))
+ break;
EOF
fi
fi
cat >>e${EMULATION_NAME}.c <<EOF
- len = strlen (l->name);
- for (search = search_head; search != NULL; search = search->next)
- {
- char *filename;
-
- if (search->cmdline)
- continue;
- filename = (char *) xmalloc (strlen (search->name) + len + 2);
- sprintf (filename, "%s/%s", search->name, l->name);
- if (gld${EMULATION_NAME}_try_needed (filename))
+ len = strlen (l->name);
+ for (search = search_head; search != NULL; search = search->next)
+ {
+ char *filename;
+
+ if (search->cmdline)
+ continue;
+ filename = (char *) xmalloc (strlen (search->name) + len + 2);
+ sprintf (filename, "%s/%s", search->name, l->name);
+ if (gld${EMULATION_NAME}_try_needed (filename, force))
+ break;
+ free (filename);
+ }
+ if (search != NULL)
break;
- free (filename);
- }
- if (search != NULL)
- continue;
EOF
if [ "x${host}" = "x${target}" ] ; then
if [ "x${DEFAULT_EMULATION}" = "x${EMULATION_NAME}" ] ; then
cat >>e${EMULATION_NAME}.c <<EOF
- if (gld${EMULATION_NAME}_check_ld_so_conf (l->name))
- continue;
+ if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force))
+ break;
EOF
fi
fi
cat >>e${EMULATION_NAME}.c <<EOF
+ }
+
+ if (force < 2)
+ continue;
einfo ("%P: warning: %s, needed by %B, not found (try using --rpath)\n",
l->name, l->by);
@@ -335,9 +355,10 @@ cat >>e${EMULATION_NAME}.c <<EOF
/* Search for a needed file in a path. */
static boolean
-gld${EMULATION_NAME}_search_needed (path, name)
+gld${EMULATION_NAME}_search_needed (path, name, force)
const char *path;
const char *name;
+ int force;
{
const char *s;
size_t len;
@@ -364,7 +385,7 @@ gld${EMULATION_NAME}_search_needed (path, name)
}
strcpy (sset, name);
- if (gld${EMULATION_NAME}_try_needed (filename))
+ if (gld${EMULATION_NAME}_try_needed (filename, force))
return true;
free (filename);
@@ -378,11 +399,13 @@ gld${EMULATION_NAME}_search_needed (path, name)
}
/* This function is called for each possible name for a dynamic object
- named by a DT_NEEDED entry. */
+ named by a DT_NEEDED entry. The FORCE parameter indicates whether
+ to skip the check for a conflicting version. */
static boolean
-gld${EMULATION_NAME}_try_needed (name)
+gld${EMULATION_NAME}_try_needed (name, force)
const char *name;
+ int force;
{
bfd *abfd;
@@ -400,6 +423,62 @@ gld${EMULATION_NAME}_try_needed (name)
return false;
}
+ /* Check whether this object would include any conflicting library
+ versions. If FORCE is set, then we skip this check; we use this
+ the second time around, if we couldn't find any compatible
+ instance of the shared library. */
+
+ if (! force)
+ {
+ struct bfd_link_needed_list *needed;
+
+ if (! bfd_elf_get_bfd_needed_list (abfd, &needed))
+ einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd);
+
+ if (needed != NULL)
+ {
+ global_vercheck_needed = needed;
+ global_vercheck_failed = false;
+ lang_for_each_input_file (gld${EMULATION_NAME}_vercheck);
+ if (global_vercheck_failed)
+ {
+ (void) bfd_close (abfd);
+ /* Return false to force the caller to move on to try
+ another file on the search path. */
+ return false;
+ }
+
+ /* But wait! It gets much worse. On Linux, if a shared
+ library does not use libc at all, we are supposed to skip
+ it the first time around in case we encounter a shared
+ library later on with the same name which does use the
+ version of libc that we want. This is much too horrible
+ to use on any system other than Linux. */
+
+EOF
+case ${target} in
+ *-*-linux-gnu*)
+ cat >>e${EMULATION_NAME}.c <<EOF
+ {
+ struct bfd_link_needed_list *l;
+
+ for (l = needed; l != NULL; l = l->next)
+ if (strncmp (l->name, "libc.so", 7) == 0)
+ break;
+ if (l == NULL)
+ {
+ (void) bfd_close (abfd);
+ return false;
+ }
+ }
+
+EOF
+ ;;
+esac
+cat >>e${EMULATION_NAME}.c <<EOF
+ }
+ }
+
/* We've found a dynamic object matching the DT_NEEDED entry. */
/* We have already checked that there is no other input file of the
@@ -538,6 +617,78 @@ gld${EMULATION_NAME}_stat_needed (s)
global_needed->name, global_needed->by, f);
}
+/* On Linux, it's possible to have different versions of the same
+ shared library linked against different versions of libc. The
+ dynamic linker somehow tags which libc version to use in
+ /etc/ld.so.cache, and, based on the libc that it sees in the
+ executable, chooses which version of the shared library to use.
+
+ We try to do a similar check here by checking whether this shared
+ library needs any other shared libraries which may conflict with
+ libraries we have already included in the link. If it does, we
+ skip it, and try to find another shared library farther on down the
+ link path.
+
+ This is called via lang_for_each_input_file.
+ GLOBAL_VERCHECK_NEEDED is the list of objects needed by the object
+ which we ar checking. This sets GLOBAL_VERCHECK_FAILED if we find
+ a conflicting version. */
+
+static void
+gld${EMULATION_NAME}_vercheck (s)
+ lang_input_statement_type *s;
+{
+ const char *soname, *f;
+ struct bfd_link_needed_list *l;
+
+ if (global_vercheck_failed)
+ return;
+ if (s->the_bfd == NULL
+ || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0)
+ return;
+
+ soname = bfd_elf_get_dt_soname (s->the_bfd);
+ if (soname == NULL)
+ soname = bfd_get_filename (s->the_bfd);
+
+ f = strrchr (soname, '/');
+ if (f != NULL)
+ ++f;
+ else
+ f = soname;
+
+ for (l = global_vercheck_needed; l != NULL; l = l->next)
+ {
+ const char *suffix;
+
+ if (strcmp (f, l->name) == 0)
+ {
+ /* Probably can't happen, but it's an easy check. */
+ continue;
+ }
+
+ if (strchr (l->name, '/') != NULL)
+ continue;
+
+ suffix = strstr (l->name, ".so.");
+ if (suffix == NULL)
+ continue;
+
+ suffix += sizeof ".so." - 1;
+
+ if (strncmp (f, l->name, suffix - l->name) == 0)
+ {
+ /* Here we know that S is a dynamic object FOO.SO.VER1, and
+ the object we are considering needs a dynamic object
+ FOO.SO.VER2, and VER1 and VER2 are different. This
+ appears to be a version mismatch, so we tell the caller
+ to try a different version of this library. */
+ global_vercheck_failed = true;
+ return;
+ }
+ }
+}
+
/* This is called after the sections have been attached to output
sections, but before any sizes or addresses have been set. */
@@ -844,7 +995,7 @@ gld${EMULATION_NAME}_place_orphan (file, s)
/* If the name of the section is representable in C, then create
symbols to mark the start and the end of the section. */
for (ps = outsecname; *ps != '\0'; ps++)
- if (! isalnum (*ps) && *ps != '_')
+ if (! isalnum ((unsigned char) *ps) && *ps != '_')
break;
if (*ps == '\0' && config.build_constructors)
{
@@ -907,6 +1058,7 @@ gld${EMULATION_NAME}_place_section (s)
os = &s->output_section_statement;
if (strcmp (os->name, hold_section->name) == 0
+ && os->bfd_section != NULL
&& ((hold_section->flags & (SEC_LOAD | SEC_ALLOC))
== (os->bfd_section->flags & (SEC_LOAD | SEC_ALLOC))))
hold_use = os;
OpenPOWER on IntegriCloud