# This file is now misnamed, because it supports both 32 bit and 64 bit
# ELF emulations.
test -z "${ELFSIZE}" && ELFSIZE=32
+if [ -z "$MACHINE" ]; then
+ OUTPUT_ARCH=${ARCH}
+else
+ OUTPUT_ARCH=${ARCH}:${MACHINE}
+fi
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, 97, 98, 99, 2000
+ Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
Written by Steve Chamberlain <sac@cygnus.com>
ELF support by Ian Lance Taylor <ian@cygnus.com>
#include "bfd.h"
#include "sysdep.h"
-
-#include <ctype.h>
+#include "libiberty.h"
+#include "safe-ctype.h"
#include "bfdlink.h"
#include "ldgram.h"
#include "elf/common.h"
-static void gld${EMULATION_NAME}_before_parse PARAMS ((void));
-static boolean gld${EMULATION_NAME}_open_dynamic_archive
- PARAMS ((const char *, search_dirs_type *, lang_input_statement_type *));
-static void gld${EMULATION_NAME}_after_open PARAMS ((void));
-static void gld${EMULATION_NAME}_check_needed
+static void gld${EMULATION_NAME}_before_parse
+ PARAMS ((void));
+static void gld${EMULATION_NAME}_vercheck
PARAMS ((lang_input_statement_type *));
static void gld${EMULATION_NAME}_stat_needed
PARAMS ((lang_input_statement_type *));
+static boolean gld${EMULATION_NAME}_try_needed
+ PARAMS ((const char *, int));
static boolean gld${EMULATION_NAME}_search_needed
PARAMS ((const char *, const char *, int));
-static boolean gld${EMULATION_NAME}_try_needed PARAMS ((const char *, int));
-static void gld${EMULATION_NAME}_vercheck
+static void gld${EMULATION_NAME}_check_needed
PARAMS ((lang_input_statement_type *));
-static void gld${EMULATION_NAME}_before_allocation PARAMS ((void));
+static void gld${EMULATION_NAME}_after_open
+ PARAMS ((void));
+static void gld${EMULATION_NAME}_find_exp_assignment
+ PARAMS ((etree_type *));
static void gld${EMULATION_NAME}_find_statement_assignment
PARAMS ((lang_statement_union_type *));
-static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *));
+static void gld${EMULATION_NAME}_before_allocation
+ PARAMS ((void));
+static boolean gld${EMULATION_NAME}_open_dynamic_archive
+ PARAMS ((const char *, search_dirs_type *, lang_input_statement_type *));
+static lang_output_section_statement_type *output_rel_find
+ PARAMS ((void));
+static asection *output_prev_sec_find
+ PARAMS ((lang_output_section_statement_type *));
static boolean gld${EMULATION_NAME}_place_orphan
PARAMS ((lang_input_statement_type *, asection *));
-static lang_output_section_statement_type *output_rel_find PARAMS ((void));
-static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile));
+static char *gld${EMULATION_NAME}_get_script
+ PARAMS ((int *isfile));
+
+EOF
+
+# Import any needed special functions and/or overrides.
+#
+if test -n "$EXTRA_EM_FILE" ; then
+. ${srcdir}/emultempl/${EXTRA_EM_FILE}.em
+fi
+
+# Functions in this file can be overridden by setting the LDEMUL_* shell
+# variables. If the name of the overriding function is the same as is
+# defined in this file, then don't output this file's version.
+# If a different overriding name is given then output the standard function
+# as presumably it is called from the overriding function.
+#
+if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then
+cat >>e${EMULATION_NAME}.c <<EOF
static void
-gld${EMULATION_NAME}_before_parse()
+gld${EMULATION_NAME}_before_parse ()
{
- ldfile_output_architecture = bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`;
+ const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}");
+ if (arch)
+ {
+ ldfile_output_architecture = arch->arch;
+ ldfile_output_machine = arch->mach;
+ ldfile_output_machine_name = arch->printable_name;
+ }
+ else
+ ldfile_output_architecture = bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`;
config.dynamic_link = ${DYNAMIC_LINK-true};
config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`;
}
-/* Try to open a dynamic archive. This is where we know that ELF
- dynamic libraries have an extension of .so (or .sl on oddball systems
- like hpux). */
+EOF
+fi
-static boolean
-gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry)
- const char *arch;
- search_dirs_type *search;
- lang_input_statement_type *entry;
-{
- const char *filename;
- char *string;
+cat >>e${EMULATION_NAME}.c <<EOF
- if (! entry->is_archive)
- return false;
+/* These variables are required to pass information back and forth
+ between after_open and check_needed and stat_needed and vercheck. */
- filename = entry->filename;
+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 allocates a few bytes too many when EXTRA_SHLIB_EXTENSION
- is defined, but it does not seem worth the headache to optimize
- away those two bytes of space. */
- string = (char *) xmalloc (strlen (search->name)
- + strlen (filename)
- + strlen (arch)
-#ifdef EXTRA_SHLIB_EXTENSION
- + strlen (EXTRA_SHLIB_EXTENSION)
-#endif
- + sizeof "/lib.so");
- sprintf (string, "%s/lib%s%s.so", search->name, filename, arch);
+/* 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.
-#ifdef EXTRA_SHLIB_EXTENSION
- /* Try the .so extension first. If that fails build a new filename
- using EXTRA_SHLIB_EXTENSION. */
- if (! ldfile_try_open_bfd (string, entry))
- sprintf (string, "%s/lib%s%s%s", search->name,
- filename, arch, EXTRA_SHLIB_EXTENSION);
-#endif
+ 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.
- if (! ldfile_try_open_bfd (string, entry))
- {
- free (string);
- return false;
- }
+ This is called via lang_for_each_input_file.
+ GLOBAL_VERCHECK_NEEDED is the list of objects needed by the object
+ which we are checking. This sets GLOBAL_VERCHECK_FAILED if we find
+ a conflicting version. */
- entry->filename = string;
+static void
+gld${EMULATION_NAME}_vercheck (s)
+ lang_input_statement_type *s;
+{
+ const char *soname;
+ struct bfd_link_needed_list *l;
- /* We have found a dynamic object to include in the link. The ELF
- backend linker will create a DT_NEEDED entry in the .dynamic
- section naming this file. If this file includes a DT_SONAME
- entry, it will be used. Otherwise, the ELF linker will just use
- the name of the file. For an archive found by searching, like
- this one, the DT_NEEDED entry should consist of just the name of
- the file, without the path information used to find it. Note
- that we only need to do this if we have a dynamic object; an
- archive will never be referenced by a DT_NEEDED entry.
+ if (global_vercheck_failed)
+ return;
+ if (s->the_bfd == NULL
+ || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0)
+ return;
- FIXME: This approach--using bfd_elf_set_dt_needed_name--is not
- very pretty. I haven't been able to think of anything that is
- pretty, though. */
- if (bfd_check_format (entry->the_bfd, bfd_object)
- && (entry->the_bfd->flags & DYNAMIC) != 0)
+ soname = bfd_elf_get_dt_soname (s->the_bfd);
+ if (soname == NULL)
+ soname = basename (bfd_get_filename (s->the_bfd));
+
+ for (l = global_vercheck_needed; l != NULL; l = l->next)
{
- char *needed_name;
+ const char *suffix;
- ASSERT (entry->is_archive && entry->search_dirs_flag);
+ if (strcmp (soname, l->name) == 0)
+ {
+ /* Probably can't happen, but it's an easy check. */
+ continue;
+ }
- /* Rather than duplicating the logic above. Just use the
- filename we recorded earlier.
+ if (strchr (l->name, '/') != NULL)
+ continue;
- First strip off everything before the last '/'. */
- filename = strrchr (entry->filename, '/');
- filename++;
+ suffix = strstr (l->name, ".so.");
+ if (suffix == NULL)
+ continue;
- needed_name = (char *) xmalloc (strlen (filename) + 1);
- strcpy (needed_name, filename);
- bfd_elf_set_dt_needed_name (entry->the_bfd, needed_name);
- }
+ suffix += sizeof ".so." - 1;
- return true;
+ if (strncmp (soname, 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;
+ }
+ }
}
-EOF
-if [ "x${host}" = "x${target}" ] ; then
- case " ${EMULATION_LIBPATH} " in
- *" ${EMULATION_NAME} "*)
-cat >>e${EMULATION_NAME}.c <<EOF
-
-/* For a native linker, check the file /etc/ld.so.conf for directories
- 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 *, int));
+/* See if an input file matches a DT_NEEDED entry by running stat on
+ the file. */
-static boolean
-gld${EMULATION_NAME}_check_ld_so_conf (name, force)
- const char *name;
- int force;
+static void
+gld${EMULATION_NAME}_stat_needed (s)
+ lang_input_statement_type *s;
{
- static boolean initialized;
- static char *ld_so_conf;
+ struct stat st;
+ const char *suffix;
+ const char *soname;
- if (! initialized)
+ if (global_found)
+ return;
+ if (s->the_bfd == NULL)
+ return;
+
+ if (bfd_stat (s->the_bfd, &st) != 0)
{
- FILE *f;
+ einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd);
+ return;
+ }
- f = fopen ("/etc/ld.so.conf", FOPEN_RT);
- if (f != NULL)
- {
- char *b;
- size_t len, alloc;
- int c;
+ if (st.st_dev == global_stat.st_dev
+ && st.st_ino == global_stat.st_ino)
+ {
+ global_found = true;
+ return;
+ }
- len = 0;
- alloc = 100;
- b = (char *) xmalloc (alloc);
+ /* We issue a warning if it looks like we are including two
+ different versions of the same shared library. For example,
+ there may be a problem if -lc picks up libc.so.6 but some other
+ shared library has a DT_NEEDED entry of libc.so.5. This is a
+ heuristic test, and it will only work if the name looks like
+ NAME.so.VERSION. FIXME: Depending on file names is error-prone.
+ If we really want to issue warnings about mixing version numbers
+ of shared libraries, we need to find a better way. */
- while ((c = getc (f)) != EOF)
- {
- if (len + 1 >= alloc)
- {
- alloc *= 2;
- b = (char *) xrealloc (b, alloc);
- }
- if (c != ':'
- && c != ' '
- && c != '\t'
- && c != '\n'
- && c != ',')
- {
- b[len] = c;
- ++len;
- }
- else
- {
- if (len > 0 && b[len - 1] != ':')
- {
- b[len] = ':';
- ++len;
- }
- }
- }
+ if (strchr (global_needed->name, '/') != NULL)
+ return;
+ suffix = strstr (global_needed->name, ".so.");
+ if (suffix == NULL)
+ return;
+ suffix += sizeof ".so." - 1;
- if (len > 0 && b[len - 1] == ':')
- --len;
+ soname = bfd_elf_get_dt_soname (s->the_bfd);
+ if (soname == NULL)
+ soname = basename (s->filename);
- if (len > 0)
- b[len] = '\0';
- else
- {
- free (b);
- b = NULL;
- }
+ if (strncmp (soname, global_needed->name, suffix - global_needed->name) == 0)
+ einfo ("%P: warning: %s, needed by %B, may conflict with %s\n",
+ global_needed->name, global_needed->by, soname);
+}
- fclose (f);
- ld_so_conf = b;
- }
+/* This function is called for each possible name for a dynamic object
+ named by a DT_NEEDED entry. The FORCE parameter indicates whether
+ to skip the check for a conflicting version. */
- initialized = true;
- }
+static boolean
+gld${EMULATION_NAME}_try_needed (name, force)
+ const char *name;
+ int force;
+{
+ bfd *abfd;
+ const char *soname;
- if (ld_so_conf == NULL)
- return false;
-
- return gld${EMULATION_NAME}_search_needed (ld_so_conf, name, force);
-}
-
-EOF
- ;;
- esac
-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 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. */
-
-static void
-gld${EMULATION_NAME}_after_open ()
-{
- struct bfd_link_needed_list *needed, *l;
-
- /* We only need to worry about this when doing a final link. */
- if (link_info.relocateable || link_info.shared)
- return;
-
- /* Get the list of files which appear in DT_NEEDED entries in
- dynamic objects included in the link (often there will be none).
- For each such file, we want to track down the corresponding
- library, and include the symbol table in the link. This is what
- the runtime dynamic linker will do. Tracking the files down here
- permits one dynamic object to include another without requiring
- special action by the person doing the link. Note that the
- needed list can actually grow while we are stepping through this
- loop. */
- needed = bfd_elf_get_needed_list (output_bfd, &link_info);
- for (l = needed; l != NULL; l = l->next)
- {
- struct bfd_link_needed_list *ll;
- int force;
-
- /* If we've already seen this file, skip it. */
- for (ll = needed; ll != l; ll = ll->next)
- if (strcmp (ll->name, l->name) == 0)
- break;
- if (ll != l)
- continue;
-
- /* See if this file was included in the link explicitly. */
- global_needed = l;
- global_found = false;
- lang_for_each_input_file (gld${EMULATION_NAME}_check_needed);
- if (global_found)
- continue;
-
- /* We need to find this file and include the symbol table. We
- want to search for the file in the same way that the dynamic
- 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.
-
- 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++)
- {
- 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
- case " ${EMULATION_LIBPATH} " in
- *" ${EMULATION_NAME} "*)
-cat >>e${EMULATION_NAME}.c <<EOF
- lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
- if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force))
- break;
-EOF
- ;;
- esac
-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, force))
- break;
- free (filename);
- }
- if (search != NULL)
- break;
-EOF
-if [ "x${host}" = "x${target}" ] ; then
- case " ${EMULATION_LIBPATH} " in
- *" ${EMULATION_NAME} "*)
-cat >>e${EMULATION_NAME}.c <<EOF
- if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force))
- break;
-EOF
- ;;
- esac
-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);
- }
-}
-
-/* Search for a needed file in a path. */
-
-static boolean
-gld${EMULATION_NAME}_search_needed (path, name, force)
- const char *path;
- const char *name;
- int force;
-{
- const char *s;
- size_t len;
-
- if (path == NULL || *path == '\0')
- return false;
- len = strlen (name);
- while (1)
- {
- char *filename, *sset;
-
- s = strchr (path, ':');
- if (s == NULL)
- s = path + strlen (path);
-
- filename = (char *) xmalloc (s - path + len + 2);
- if (s == path)
- sset = filename;
- else
- {
- memcpy (filename, path, s - path);
- filename[s - path] = '/';
- sset = filename + (s - path) + 1;
- }
- strcpy (sset, name);
-
- if (gld${EMULATION_NAME}_try_needed (filename, force))
- return true;
-
- free (filename);
-
- if (*s == '\0')
- break;
- path = s + 1;
- }
-
- return false;
-}
-
-/* This function is called for each possible name for a dynamic object
- 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, force)
- const char *name;
- int force;
-{
- bfd *abfd;
-
- abfd = bfd_openr (name, bfd_get_target (output_bfd));
- if (abfd == NULL)
+ abfd = bfd_openr (name, bfd_get_target (output_bfd));
+ if (abfd == NULL)
return false;
if (! bfd_check_format (abfd, bfd_object))
{
- (void) bfd_close (abfd);
+ bfd_close (abfd);
return false;
}
if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0)
{
- (void) bfd_close (abfd);
+ bfd_close (abfd);
return false;
}
lang_for_each_input_file (gld${EMULATION_NAME}_vercheck);
if (global_vercheck_failed)
{
- (void) bfd_close (abfd);
+ bfd_close (abfd);
/* Return false to force the caller to move on to try
another file on the search path. */
return false;
break;
if (l == NULL)
{
- (void) bfd_close (abfd);
+ bfd_close (abfd);
return false;
}
}
if (bfd_stat (abfd, &global_stat) != 0)
einfo ("%F%P:%B: bfd_stat failed: %E\n", abfd);
+
+ /* First strip off everything before the last '/'. */
+ soname = basename (abfd->filename);
+
+ if (trace_file_tries)
+ info_msg (_("found %s at %s\n"), soname, name);
+
global_found = false;
lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed);
if (global_found)
return true;
}
- /* Tell the ELF backend that don't want the output file to have a
+ /* Tell the ELF backend that we don't want the output file to have a
DT_NEEDED entry for this file. */
bfd_elf_set_dt_needed_name (abfd, "");
- /* First strip off everything before the last '/'. */
- name = strrchr (abfd->filename, '/');
- if (name)
- name++;
- else
- name = abfd->filename;
+ /* Previos basename call was clobbered in lang_for_each_input_file. */
+ soname = basename (abfd->filename);
/* Tell the ELF backend that the output file needs a DT_NEEDED
entry for this file if it is used to resolve the reference in
a regular object. */
- bfd_elf_set_dt_needed_soname (abfd, name);
+ bfd_elf_set_dt_needed_soname (abfd, soname);
/* Add this file into the symbol table. */
if (! bfd_link_add_symbols (abfd, &link_info))
return true;
}
-/* See if an input file matches a DT_NEEDED entry by name. */
-static void
-gld${EMULATION_NAME}_check_needed (s)
- lang_input_statement_type *s;
+/* Search for a needed file in a path. */
+
+static boolean
+gld${EMULATION_NAME}_search_needed (path, name, force)
+ const char *path;
+ const char *name;
+ int force;
{
- if (global_found)
- return;
+ const char *s;
+ size_t len;
- if (s->filename != NULL
- && strcmp (s->filename, global_needed->name) == 0)
- {
- global_found = true;
- return;
- }
+ if (name[0] == '/')
+ return gld${EMULATION_NAME}_try_needed (name, force);
- if (s->the_bfd != NULL)
+ if (path == NULL || *path == '\0')
+ return false;
+ len = strlen (name);
+ while (1)
{
- const char *soname;
+ char *filename, *sset;
- soname = bfd_elf_get_dt_soname (s->the_bfd);
- if (soname != NULL
- && strcmp (soname, global_needed->name) == 0)
- {
- global_found = true;
- return;
- }
- }
-
- if (s->search_dirs_flag
- && s->filename != NULL
- && strchr (global_needed->name, '/') == NULL)
- {
- const char *f;
+ s = strchr (path, ':');
+ if (s == NULL)
+ s = path + strlen (path);
- f = strrchr (s->filename, '/');
- if (f != NULL
- && strcmp (f + 1, global_needed->name) == 0)
+ filename = (char *) xmalloc (s - path + len + 2);
+ if (s == path)
+ sset = filename;
+ else
{
- global_found = true;
- return;
+ memcpy (filename, path, s - path);
+ filename[s - path] = '/';
+ sset = filename + (s - path) + 1;
}
- }
-}
+ strcpy (sset, name);
-/* See if an input file matches a DT_NEEDED entry by running stat on
- the file. */
+ if (gld${EMULATION_NAME}_try_needed (filename, force))
+ return true;
-static void
-gld${EMULATION_NAME}_stat_needed (s)
- lang_input_statement_type *s;
-{
- struct stat st;
- const char *suffix;
- const char *soname;
- const char *f;
-
- if (global_found)
- return;
- if (s->the_bfd == NULL)
- return;
+ free (filename);
- if (bfd_stat (s->the_bfd, &st) != 0)
- {
- einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd);
- return;
+ if (*s == '\0')
+ break;
+ path = s + 1;
}
- if (st.st_dev == global_stat.st_dev
- && st.st_ino == global_stat.st_ino)
+ return false;
+}
+
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+ case " ${EMULATION_LIBPATH} " in
+ *" ${EMULATION_NAME} "*)
+ case ${target} in
+ *-*-linux-gnu*)
+ cat >>e${EMULATION_NAME}.c <<EOF
+
+/* For a native linker, check the file /etc/ld.so.conf for directories
+ in which we may find shared libraries. /etc/ld.so.conf is really
+ only meaningful on Linux. */
+
+static boolean gld${EMULATION_NAME}_check_ld_so_conf
+ PARAMS ((const char *, int));
+
+static boolean
+gld${EMULATION_NAME}_check_ld_so_conf (name, force)
+ const char *name;
+ int force;
+{
+ static boolean initialized;
+ static char *ld_so_conf;
+
+ if (! initialized)
{
- global_found = true;
- return;
+ FILE *f;
+
+ f = fopen ("/etc/ld.so.conf", FOPEN_RT);
+ if (f != NULL)
+ {
+ char *b;
+ size_t len, alloc;
+ int c;
+
+ len = 0;
+ alloc = 100;
+ b = (char *) xmalloc (alloc);
+
+ while ((c = getc (f)) != EOF)
+ {
+ if (len + 1 >= alloc)
+ {
+ alloc *= 2;
+ b = (char *) xrealloc (b, alloc);
+ }
+ if (c != ':'
+ && c != ' '
+ && c != '\t'
+ && c != '\n'
+ && c != ',')
+ {
+ b[len] = c;
+ ++len;
+ }
+ else
+ {
+ if (len > 0 && b[len - 1] != ':')
+ {
+ b[len] = ':';
+ ++len;
+ }
+ }
+ }
+
+ if (len > 0 && b[len - 1] == ':')
+ --len;
+
+ if (len > 0)
+ b[len] = '\0';
+ else
+ {
+ free (b);
+ b = NULL;
+ }
+
+ fclose (f);
+
+ ld_so_conf = b;
+ }
+
+ initialized = true;
}
- /* We issue a warning if it looks like we are including two
- different versions of the same shared library. For example,
- there may be a problem if -lc picks up libc.so.6 but some other
- shared library has a DT_NEEDED entry of libc.so.5. This is a
- hueristic test, and it will only work if the name looks like
- NAME.so.VERSION. FIXME: Depending on file names is error-prone.
- If we really want to issue warnings about mixing version numbers
- of shared libraries, we need to find a better way. */
+ if (ld_so_conf == NULL)
+ return false;
- if (strchr (global_needed->name, '/') != NULL)
- return;
- suffix = strstr (global_needed->name, ".so.");
- if (suffix == NULL)
+ return gld${EMULATION_NAME}_search_needed (ld_so_conf, name, force);
+}
+
+EOF
+ # Linux
+ ;;
+ esac
+ esac
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* See if an input file matches a DT_NEEDED entry by name. */
+
+static void
+gld${EMULATION_NAME}_check_needed (s)
+ lang_input_statement_type *s;
+{
+ if (global_found)
return;
- suffix += sizeof ".so." - 1;
- soname = bfd_elf_get_dt_soname (s->the_bfd);
- if (soname == NULL)
- soname = s->filename;
+ if (s->filename != NULL)
+ {
+ const char *f;
- f = strrchr (soname, '/');
- if (f != NULL)
- ++f;
- else
- f = soname;
+ if (strcmp (s->filename, global_needed->name) == 0)
+ {
+ global_found = true;
+ return;
+ }
- if (strncmp (f, global_needed->name, suffix - global_needed->name) == 0)
- einfo ("%P: warning: %s, needed by %B, may conflict with %s\n",
- global_needed->name, global_needed->by, f);
+ if (s->search_dirs_flag)
+ {
+ f = strrchr (s->filename, '/');
+ if (f != NULL
+ && strcmp (f + 1, global_needed->name) == 0)
+ {
+ global_found = true;
+ return;
+ }
+ }
+ }
+
+ if (s->the_bfd != NULL)
+ {
+ const char *soname;
+
+ soname = bfd_elf_get_dt_soname (s->the_bfd);
+ if (soname != NULL
+ && strcmp (soname, global_needed->name) == 0)
+ {
+ global_found = true;
+ return;
+ }
+ }
}
-/* 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.
+EOF
- 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.
+if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then
+cat >>e${EMULATION_NAME}.c <<EOF
- 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. */
+/* This is called after all the input files have been opened. */
static void
-gld${EMULATION_NAME}_vercheck (s)
- lang_input_statement_type *s;
+gld${EMULATION_NAME}_after_open ()
{
- const char *soname, *f;
- struct bfd_link_needed_list *l;
+ struct bfd_link_needed_list *needed, *l;
- if (global_vercheck_failed)
- return;
- if (s->the_bfd == NULL
- || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0)
+ /* We only need to worry about this when doing a final link. */
+ if (link_info.relocateable || link_info.shared)
return;
- soname = bfd_elf_get_dt_soname (s->the_bfd);
- if (soname == NULL)
- soname = bfd_get_filename (s->the_bfd);
+ /* Get the list of files which appear in DT_NEEDED entries in
+ dynamic objects included in the link (often there will be none).
+ For each such file, we want to track down the corresponding
+ library, and include the symbol table in the link. This is what
+ the runtime dynamic linker will do. Tracking the files down here
+ permits one dynamic object to include another without requiring
+ special action by the person doing the link. Note that the
+ needed list can actually grow while we are stepping through this
+ loop. */
+ needed = bfd_elf_get_needed_list (output_bfd, &link_info);
+ for (l = needed; l != NULL; l = l->next)
+ {
+ struct bfd_link_needed_list *ll;
+ int force;
- f = strrchr (soname, '/');
- if (f != NULL)
- ++f;
- else
- f = soname;
+ /* If we've already seen this file, skip it. */
+ for (ll = needed; ll != l; ll = ll->next)
+ if (strcmp (ll->name, l->name) == 0)
+ break;
+ if (ll != l)
+ continue;
- for (l = global_vercheck_needed; l != NULL; l = l->next)
- {
- const char *suffix;
+ /* See if this file was included in the link explicitly. */
+ global_needed = l;
+ global_found = false;
+ lang_for_each_input_file (gld${EMULATION_NAME}_check_needed);
+ if (global_found)
+ continue;
- if (strcmp (f, l->name) == 0)
+ if (trace_file_tries)
+ info_msg (_("%s needed by %B\n"), l->name, l->by);
+
+ /* We need to find this file and include the symbol table. We
+ want to search for the file in the same way that the dynamic
+ linker will search. That means that we want to use
+ rpath_link, rpath, then the environment variable
+ LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH
+ entries (native only), then the linker script 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++)
{
- /* Probably can't happen, but it's an easy check. */
- continue;
+ size_t len;
+ search_dirs_type *search;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+ case " ${EMULATION_LIBPATH} " in
+ *" ${EMULATION_NAME} "*)
+cat >>e${EMULATION_NAME}.c <<EOF
+ const char *lib_path;
+ struct bfd_link_needed_list *rp;
+ int found;
+EOF
+ ;;
+ esac
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
+
+ if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
+ l->name, force))
+ break;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+ case " ${EMULATION_LIBPATH} " in
+ *" ${EMULATION_NAME} "*)
+cat >>e${EMULATION_NAME}.c <<EOF
+ 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;
+ }
+ lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
+ if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force))
+ break;
+
+ found = 0;
+ rp = bfd_elf_get_runpath_list (output_bfd, &link_info);
+ for (; !found && rp != NULL; rp = rp->next)
+ {
+ found = (rp->by == l->by
+ && gld${EMULATION_NAME}_search_needed (rp->name,
+ l->name,
+ force));
+ }
+ if (found)
+ break;
+
+EOF
+ ;;
+ esac
+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, force))
+ break;
+ free (filename);
+ }
+ if (search != NULL)
+ break;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+ case " ${EMULATION_LIBPATH} " in
+ *" ${EMULATION_NAME} "*)
+ case ${target} in
+ *-*-linux-gnu*)
+ cat >>e${EMULATION_NAME}.c <<EOF
+ if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force))
+ break;
+EOF
+ # Linux
+ ;;
+ esac
+ ;;
+ esac
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
}
- if (strchr (l->name, '/') != NULL)
+ if (force < 2)
continue;
- suffix = strstr (l->name, ".so.");
- if (suffix == NULL)
- continue;
+ einfo ("%P: warning: %s, needed by %B, not found (try using -rpath or -rpath-link)\n",
+ l->name, l->by);
+ }
+}
- suffix += sizeof ".so." - 1;
+EOF
+fi
+
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* Look through an expression for an assignment statement. */
+
+static void
+gld${EMULATION_NAME}_find_exp_assignment (exp)
+ etree_type *exp;
+{
+ struct bfd_link_hash_entry *h;
+
+ switch (exp->type.node_class)
+ {
+ case etree_provide:
+ h = bfd_link_hash_lookup (link_info.hash, exp->assign.dst,
+ false, false, false);
+ if (h == NULL)
+ break;
+
+ /* We call record_link_assignment even if the symbol is defined.
+ This is because if it is defined by a dynamic object, we
+ actually want to use the value defined by the linker script,
+ not the value from the dynamic object (because we are setting
+ symbols like etext). If the symbol is defined by a regular
+ object, then, as it happens, calling record_link_assignment
+ will do no harm. */
- if (strncmp (f, l->name, suffix - l->name) == 0)
+ /* Fall through. */
+ case etree_assign:
+ if (strcmp (exp->assign.dst, ".") != 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;
+ if (! (bfd_elf${ELFSIZE}_record_link_assignment
+ (output_bfd, &link_info, exp->assign.dst,
+ exp->type.node_class == etree_provide ? true : false)))
+ einfo ("%P%F: failed to record assignment to %s: %E\n",
+ exp->assign.dst);
}
+ gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src);
+ break;
+
+ case etree_binary:
+ gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs);
+ gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs);
+ break;
+
+ case etree_trinary:
+ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond);
+ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs);
+ gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs);
+ break;
+
+ case etree_unary:
+ gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child);
+ break;
+
+ default:
+ break;
}
}
+
+/* This is called by the before_allocation routine via
+ lang_for_each_statement. It locates any assignment statements, and
+ tells the ELF backend about them, in case they are assignments to
+ symbols which are referred to by dynamic objects. */
+
+static void
+gld${EMULATION_NAME}_find_statement_assignment (s)
+ lang_statement_union_type *s;
+{
+ if (s->header.type == lang_assignment_statement_enum)
+ gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
+}
+
+EOF
+
+if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then
+ if test x"${ELF_INTERPRETER_NAME+set}" = xset; then
+ ELF_INTERPRETER_SET_DEFAULT="
+ if (sinterp != NULL)
+ {
+ sinterp->contents = ${ELF_INTERPRETER_NAME};
+ sinterp->_raw_size = strlen (sinterp->contents) + 1;
+ }
+
+"
+ else
+ ELF_INTERPRETER_SET_DEFAULT=
+ fi
+cat >>e${EMULATION_NAME}.c <<EOF
+
/* This is called after the sections have been attached to output
sections, but before any sizes or addresses have been set. */
rpath = (const char *) getenv ("LD_RUN_PATH");
if (! (bfd_elf${ELFSIZE}_size_dynamic_sections
(output_bfd, command_line.soname, rpath,
- command_line.export_dynamic, command_line.filter_shlib,
+ command_line.filter_shlib,
(const char * const *) command_line.auxiliary_filters,
&link_info, &sinterp, lang_elf_version_info)))
einfo ("%P%F: failed to set dynamic section sizes: %E\n");
-
+${ELF_INTERPRETER_SET_DEFAULT}
/* Let the user override the dynamic linker we are using. */
if (command_line.interpreter != NULL
&& sinterp != NULL)
sinterp->_raw_size = strlen (command_line.interpreter) + 1;
}
- /* Look for any sections named .gnu.warning. As a GNU extensions,
- we treat such sections as containing warning messages. We print
- out the warning message, and then zero out the section size so
- that it does not get copied into the output file. */
+ /* Look for any sections named .gnu.warning. As a GNU extensions,
+ we treat such sections as containing warning messages. We print
+ out the warning message, and then zero out the section size so
+ that it does not get copied into the output file. */
+
+ {
+ LANG_FOR_EACH_INPUT_STATEMENT (is)
+ {
+ asection *s;
+ bfd_size_type sz;
+ char *msg;
+ boolean ret;
+
+ if (is->just_syms_flag)
+ continue;
+
+ s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning");
+ if (s == NULL)
+ continue;
+
+ sz = bfd_section_size (is->the_bfd, s);
+ msg = xmalloc ((size_t) sz + 1);
+ if (! bfd_get_section_contents (is->the_bfd, s, msg, (file_ptr) 0, sz))
+ einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n",
+ is->the_bfd);
+ msg[sz] = '\0';
+ ret = link_info.callbacks->warning (&link_info, msg,
+ (const char *) NULL,
+ is->the_bfd, (asection *) NULL,
+ (bfd_vma) 0);
+ ASSERT (ret);
+ free (msg);
+
+ /* Clobber the section size, so that we don't waste copying the
+ warning into the output file. */
+ s->_raw_size = 0;
+ }
+ }
+}
+
+EOF
+fi
+
+if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+/* Try to open a dynamic archive. This is where we know that ELF
+ dynamic libraries have an extension of .so (or .sl on oddball systems
+ like hpux). */
+
+static boolean
+gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry)
+ const char *arch;
+ search_dirs_type *search;
+ lang_input_statement_type *entry;
+{
+ const char *filename;
+ char *string;
+
+ if (! entry->is_archive)
+ return false;
+
+ filename = entry->filename;
+
+ /* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION
+ is defined, but it does not seem worth the headache to optimize
+ away those two bytes of space. */
+ string = (char *) xmalloc (strlen (search->name)
+ + strlen (filename)
+ + strlen (arch)
+#ifdef EXTRA_SHLIB_EXTENSION
+ + strlen (EXTRA_SHLIB_EXTENSION)
+#endif
+ + sizeof "/lib.so");
+
+ sprintf (string, "%s/lib%s%s.so", search->name, filename, arch);
+
+#ifdef EXTRA_SHLIB_EXTENSION
+ /* Try the .so extension first. If that fails build a new filename
+ using EXTRA_SHLIB_EXTENSION. */
+ if (! ldfile_try_open_bfd (string, entry))
+ sprintf (string, "%s/lib%s%s%s", search->name,
+ filename, arch, EXTRA_SHLIB_EXTENSION);
+#endif
+
+ if (! ldfile_try_open_bfd (string, entry))
+ {
+ free (string);
+ return false;
+ }
+
+ entry->filename = string;
- {
- LANG_FOR_EACH_INPUT_STATEMENT (is)
- {
- asection *s;
- bfd_size_type sz;
- char *msg;
- boolean ret;
+ /* We have found a dynamic object to include in the link. The ELF
+ backend linker will create a DT_NEEDED entry in the .dynamic
+ section naming this file. If this file includes a DT_SONAME
+ entry, it will be used. Otherwise, the ELF linker will just use
+ the name of the file. For an archive found by searching, like
+ this one, the DT_NEEDED entry should consist of just the name of
+ the file, without the path information used to find it. Note
+ that we only need to do this if we have a dynamic object; an
+ archive will never be referenced by a DT_NEEDED entry.
- if (is->just_syms_flag)
- continue;
+ FIXME: This approach--using bfd_elf_set_dt_needed_name--is not
+ very pretty. I haven't been able to think of anything that is
+ pretty, though. */
+ if (bfd_check_format (entry->the_bfd, bfd_object)
+ && (entry->the_bfd->flags & DYNAMIC) != 0)
+ {
+ ASSERT (entry->is_archive && entry->search_dirs_flag);
- s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning");
- if (s == NULL)
- continue;
+ /* Rather than duplicating the logic above. Just use the
+ filename we recorded earlier. */
- sz = bfd_section_size (is->the_bfd, s);
- msg = xmalloc ((size_t) sz + 1);
- if (! bfd_get_section_contents (is->the_bfd, s, msg, (file_ptr) 0, sz))
- einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n",
- is->the_bfd);
- msg[sz] = '\0';
- ret = link_info.callbacks->warning (&link_info, msg,
- (const char *) NULL,
- is->the_bfd, (asection *) NULL,
- (bfd_vma) 0);
- ASSERT (ret);
- free (msg);
+ filename = xstrdup (basename (entry->filename));
+ bfd_elf_set_dt_needed_name (entry->the_bfd, filename);
+ }
- /* Clobber the section size, so that we don't waste copying the
- warning into the output file. */
- s->_raw_size = 0;
- }
- }
+ return true;
}
-/* This is called by the before_allocation routine via
- lang_for_each_statement. It locates any assignment statements, and
- tells the ELF backend about them, in case they are assignments to
- symbols which are referred to by dynamic objects. */
+EOF
+fi
-static void
-gld${EMULATION_NAME}_find_statement_assignment (s)
- lang_statement_union_type *s;
-{
- if (s->header.type == lang_assignment_statement_enum)
- gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
-}
+if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
+cat >>e${EMULATION_NAME}.c <<EOF
-/* Look through an expression for an assignment statement. */
+/* A variant of lang_output_section_find. Used by place_orphan. */
-static void
-gld${EMULATION_NAME}_find_exp_assignment (exp)
- etree_type *exp;
+static lang_output_section_statement_type *
+output_rel_find ()
{
- struct bfd_link_hash_entry *h;
+ lang_statement_union_type *u;
+ lang_output_section_statement_type *lookup;
- switch (exp->type.node_class)
+ for (u = lang_output_section_statement.head;
+ u != (lang_statement_union_type *) NULL;
+ u = lookup->next)
{
- case etree_provide:
- h = bfd_link_hash_lookup (link_info.hash, exp->assign.dst,
- false, false, false);
- if (h == NULL)
- break;
-
- /* We call record_link_assignment even if the symbol is defined.
- This is because if it is defined by a dynamic object, we
- actually want to use the value defined by the linker script,
- not the value from the dynamic object (because we are setting
- symbols like etext). If the symbol is defined by a regular
- object, then, as it happens, calling record_link_assignment
- will do no harm. */
-
- /* Fall through. */
- case etree_assign:
- if (strcmp (exp->assign.dst, ".") != 0)
+ lookup = &u->output_section_statement;
+ if (strncmp (".rel", lookup->name, 4) == 0
+ && lookup->bfd_section != NULL
+ && (lookup->bfd_section->flags & SEC_ALLOC) != 0)
{
- if (! (bfd_elf${ELFSIZE}_record_link_assignment
- (output_bfd, &link_info, exp->assign.dst,
- exp->type.node_class == etree_provide ? true : false)))
- einfo ("%P%F: failed to record assignment to %s: %E\n",
- exp->assign.dst);
+ return lookup;
}
- gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src);
- break;
+ }
+ return (lang_output_section_statement_type *) NULL;
+}
- case etree_binary:
- gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs);
- gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs);
- break;
+/* Find the last output section before given output statement.
+ Used by place_orphan. */
- case etree_trinary:
- gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond);
- gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs);
- gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs);
- break;
+static asection *
+output_prev_sec_find (os)
+ lang_output_section_statement_type *os;
+{
+ asection *s = (asection *) NULL;
+ lang_statement_union_type *u;
+ lang_output_section_statement_type *lookup;
- case etree_unary:
- gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child);
- break;
+ for (u = lang_output_section_statement.head;
+ u != (lang_statement_union_type *) NULL;
+ u = lookup->next)
+ {
+ lookup = &u->output_section_statement;
+ if (lookup == os)
+ return s;
- default:
- break;
+ if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
+ s = lookup->bfd_section;
}
+
+ return NULL;
}
/* Place an orphan section. We use this to put random SHF_ALLOC
sections in the right segment. */
-struct orphan_save
-{
+struct orphan_save {
lang_output_section_statement_type *os;
asection **section;
lang_statement_union_type **stmt;
};
-/*ARGSUSED*/
static boolean
gld${EMULATION_NAME}_place_orphan (file, s)
lang_input_statement_type *file;
static struct orphan_save hold_bss;
static struct orphan_save hold_rel;
static struct orphan_save hold_interp;
+ static struct orphan_save hold_sdata;
+ static int count = 1;
struct orphan_save *place;
lang_statement_list_type *old;
lang_statement_list_type add;
etree_type *address;
- const char *secname, *ps;
+ const char *secname;
const char *outsecname;
+ const char *ps = NULL;
lang_output_section_statement_type *os;
secname = bfd_get_section_name (s->owner, s);
- /* Look through the script to see where to place this section. */
- os = lang_output_section_find (secname);
-
- if (os != NULL
- && os->bfd_section != NULL
- && ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0)
+ if (! config.unique_orphan_sections && ! unique_section_p (secname))
{
- /* We have already placed a section with this name. */
- wild_doit (&os->children, s, os, file);
- return true;
+ /* Look through the script to see where to place this section. */
+ os = lang_output_section_find (secname);
+
+ if (os != NULL
+ && (os->bfd_section == NULL
+ || ((s->flags ^ os->bfd_section->flags)
+ & (SEC_LOAD | SEC_ALLOC)) == 0))
+ {
+ /* We already have an output section statement with this
+ name, and its bfd section, if any, has compatible flags. */
+ lang_add_section (&os->children, s, os, file);
+ return true;
+ }
}
if (hold_text.os == NULL)
&& strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
&& hold_text.os != NULL)
{
- wild_doit (&hold_text.os->children, s, hold_text.os, file);
+ lang_add_section (&hold_text.os->children, s, hold_text.os, file);
return true;
}
(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
if (s->flags & SEC_EXCLUDE)
- return false;
- else if ((s->flags & SEC_ALLOC) == 0)
- place = NULL;
+ {
+ if (s->output_section == NULL)
+ s->output_section = bfd_abs_section_ptr;
+ return true;
+ }
+
+ place = NULL;
+ if ((s->flags & SEC_ALLOC) == 0)
+ ;
else if ((s->flags & SEC_LOAD) != 0
- && strncmp (secname, ".note", 4) == 0
+ && strncmp (secname, ".note", 5) == 0
&& HAVE_SECTION (hold_interp, ".interp"))
place = &hold_interp;
else if ((s->flags & SEC_HAS_CONTENTS) == 0
&& HAVE_SECTION (hold_bss, ".bss"))
place = &hold_bss;
+ else if ((s->flags & SEC_SMALL_DATA) != 0
+ && HAVE_SECTION (hold_sdata, ".sdata"))
+ place = &hold_sdata;
else if ((s->flags & SEC_READONLY) == 0
&& HAVE_SECTION (hold_data, ".data"))
place = &hold_data;
else if (strncmp (secname, ".rel", 4) == 0
&& (hold_rel.os != NULL
|| (hold_rel.os = output_rel_find ()) != NULL))
- place = &hold_rel;
- else if ((s->flags & SEC_CODE) == 0
- && (s->flags & SEC_READONLY) != 0
+ {
+ if (! link_info.relocateable && link_info.combreloc)
+ {
+ if (strncmp (secname, ".rela", 5) == 0)
+ os = lang_output_section_find (".rela.dyn");
+ else
+ os = lang_output_section_find (".rel.dyn");
+
+ if (os != NULL
+ && os->bfd_section != NULL
+ && ((s->flags ^ os->bfd_section->flags)
+ & (SEC_LOAD | SEC_ALLOC)) == 0)
+ {
+ lang_add_section (&os->children, s, os, file);
+ return true;
+ }
+ }
+ place = &hold_rel;
+ }
+ else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
&& HAVE_SECTION (hold_rodata, ".rodata"))
place = &hold_rodata;
- else if ((s->flags & SEC_READONLY) != 0
+ else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
&& hold_text.os != NULL)
place = &hold_text;
- else
- place = NULL;
#undef HAVE_SECTION
/* Choose a unique name for the section. This will be needed if the
same section name appears in the input file with different
- loadable or allocateable characteristics. */
+ loadable or allocatable characteristics. */
outsecname = secname;
if (bfd_get_section_by_name (output_bfd, outsecname) != NULL)
{
- unsigned int len;
- char *newname;
- unsigned int i;
-
- len = strlen (outsecname);
- newname = xmalloc (len + 5);
- strcpy (newname, outsecname);
- i = 0;
- do
- {
- sprintf (newname + len, "%d", i);
- ++i;
- }
- while (bfd_get_section_by_name (output_bfd, newname) != NULL);
-
- outsecname = newname;
+ outsecname = bfd_get_unique_section_name (output_bfd,
+ outsecname,
+ &count);
+ if (outsecname == NULL)
+ einfo ("%F%P: place_orphan failed: %E\n");
}
+ /* Start building a list of statements for this section.
+ First save the current statement pointer. */
+ old = stat_ptr;
+
+ /* If we have found an appropriate place for the output section
+ statements for this orphan, add them to our own private list,
+ inserting them later into the global statement list. */
if (place != NULL)
{
- /* Start building a list of statements for this section. */
- old = stat_ptr;
stat_ptr = &add;
lang_list_init (stat_ptr);
+ }
+ if (config.build_constructors)
+ {
/* 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 ((unsigned char) *ps) && *ps != '_')
+ if (! ISALNUM (*ps) && *ps != '_')
break;
- if (*ps == '\0' && config.build_constructors)
+ if (*ps == '\0')
{
char *symname;
etree_type *e_align;
(etree_type *) NULL,
(etree_type *) NULL);
- wild_doit (&os->children, s, os, file);
+ lang_add_section (&os->children, s, os, file);
lang_leave_output_section_statement
((bfd_vma) 0, "*default*",
(struct lang_output_section_phdr_list *) NULL, "*default*");
+ if (config.build_constructors && *ps == '\0')
+ {
+ char *symname;
+
+ /* lang_leave_ouput_section_statement resets stat_ptr. Put
+ stat_ptr back where we want it. */
+ if (place != NULL)
+ stat_ptr = &add;
+
+ symname = (char *) xmalloc (ps - outsecname + sizeof "__stop_");
+ sprintf (symname, "__stop_%s", outsecname);
+ lang_add_assignment (exp_assop ('=', symname,
+ exp_nameop (NAME, ".")));
+ }
+
+ /* Restore the global list pointer. */
+ stat_ptr = old;
+
if (place != NULL)
{
asection *snew, **pps;
- stat_ptr = &add;
+ snew = os->bfd_section;
- if (*ps == '\0' && config.build_constructors)
+ /* Shuffle the bfd section list to make the output file look
+ neater. This is really only cosmetic. */
+ if (place->section == NULL)
{
- char *symname;
+ asection *bfd_section = place->os->bfd_section;
+
+ /* If the output statement hasn't been used to place
+ any input sections (and thus doesn't have an output
+ bfd_section), look for the closest prior output statement
+ having an output section. */
+ if (bfd_section == NULL)
+ bfd_section = output_prev_sec_find (place->os);
- symname = (char *) xmalloc (ps - outsecname + sizeof "__stop_");
- sprintf (symname, "__stop_%s", outsecname);
- lang_add_assignment (exp_assop ('=', symname,
- exp_nameop (NAME, ".")));
+ if (bfd_section != NULL && bfd_section != snew)
+ place->section = &bfd_section->next;
}
- stat_ptr = old;
- snew = os->bfd_section;
- if (place->os->bfd_section != NULL || place->section != NULL)
+ if (place->section != NULL)
{
- /* Shuffle the section to make the output file look neater. */
- if (place->section == NULL)
- {
-#if 0
- /* Finding the end of the list is a little tricky. We
- make a wild stab at it by comparing section flags. */
- flagword first_flags = place->os->bfd_section->flags;
- for (pps = &place->os->bfd_section->next;
- *pps != NULL && (*pps)->flags == first_flags;
- pps = &(*pps)->next)
- ;
- place->section = pps;
-#else
- /* Put orphans after the first section on the list. */
- place->section = &place->os->bfd_section->next;
-#endif
- }
-
/* Unlink the section. */
for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
;
snew->next = *place->section;
*place->section = snew;
}
- place->section = &snew->next; /* Save the end of this list. */
- if (place->stmt == NULL)
- {
- /* Put the new statement list right at the head. */
- *add.tail = place->os->header.next;
- place->os->header.next = add.head;
- }
- else
+ /* Save the end of this list. Further ophans of this type will
+ follow the one we've just added. */
+ place->section = &snew->next;
+
+ /* The following is non-cosmetic. We try to put the output
+ statements in some sort of reasonable order here, because
+ they determine the final load addresses of the orphan
+ sections. In addition, placing output statements in the
+ wrong order may require extra segments. For instance,
+ given a typical situation of all read-only sections placed
+ in one segment and following that a segment containing all
+ the read-write sections, we wouldn't want to place an orphan
+ read/write section before or amongst the read-only ones. */
+ if (add.head != NULL)
{
- /* Put it after the last orphan statement we added. */
- *add.tail = *place->stmt;
- *place->stmt = add.head;
+ if (place->stmt == NULL)
+ {
+ /* Put the new statement list right at the head. */
+ *add.tail = place->os->header.next;
+ place->os->header.next = add.head;
+ }
+ else
+ {
+ /* Put it after the last orphan statement we added. */
+ *add.tail = *place->stmt;
+ *place->stmt = add.head;
+ }
+
+ /* Fix the global list pointer if we happened to tack our
+ new list at the tail. */
+ if (*old->tail == add.head)
+ old->tail = add.tail;
+
+ /* Save the end of this list. */
+ place->stmt = add.tail;
}
- place->stmt = add.tail; /* Save the end of this list. */
}
return true;
}
-/* A variant of lang_output_section_find. */
-static lang_output_section_statement_type *
-output_rel_find ()
-{
- lang_statement_union_type *u;
- lang_output_section_statement_type *lookup;
+EOF
+fi
- for (u = lang_output_section_statement.head;
- u != (lang_statement_union_type *) NULL;
- u = lookup->next)
- {
- lookup = &u->output_section_statement;
- if (strncmp (".rel", lookup->name, 4) == 0
- && lookup->bfd_section != NULL
- && (lookup->bfd_section->flags & SEC_ALLOC) != 0)
- {
- return lookup;
- }
- }
- return (lang_output_section_statement_type *) NULL;
-}
+if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then
+cat >>e${EMULATION_NAME}.c <<EOF
static char *
-gld${EMULATION_NAME}_get_script(isfile)
+gld${EMULATION_NAME}_get_script (isfile)
int *isfile;
EOF
sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c
echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c
+if ! cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then
echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c
-
+fi
if test -n "$GENERATE_SHLIB_SCRIPT" ; then
+echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c
echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c
fi
-
+echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c
echo ' ; else return' >> e${EMULATION_NAME}.c
sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c
echo '; }' >> e${EMULATION_NAME}.c
else
return "ldscripts/${EMULATION_NAME}.x";
}
-EOF
-
-fi
-
-if test -n "$PARSE_AND_LIST_ARGS_CASES" || test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
-NEED_PARSE_AND_LIST=yes
-cat >>e${EMULATION_NAME}.c <<EOF
-static int gld_${EMULATION_NAME}_parse_args PARAMS ((int, char **));
-static void gld_${EMULATION_NAME}_list_options PARAMS ((FILE * file));
EOF
-else
-NEED_PARSE_AND_LIST=no
+fi
+fi
-cat >>e${EMULATION_NAME}.c <<EOF
-#define gld_${EMULATION_NAME}_parse_args NULL
-#define gld_${EMULATION_NAME}_list_options NULL
-EOF
+if test -n "$PARSE_AND_LIST_ARGS_CASES" -o x"$GENERATE_SHLIB_SCRIPT" = xyes; then
-fi
+if test x"$LDEMUL_PARSE_ARGS" != xgld"$EMULATION_NAME"_parse_args; then
if test -n "$PARSE_AND_LIST_PROLOGUE" ; then
cat >>e${EMULATION_NAME}.c <<EOF
EOF
fi
-if test "$NEED_PARSE_AND_LIST" = yes; then
cat >>e${EMULATION_NAME}.c <<EOF
#include "getopt.h"
+#define OPTION_DISABLE_NEW_DTAGS (400)
+#define OPTION_ENABLE_NEW_DTAGS (OPTION_DISABLE_NEW_DTAGS + 1)
+#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1)
+
static struct option longopts[] =
{
EOF
-fi
if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
cat >>e${EMULATION_NAME}.c <<EOF
- {NULL, required_argument, NULL, 'z'},
+ /* getopt allows abbreviations, so we do this to stop it from
+ treating -d/-e as abbreviations for these options. */
+ {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
+ {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
+ {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
+ {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
+ {"Bgroup", no_argument, NULL, OPTION_GROUP},
+ {"Bgroup", no_argument, NULL, OPTION_GROUP},
EOF
fi
EOF
fi
-if test "$NEED_PARSE_AND_LIST" = yes; then
cat >>e${EMULATION_NAME}.c <<EOF
{NULL, no_argument, NULL, 0}
};
+
+static int gld${EMULATION_NAME}_parse_args PARAMS ((int, char **));
+
static int
-gld_${EMULATION_NAME}_parse_args (argc, argv)
+gld${EMULATION_NAME}_parse_args (argc, argv)
int argc;
char ** argv;
{
- int longind, optc;
- int prevoptind = optind;
+ int longind;
+ int optc;
+ static int prevoptind = -1;
int prevopterr = opterr;
int wanterror;
- static int lastoptind = -1;
- if (lastoptind != optind)
+ if (prevoptind != optind)
opterr = 0;
- wanterror = opterr;
- optc = getopt_long_only (argc, argv, "-z:", longopts, &longind);
+ wanterror = opterr;
+ prevoptind = optind;
+
+ optc = getopt_long_only (argc, argv,
+ "-${PARSE_AND_LIST_SHORTOPTS}z:", longopts,
+ &longind);
opterr = prevopterr;
switch (optc)
default:
if (wanterror)
xexit (1);
- optind = prevoptind;
+ optind = prevoptind;
return 0;
+
EOF
-fi
if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
cat >>e${EMULATION_NAME}.c <<EOF
+ case OPTION_DISABLE_NEW_DTAGS:
+ link_info.new_dtags = false;
+ break;
+
+ case OPTION_ENABLE_NEW_DTAGS:
+ link_info.new_dtags = true;
+ break;
+
+ case OPTION_GROUP:
+ link_info.flags_1 |= (bfd_vma) DF_1_GROUP;
+ /* Groups must be self-contained. */
+ link_info.no_undefined = true;
+ break;
+
case 'z':
if (strcmp (optarg, "initfirst") == 0)
link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST;
link_info.flags |= (bfd_vma) DF_ORIGIN;
link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN;
}
+ else if (strcmp (optarg, "defs") == 0)
+ link_info.no_undefined = true;
+ else if (strcmp (optarg, "combreloc") == 0)
+ link_info.combreloc = true;
+ else if (strcmp (optarg, "nocombreloc") == 0)
+ link_info.combreloc = false;
/* What about the other Solaris -z options? FIXME. */
- break;
+ break;
EOF
fi
EOF
fi
-if test "$NEED_PARSE_AND_LIST" = yes; then
cat >>e${EMULATION_NAME}.c <<EOF
}
return 1;
}
+EOF
+fi
+
+if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static void gld${EMULATION_NAME}_list_options PARAMS ((FILE * file));
+
static void
-gld_${EMULATION_NAME}_list_options (file)
+gld${EMULATION_NAME}_list_options (file)
FILE * file;
{
EOF
-fi
if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
cat >>e${EMULATION_NAME}.c <<EOF
- fprintf (file, _(" -z initfirst\t\tMark DSO to be initialized first at rutime\n"));
- fprintf (file, _(" -z interpose\t\tMark object to interpose all DSOs but execuable\n"));
+ fprintf (file, _(" -Bgroup\t\tSelects group name lookup rules for DSO\n"));
+ fprintf (file, _(" --disable-new-dtags\tDisable new dynamic tags\n"));
+ fprintf (file, _(" --enable-new-dtags\tEnable new dynamic tags\n"));
+ fprintf (file, _(" -z defs\t\tDisallows undefined symbols\n"));
+ fprintf (file, _(" -z initfirst\t\tMark DSO to be initialized first at runtime\n"));
+ fprintf (file, _(" -z interpose\t\tMark object to interpose all DSOs but executable\n"));
fprintf (file, _(" -z loadfltr\t\tMark object requiring immediate process\n"));
fprintf (file, _(" -z nodefaultlib\tMark object not to use default search paths\n"));
fprintf (file, _(" -z nodelete\t\tMark DSO non-deletable at runtime\n"));
- fprintf (file, _(" -z nodlopen\t\tMark DSO not availale to dlopen\n"));
- fprintf (file, _(" -z nodump\t\tMark DSO not availale to dldump\n"));
+ fprintf (file, _(" -z nodlopen\t\tMark DSO not available to dlopen\n"));
+ fprintf (file, _(" -z nodump\t\tMark DSO not available to dldump\n"));
fprintf (file, _(" -z now\t\tMark object non-lazy runtime binding\n"));
fprintf (file, _(" -z origin\t\tMark object requiring immediate \$ORIGIN processing\n"));
fprintf (file, _("\t\t\t at runtime\n"));
EOF
fi
-if test "$NEED_PARSE_AND_LIST" = yes; then
cat >>e${EMULATION_NAME}.c <<EOF
}
EOF
-fi
if test -n "$PARSE_AND_LIST_EPILOGUE" ; then
cat >>e${EMULATION_NAME}.c <<EOF
$PARSE_AND_LIST_EPILOGUE
EOF
fi
+fi
+else
+if test x"$LDEMUL_PARSE_ARGS" != xgld"$EMULATION_NAME"_parse_args; then
+cat >>e${EMULATION_NAME}.c <<EOF
+#define gld${EMULATION_NAME}_parse_args NULL
+EOF
+fi
+if test x"$LDEMUL_LIST_OPTIONS" != xgld"$EMULATION_NAME"_list_options; then
+cat >>e${EMULATION_NAME}.c <<EOF
+#define gld${EMULATION_NAME}_list_options NULL
+EOF
+fi
+fi
cat >>e${EMULATION_NAME}.c <<EOF
struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
{
- gld${EMULATION_NAME}_before_parse,
- syslib_default,
- hll_default,
- after_parse_default,
- gld${EMULATION_NAME}_after_open,
- after_allocation_default,
- set_output_arch_default,
- ldemul_default_target,
- gld${EMULATION_NAME}_before_allocation,
- gld${EMULATION_NAME}_get_script,
+ ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
+ ${LDEMUL_SYSLIB-syslib_default},
+ ${LDEMUL_HLL-hll_default},
+ ${LDEMUL_AFTER_PARSE-after_parse_default},
+ ${LDEMUL_AFTER_OPEN-gld${EMULATION_NAME}_after_open},
+ ${LDEMUL_AFTER_ALLOCATION-after_allocation_default},
+ ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
+ ${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
+ ${LDEMUL_BEFORE_ALLOCATION-gld${EMULATION_NAME}_before_allocation},
+ ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script},
"${EMULATION_NAME}",
"${OUTPUT_FORMAT}",
- NULL, /* finish */
- NULL, /* create output section statements */
- gld${EMULATION_NAME}_open_dynamic_archive,
- gld${EMULATION_NAME}_place_orphan,
- NULL, /* set_symbols */
- gld_${EMULATION_NAME}_parse_args,
- NULL, /* unrecognized_file */
- gld_${EMULATION_NAME}_list_options,
- NULL, /* recognized_file */
- NULL /* find_potential_libraries */
+ ${LDEMUL_FINISH-NULL},
+ ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
+ ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-gld${EMULATION_NAME}_open_dynamic_archive},
+ ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
+ ${LDEMUL_SET_SYMBOLS-NULL},
+ ${LDEMUL_PARSE_ARGS-gld${EMULATION_NAME}_parse_args},
+ ${LDEMUL_UNRECOGNIZED_FILE-NULL},
+ ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options},
+ ${LDEMUL_RECOGNIZED_FILE-NULL},
+ ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
};
EOF