bfd/
[deliverable/binutils-gdb.git] / ld / emultempl / elf32.em
index cfe6407f49b061cdc3afa550d7dda6ac5606296e..641cd6321144270c49d6f60ee0c9a88c66b678d6 100644 (file)
@@ -13,7 +13,7 @@ cat >e${EMULATION_NAME}.c <<EOF
 
 /* ${ELFSIZE} bit ELF emulation code for ${EMULATION_NAME}
    Copyright 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Written by Steve Chamberlain <sac@cygnus.com>
    ELF support by Ian Lance Taylor <ian@cygnus.com>
 
@@ -35,10 +35,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #define TARGET_IS_${EMULATION_NAME}
 
+#include "config.h"
 #include "bfd.h"
 #include "sysdep.h"
 #include "libiberty.h"
 #include "safe-ctype.h"
+#include "getopt.h"
 
 #include "bfdlink.h"
 
@@ -51,43 +53,32 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "ldemul.h"
 #include <ldgram.h>
 #include "elf/common.h"
-#include "getopt.h"
 
-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 bfd_boolean gld${EMULATION_NAME}_try_needed
-  PARAMS ((const char *, int));
-static bfd_boolean gld${EMULATION_NAME}_search_needed
-  PARAMS ((const char *, const char *, int));
-static void gld${EMULATION_NAME}_check_needed
-  PARAMS ((lang_input_statement_type *));
-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}_before_allocation
-  PARAMS ((void));
-static bfd_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 ((asection *));
-static asection *output_prev_sec_find
-  PARAMS ((lang_output_section_statement_type *));
+/* Declare functions used by various EXTRA_EM_FILEs.  */
+static void gld${EMULATION_NAME}_before_parse (void);
+static void gld${EMULATION_NAME}_after_open (void);
+static void gld${EMULATION_NAME}_before_allocation (void);
 static bfd_boolean gld${EMULATION_NAME}_place_orphan
-  PARAMS ((lang_input_statement_type *, asection *));
-static void gld${EMULATION_NAME}_finish
-  PARAMS ((void));
-static char *gld${EMULATION_NAME}_get_script
-  PARAMS ((int *isfile));
+  (lang_input_statement_type *file, asection *s);
+static void gld${EMULATION_NAME}_layout_sections_again (void);
+static void gld${EMULATION_NAME}_strip_empty_sections (void);
+static void gld${EMULATION_NAME}_provide_init_fini_syms (void);
+static void gld${EMULATION_NAME}_finish (void) ATTRIBUTE_UNUSED;
 
 EOF
 
+if [ "x${USE_LIBPATH}" = xyes ] ; then
+  case ${target} in
+    *-*-linux-*)
+  cat >>e${EMULATION_NAME}.c <<EOF
+#ifdef HAVE_GLOB
+#include <glob.h>
+#endif
+EOF
+    ;;
+  esac
+fi
+
 # Import any needed special functions and/or overrides.
 #
 if test -n "$EXTRA_EM_FILE" ; then
@@ -104,17 +95,9 @@ 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 (void)
 {
-  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/:.*//'`;
+  ldfile_set_output_arch ("${OUTPUT_ARCH}", 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`;
 }
@@ -122,6 +105,39 @@ gld${EMULATION_NAME}_before_parse ()
 EOF
 fi
 
+if test x"$LDEMUL_RECOGNIZED_FILE" != xgld"${EMULATION_NAME}"_load_symbols; then
+cat >>e${EMULATION_NAME}.c <<EOF
+/* Handle as_needed DT_NEEDED.  */
+
+static bfd_boolean
+gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry)
+{
+  int class = 0;
+
+  /* Tell the ELF linker that we don't want the output file to have a
+     DT_NEEDED entry for this file, unless it is used to resolve
+     references in a regular object.  */
+  if (entry->as_needed)
+    class = DYN_AS_NEEDED;
+
+  /* Tell the ELF linker that we don't want the output file to have a
+     DT_NEEDED entry for any dynamic library in DT_NEEDED tags from
+     this file at all.  */
+  if (!entry->add_needed)
+    class |= DYN_NO_ADD_NEEDED;
+
+  if (!class
+      || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0)
+    return FALSE;
+
+  bfd_elf_set_dyn_lib_class (entry->the_bfd, class);
+
+  /* Continue on with normal load_symbols processing.  */
+  return FALSE;
+}
+EOF
+fi
+
 cat >>e${EMULATION_NAME}.c <<EOF
 
 /* These variables are required to pass information back and forth
@@ -152,8 +168,7 @@ static bfd_boolean global_vercheck_failed;
    a conflicting version.  */
 
 static void
-gld${EMULATION_NAME}_vercheck (s)
-     lang_input_statement_type *s;
+gld${EMULATION_NAME}_vercheck (lang_input_statement_type *s)
 {
   const char *soname;
   struct bfd_link_needed_list *l;
@@ -190,10 +205,10 @@ gld${EMULATION_NAME}_vercheck (s)
       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.  */
+            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;
        }
@@ -205,8 +220,7 @@ gld${EMULATION_NAME}_vercheck (s)
    the file.  */
 
 static void
-gld${EMULATION_NAME}_stat_needed (s)
-     lang_input_statement_type *s;
+gld${EMULATION_NAME}_stat_needed (lang_input_statement_type *s)
 {
   struct stat st;
   const char *suffix;
@@ -216,6 +230,9 @@ gld${EMULATION_NAME}_stat_needed (s)
     return;
   if (s->the_bfd == NULL)
     return;
+  if (s->as_needed
+      && (bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0)
+    return;
 
   if (bfd_stat (s->the_bfd, &st) != 0)
     {
@@ -223,8 +240,16 @@ gld${EMULATION_NAME}_stat_needed (s)
       return;
     }
 
+  /* Some operating systems, e.g. Windows, do not provide a meaningful
+     st_ino; they always set it to zero.  (Windows does provide a
+     meaningful st_dev.)  Do not indicate a duplicate library in that
+     case.  While there is no guarantee that a system that provides
+     meaningful inode numbers will never set st_ino to zero, this is
+     merely an optimization, so we do not need to worry about false
+     negatives.  */
   if (st.st_dev == global_stat.st_dev
-      && st.st_ino == global_stat.st_ino)
+      && st.st_ino == global_stat.st_ino
+      && st.st_ino != 0)
     {
       global_found = TRUE;
       return;
@@ -255,18 +280,24 @@ gld${EMULATION_NAME}_stat_needed (s)
           global_needed->name, global_needed->by, soname);
 }
 
+struct dt_needed
+{
+  bfd *by;
+  const char *name;
+};
 
 /* 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 bfd_boolean
-gld${EMULATION_NAME}_try_needed (name, force)
-     const char *name;
-     int force;
+gld${EMULATION_NAME}_try_needed (struct dt_needed *needed,
+                                int force)
 {
   bfd *abfd;
+  const char *name = needed->name;
   const char *soname;
+  int class;
 
   abfd = bfd_openr (name, bfd_get_target (output_bfd));
   if (abfd == NULL)
@@ -310,20 +341,20 @@ gld${EMULATION_NAME}_try_needed (name, force)
            {
              bfd_close (abfd);
              /* Return FALSE to force the caller to move on to try
-                 another file on the search path.  */
+                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.  */
+            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*)
+  *-*-linux-*)
     cat >>e${EMULATION_NAME}.c <<EOF
          {
            struct bfd_link_needed_list *l;
@@ -369,18 +400,26 @@ cat >>e${EMULATION_NAME}.c <<EOF
   if (global_found)
     {
       /* Return TRUE to indicate that we found the file, even though
-         we aren't going to do anything with it.  */
+        we aren't going to do anything with it.  */
       return TRUE;
     }
 
-  /* 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, "");
+  /* Specify the soname to use.  */
+  bfd_elf_set_dt_needed_name (abfd, soname);
 
-  /* 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, soname);
+  /* Tell the ELF linker that we don't want the output file to have a
+     DT_NEEDED entry for this file, unless it is used to resolve
+     references in a regular object.  */
+  class = DYN_DT_NEEDED;
+
+  /* Tell the ELF linker that we don't want the output file to have a
+     DT_NEEDED entry for this file at all if the entry is from a file
+     with DYN_NO_ADD_NEEDED.  */
+  if (needed->by != NULL
+      && (bfd_elf_get_dyn_lib_class (needed->by) & DYN_NO_ADD_NEEDED) != 0)
+    class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED;
+
+  bfd_elf_set_dyn_lib_class (abfd, class);
 
   /* Add this file into the symbol table.  */
   if (! bfd_link_add_symbols (abfd, &link_info))
@@ -393,19 +432,23 @@ cat >>e${EMULATION_NAME}.c <<EOF
 /* Search for a needed file in a path.  */
 
 static bfd_boolean
-gld${EMULATION_NAME}_search_needed (path, name, force)
-     const char *path;
-     const char *name;
-     int force;
+gld${EMULATION_NAME}_search_needed (const char *path,
+                                   struct dt_needed *n, int force)
 {
   const char *s;
+  const char *name = n->name;
   size_t len;
+  struct dt_needed needed;
 
   if (name[0] == '/')
-    return gld${EMULATION_NAME}_try_needed (name, force);
+    return gld${EMULATION_NAME}_try_needed (n, force);
 
   if (path == NULL || *path == '\0')
     return FALSE;
+
+  needed.by = n->by;
+  needed.name = n->name;
+
   len = strlen (name);
   while (1)
     {
@@ -426,7 +469,8 @@ gld${EMULATION_NAME}_search_needed (path, name, force)
        }
       strcpy (sset, name);
 
-      if (gld${EMULATION_NAME}_try_needed (filename, force))
+      needed.name = filename;
+      if (gld${EMULATION_NAME}_try_needed (&needed, force))
        return TRUE;
 
       free (filename);
@@ -445,11 +489,8 @@ if [ "x${USE_LIBPATH}" = xyes ] ; then
 
 /* Add the sysroot to every entry in a colon-separated path.  */
 
-static char * gld${EMULATION_NAME}_add_sysroot PARAMS ((const char *));
-
 static char *
-gld${EMULATION_NAME}_add_sysroot (path)
-     const char *path;
+gld${EMULATION_NAME}_add_sysroot (const char *path)
 {
   int len, colons, i;
   char *ret, *p;
@@ -472,7 +513,7 @@ gld${EMULATION_NAME}_add_sysroot (path)
   while (path[i])
     if (path[i] == ':')
       {
-        *p++ = path[i++];
+       *p++ = path[i++];
        strcpy (p, ld_sysroot);
        p = p + strlen (p);
       }
@@ -485,97 +526,203 @@ gld${EMULATION_NAME}_add_sysroot (path)
 
 EOF
   case ${target} in
-    *-*-linux-gnu*)
+    *-*-linux-*)
       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 bfd_boolean gld${EMULATION_NAME}_check_ld_so_conf
-  PARAMS ((const char *, int));
+struct gld${EMULATION_NAME}_ld_so_conf
+{
+  char *path;
+  size_t len, alloc;
+};
 
-static bfd_boolean
-gld${EMULATION_NAME}_check_ld_so_conf (name, force)
-     const char *name;
-     int force;
+static void
+gld${EMULATION_NAME}_parse_ld_so_conf
+     (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename);
+
+static void
+gld${EMULATION_NAME}_parse_ld_so_conf_include
+     (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename,
+      const char *pattern)
 {
-  static bfd_boolean initialized;
-  static char *ld_so_conf;
+  char *newp = NULL;
+#ifdef HAVE_GLOB
+  glob_t gl;
+#endif
 
-  if (! initialized)
+  if (pattern[0] != '/')
     {
-      FILE *f;
-      char *tmppath;
+      char *p = strrchr (filename, '/');
+      size_t patlen = strlen (pattern) + 1;
 
-      tmppath = concat (ld_sysroot, "/etc/ld.so.conf", NULL);
-      f = fopen (tmppath, FOPEN_RT);
-      free (tmppath);
-      if (f != NULL)
+      newp = xmalloc (p - filename + 1 + patlen);
+      memcpy (newp, filename, p - filename + 1);
+      memcpy (newp + (p - filename + 1), pattern, patlen);
+      pattern = newp;
+    }
+
+#ifdef HAVE_GLOB
+  if (glob (pattern, 0, NULL, &gl) == 0)
+    {
+      size_t i;
+
+      for (i = 0; i < gl.gl_pathc; ++i)
+       gld${EMULATION_NAME}_parse_ld_so_conf (info, gl.gl_pathv[i]);
+      globfree (&gl);
+    }
+#else
+  /* If we do not have glob, treat the pattern as a literal filename.  */
+  gld${EMULATION_NAME}_parse_ld_so_conf (info, pattern);
+#endif
+
+  if (newp)
+    free (newp);
+}
+
+static void
+gld${EMULATION_NAME}_parse_ld_so_conf
+     (struct gld${EMULATION_NAME}_ld_so_conf *info, const char *filename)
+{
+  FILE *f = fopen (filename, FOPEN_RT);
+  char *line;
+  size_t linelen;
+
+  if (f == NULL)
+    return;
+
+  linelen = 256;
+  line = xmalloc (linelen);
+  do
+    {
+      char *p = line, *q;
+
+      /* Normally this would use getline(3), but we need to be portable.  */
+      while ((q = fgets (p, linelen - (p - line), f)) != NULL
+            && strlen (q) == linelen - (p - line) - 1
+            && line[linelen - 2] != '\n')
        {
-         char *b;
-         size_t len, alloc;
-         int c;
+         line = xrealloc (line, 2 * linelen);
+         p = line + linelen - 1;
+         linelen += linelen;
+       }
+
+      if (q == NULL && p == line)
+       break;
 
-         len = 0;
-         alloc = 100;
-         b = (char *) xmalloc (alloc);
+      p = strchr (line, '\n');
+      if (p)
+       *p = '\0';
 
-         while ((c = getc (f)) != EOF)
+      /* Because the file format does not know any form of quoting we
+        can search forward for the next '#' character and if found
+        make it terminating the line.  */
+      p = strchr (line, '#');
+      if (p)
+       *p = '\0';
+
+      /* Remove leading whitespace.  NUL is no whitespace character.  */
+      p = line;
+      while (*p == ' ' || *p == '\f' || *p == '\r' || *p == '\t' || *p == '\v')
+       ++p;
+
+      /* If the line is blank it is ignored.  */
+      if (p[0] == '\0')
+       continue;
+
+      if (!strncmp (p, "include", 7) && (p[7] == ' ' || p[7] == '\t'))
+       {
+         char *dir, c;
+         p += 8;
+         do
            {
-             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;
-                   }
-               }
-           }
+             while (*p == ' ' || *p == '\t')
+               ++p;
+
+             if (*p == '\0')
+               break;
+
+             dir = p;
 
-         if (len > 0 && b[len - 1] == ':')
-           --len;
+             while (*p != ' ' && *p != '\t' && *p)
+               ++p;
 
-         if (len > 0)
-           b[len] = '\0';
+             c = *p;
+             *p++ = '\0';
+             if (dir[0] != '\0')
+               gld${EMULATION_NAME}_parse_ld_so_conf_include (info, filename,
+                                                              dir);
+           }
+         while (c != '\0');
+       }
+      else
+       {
+         char *dir = p;
+         while (*p && *p != '=' && *p != ' ' && *p != '\t' && *p != '\f'
+                && *p != '\r' && *p != '\v')
+           ++p;
+
+         while (p != dir && p[-1] == '/')
+           --p;
+         if (info->path == NULL)
+           {
+             info->alloc = p - dir + 1 + 256;
+             info->path = xmalloc (info->alloc);
+             info->len = 0;
+           }
          else
            {
-             free (b);
-             b = NULL;
+             if (info->len + 1 + (p - dir) >= info->alloc)
+               {
+                 info->alloc += p - dir + 256;
+                 info->path = xrealloc (info->path, info->alloc);
+               }
+             info->path[info->len++] = ':';
            }
+         memcpy (info->path + info->len, dir, p - dir);
+         info->len += p - dir;
+         info->path[info->len] = '\0';
+       }
+    }
+  while (! feof (f));
+  free (line);
+  fclose (f);
+}
 
-         fclose (f);
+static bfd_boolean
+gld${EMULATION_NAME}_check_ld_so_conf (const char *name, int force)
+{
+  static bfd_boolean initialized;
+  static char *ld_so_conf;
+  struct dt_needed needed;
 
-         if (b)
-           {
-             char *d = gld${EMULATION_NAME}_add_sysroot (b);
-             free (b);
-             b = d;
-           }
+  if (! initialized)
+    {
+      char *tmppath;
+      struct gld${EMULATION_NAME}_ld_so_conf info;
 
-         ld_so_conf = b;
+      tmppath = concat (ld_sysroot, "/etc/ld.so.conf", NULL);
+      info.path = NULL;
+      info.len = info.alloc = 0;
+      gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath);
+      free (tmppath);
+      if (info.path)
+       {
+         char *d = gld${EMULATION_NAME}_add_sysroot (info.path);
+         free (info.path);
+         ld_so_conf = d;
        }
-
       initialized = TRUE;
     }
 
   if (ld_so_conf == NULL)
     return FALSE;
 
-  return gld${EMULATION_NAME}_search_needed (ld_so_conf, name, force);
+
+  needed.by = NULL;
+  needed.name = name;
+  return gld${EMULATION_NAME}_search_needed (ld_so_conf, &needed, force);
 }
 
 EOF
@@ -588,12 +735,18 @@ 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;
+gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s)
 {
   if (global_found)
     return;
 
+  /* If this input file was an as-needed entry, and wasn't found to be
+     needed at the stage it was linked, then don't say we have loaded it.  */
+  if (s->as_needed
+      && (s->the_bfd == NULL
+         || (bfd_elf_get_dyn_lib_class (s->the_bfd) & DYN_AS_NEEDED) != 0))
+    return;
+
   if (s->filename != NULL)
     {
       const char *f;
@@ -638,12 +791,12 @@ cat >>e${EMULATION_NAME}.c <<EOF
 /* This is called after all the input files have been opened.  */
 
 static void
-gld${EMULATION_NAME}_after_open ()
+gld${EMULATION_NAME}_after_open (void)
 {
   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)
+  if (link_info.relocatable || !link_info.executable)
     return;
 
   /* Get the list of files which appear in DT_NEEDED entries in
@@ -659,11 +812,20 @@ gld${EMULATION_NAME}_after_open ()
   for (l = needed; l != NULL; l = l->next)
     {
       struct bfd_link_needed_list *ll;
+      struct dt_needed n, nn;
       int force;
 
+      /* If the lib that needs this one was --as-needed and wasn't
+        found to be needed, then this lib isn't needed either.  */
+      if (l->by != NULL
+         && (bfd_elf_get_dyn_lib_class (l->by) & DYN_AS_NEEDED) != 0)
+       continue;
+
       /* If we've already seen this file, skip it.  */
       for (ll = needed; ll != l; ll = ll->next)
-       if (strcmp (ll->name, l->name) == 0)
+       if ((ll->by == NULL
+            || (bfd_elf_get_dyn_lib_class (ll->by) & DYN_AS_NEEDED) == 0)
+           && strcmp (ll->name, l->name) == 0)
          break;
       if (ll != l)
        continue;
@@ -675,6 +837,9 @@ gld${EMULATION_NAME}_after_open ()
       if (global_found)
        continue;
 
+      n.by = l->by;
+      n.name = l->name;
+      nn.by = l->by;
       if (trace_file_tries)
        info_msg (_("%s needed by %B\n"), l->name, l->by);
 
@@ -694,9 +859,13 @@ gld${EMULATION_NAME}_after_open ()
          size_t len;
          search_dirs_type *search;
 EOF
-if [ "x${USE_LIBPATH}" = xyes ] ; then
+if [ "x${NATIVE}" = xyes ] ; then
 cat >>e${EMULATION_NAME}.c <<EOF
          const char *lib_path;
+EOF
+fi
+if [ "x${USE_LIBPATH}" = xyes ] ; then
+cat >>e${EMULATION_NAME}.c <<EOF
          struct bfd_link_needed_list *rp;
          int found;
 EOF
@@ -704,13 +873,13 @@ fi
 cat >>e${EMULATION_NAME}.c <<EOF
 
          if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
-                                                 l->name, force))
+                                                 &n, force))
            break;
 EOF
 if [ "x${USE_LIBPATH}" = xyes ] ; then
 cat >>e${EMULATION_NAME}.c <<EOF
          if (gld${EMULATION_NAME}_search_needed (command_line.rpath,
-                                                 l->name, force))
+                                                 &n, force))
            break;
 EOF
 fi
@@ -720,12 +889,12 @@ cat >>e${EMULATION_NAME}.c <<EOF
              && command_line.rpath == NULL)
            {
              lib_path = (const char *) getenv ("LD_RUN_PATH");
-             if (gld${EMULATION_NAME}_search_needed (lib_path, l->name,
+             if (gld${EMULATION_NAME}_search_needed (lib_path, &n,
                                                      force))
                break;
            }
          lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
-         if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force))
+         if (gld${EMULATION_NAME}_search_needed (lib_path, &n, force))
            break;
 EOF
 fi
@@ -738,7 +907,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
              char *tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name);
              found = (rp->by == l->by
                       && gld${EMULATION_NAME}_search_needed (tmpname,
-                                                             l->name,
+                                                             &n,
                                                              force));
              free (tmpname);
            }
@@ -757,7 +926,8 @@ cat >>e${EMULATION_NAME}.c <<EOF
                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))
+             nn.name = filename;
+             if (gld${EMULATION_NAME}_try_needed (&nn, force))
                break;
              free (filename);
            }
@@ -766,7 +936,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
 EOF
 if [ "x${USE_LIBPATH}" = xyes ] ; then
   case ${target} in
-    *-*-linux-gnu*)
+    *-*-linux-*)
       cat >>e${EMULATION_NAME}.c <<EOF
          if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force))
            break;
@@ -794,19 +964,16 @@ 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;
+gld${EMULATION_NAME}_find_exp_assignment (etree_type *exp)
 {
-  struct bfd_link_hash_entry *h;
+  bfd_boolean provide = FALSE;
 
   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;
-
+      provide = TRUE;
+      /* Fall thru */
+    case etree_assign:
       /* 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,
@@ -814,14 +981,10 @@ gld${EMULATION_NAME}_find_exp_assignment (exp)
         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)
        {
-         if (! (bfd_elf${ELFSIZE}_record_link_assignment
-                (output_bfd, &link_info, exp->assign.dst,
-                 exp->type.node_class == etree_provide ? TRUE : FALSE)))
+         if (!bfd_elf_record_link_assignment (output_bfd, &link_info,
+                                              exp->assign.dst, provide))
            einfo ("%P%F: failed to record assignment to %s: %E\n",
                   exp->assign.dst);
        }
@@ -855,8 +1018,7 @@ gld${EMULATION_NAME}_find_exp_assignment (exp)
    symbols which are referred to by dynamic objects.  */
 
 static void
-gld${EMULATION_NAME}_find_statement_assignment (s)
-     lang_statement_union_type *s;
+gld${EMULATION_NAME}_find_statement_assignment (lang_statement_union_type *s)
 {
   if (s->header.type == lang_assignment_statement_enum)
     gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
@@ -869,8 +1031,8 @@ if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation;
     ELF_INTERPRETER_SET_DEFAULT="
   if (sinterp != NULL)
     {
-      sinterp->contents = ${ELF_INTERPRETER_NAME};
-      sinterp->_raw_size = strlen (sinterp->contents) + 1;
+      sinterp->contents = (unsigned char *) ${ELF_INTERPRETER_NAME};
+      sinterp->size = strlen ((char *) sinterp->contents) + 1;
     }
 
 "
@@ -883,11 +1045,14 @@ cat >>e${EMULATION_NAME}.c <<EOF
    sections, but before any sizes or addresses have been set.  */
 
 static void
-gld${EMULATION_NAME}_before_allocation ()
+gld${EMULATION_NAME}_before_allocation (void)
 {
   const char *rpath;
   asection *sinterp;
 
+  if (link_info.hash->type == bfd_link_elf_hash_table)
+    _bfd_elf_tls_setup (output_bfd, &link_info);
+
   /* If we are going to make any variable assignments, we need to let
      the ELF backend know about them in case the variables are
      referred to by dynamic objects.  */
@@ -898,19 +1063,20 @@ gld${EMULATION_NAME}_before_allocation ()
   rpath = command_line.rpath;
   if (rpath == NULL)
     rpath = (const char *) getenv ("LD_RUN_PATH");
-  if (! (bfd_elf${ELFSIZE}_size_dynamic_sections
-         (output_bfd, command_line.soname, rpath,
+  if (! (bfd_elf_size_dynamic_sections
+        (output_bfd, command_line.soname, rpath,
          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->contents = (bfd_byte *) command_line.interpreter;
-      sinterp->_raw_size = strlen (command_line.interpreter) + 1;
+      sinterp->size = strlen (command_line.interpreter) + 1;
     }
 
   /* Look for any sections named .gnu.warning.  As a GNU extensions,
@@ -923,8 +1089,10 @@ ${ELF_INTERPRETER_SET_DEFAULT}
       {
        asection *s;
        bfd_size_type sz;
+       bfd_size_type prefix_len;
        char *msg;
        bfd_boolean ret;
+       const char * gnu_warning_prefix = _("warning: ");
 
        if (is->just_syms_flag)
          continue;
@@ -933,12 +1101,15 @@ ${ELF_INTERPRETER_SET_DEFAULT}
        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))
+       sz = s->size;
+       prefix_len = strlen (gnu_warning_prefix);
+       msg = xmalloc ((size_t) (prefix_len + sz + 1));
+       strcpy (msg, gnu_warning_prefix);
+       if (! bfd_get_section_contents (is->the_bfd, s, msg + prefix_len,
+                                       (file_ptr) 0, sz))
          einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n",
                 is->the_bfd);
-       msg[sz] = '\0';
+       msg[prefix_len + sz] = '\0';
        ret = link_info.callbacks->warning (&link_info, msg,
                                            (const char *) NULL,
                                            is->the_bfd, (asection *) NULL,
@@ -948,9 +1119,19 @@ ${ELF_INTERPRETER_SET_DEFAULT}
 
        /* Clobber the section size, so that we don't waste copying the
           warning into the output file.  */
-       s->_raw_size = 0;
+       s->size = 0;
+
+       /* Also set SEC_EXCLUDE, so that symbols defined in the warning
+          section don't get copied to the output.  */
+       s->flags |= SEC_EXCLUDE;
       }
   }
+
+  if (!link_info.relocatable)
+    strip_excluded_output_sections ();
+
+  if (!bfd_elf_size_dynsym_hash_dynstr (output_bfd, &link_info))
+    einfo ("%P%F: failed to set dynamic section sizes: %E\n");
 }
 
 EOF
@@ -964,10 +1145,8 @@ cat >>e${EMULATION_NAME}.c <<EOF
    like hpux).  */
 
 static bfd_boolean
-gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry)
-     const char *arch;
-     search_dirs_type *search;
-     lang_input_statement_type *entry;
+gld${EMULATION_NAME}_open_dynamic_archive
+  (const char *arch, search_dirs_type *search, lang_input_statement_type *entry)
 {
   const char *filename;
   char *string;
@@ -1040,40 +1219,49 @@ fi
 if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
 cat >>e${EMULATION_NAME}.c <<EOF
 
-/* A variant of lang_output_section_find.  Used by place_orphan.  */
+/* A variant of lang_output_section_find used by place_orphan.  */
 
 static lang_output_section_statement_type *
-output_rel_find (sec)
-     asection *sec;
+output_rel_find (asection *sec, int isdyn)
 {
-  lang_statement_union_type *u;
   lang_output_section_statement_type *lookup;
   lang_output_section_statement_type *last = NULL;
+  lang_output_section_statement_type *last_alloc = NULL;
   lang_output_section_statement_type *last_rel = NULL;
   lang_output_section_statement_type *last_rel_alloc = NULL;
   int rela = sec->name[4] == 'a';
 
-  for (u = lang_output_section_statement.head; u; u = lookup->next)
+  for (lookup = &lang_output_section_statement.head->output_section_statement;
+       lookup != NULL;
+       lookup = lookup->next)
     {
-      lookup = &u->output_section_statement;
-      if (strncmp (".rel", lookup->name, 4) == 0)
+      if (lookup->constraint != -1
+         && strncmp (".rel", lookup->name, 4) == 0)
        {
-         /* Don't place after .rel.plt as doing so results in wrong
-            dynamic tags.  Also, place allocated reloc sections before
-            non-allocated.  */
          int lookrela = lookup->name[4] == 'a';
 
-         if (strcmp (".plt", lookup->name + 4 + lookrela) == 0
-             || (lookup->bfd_section != NULL
-                 && (lookup->bfd_section->flags & SEC_ALLOC) == 0))
+         /* .rel.dyn must come before all other reloc sections, to suit
+            GNU ld.so.  */
+         if (isdyn)
            break;
-         last = lookup;
-         if (rela == lookrela)
+
+         /* Don't place after .rel.plt as doing so results in wrong
+            dynamic tags.  */
+         if (strcmp (".plt", lookup->name + 4 + lookrela) == 0)
+           break;
+
+         if (rela == lookrela || last_rel == NULL)
            last_rel = lookup;
-         if (lookup->bfd_section != NULL
+         if ((rela == lookrela || last_rel_alloc == NULL)
+             && lookup->bfd_section != NULL
              && (lookup->bfd_section->flags & SEC_ALLOC) != 0)
            last_rel_alloc = lookup;
        }
+
+      last = lookup;
+      if (lookup->bfd_section != NULL
+         && (lookup->bfd_section->flags & SEC_ALLOC) != 0)
+       last_alloc = lookup;
     }
 
   if (last_rel_alloc)
@@ -1082,71 +1270,62 @@ output_rel_find (sec)
   if (last_rel)
     return last_rel;
 
-  return last;
-}
-
-/* Find the last output section before given output statement.
-   Used by place_orphan.  */
-
-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;
-
-  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;
+  if (last_alloc)
+    return last_alloc;
 
-      if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
-       s = lookup->bfd_section;
-    }
-
-  return NULL;
+  return last;
 }
 
 /* Place an orphan section.  We use this to put random SHF_ALLOC
    sections in the right segment.  */
 
-struct orphan_save {
-  lang_output_section_statement_type *os;
-  asection **section;
-  lang_statement_union_type **stmt;
-  lang_statement_union_type **os_tail;
-};
-
 static bfd_boolean
-gld${EMULATION_NAME}_place_orphan (file, s)
-     lang_input_statement_type *file;
-     asection *s;
+gld${EMULATION_NAME}_place_orphan (lang_input_statement_type *file, asection *s)
 {
-  static struct orphan_save hold_text;
-  static struct orphan_save hold_rodata;
-  static struct orphan_save hold_data;
-  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;
+  static struct orphan_save hold[] =
+    {
+      { ".text",
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE,
+       0, 0, 0, 0 },
+      { ".rodata",
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
+       0, 0, 0, 0 },
+      { ".data",
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA,
+       0, 0, 0, 0 },
+      { ".bss",
+       SEC_ALLOC,
+       0, 0, 0, 0 },
+      { 0,
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
+       0, 0, 0, 0 },
+      { ".interp",
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA,
+       0, 0, 0, 0 },
+      { ".sdata",
+       SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA,
+       0, 0, 0, 0 }
+    };
+  enum orphan_save_index
+    {
+      orphan_text = 0,
+      orphan_rodata,
+      orphan_data,
+      orphan_bss,
+      orphan_rel,
+      orphan_interp,
+      orphan_sdata
+    };
+  static int orphan_init_done = 0;
   struct orphan_save *place;
-  lang_statement_list_type *old;
-  lang_statement_list_type add;
-  etree_type *address;
   const char *secname;
-  const char *ps = NULL;
+  lang_output_section_statement_type *after;
   lang_output_section_statement_type *os;
-  lang_statement_union_type **os_tail;
-  etree_type *load_base;
   int isdyn = 0;
 
   secname = bfd_get_section_name (s->owner, s);
-  if (! link_info.relocateable
+
+  if (! link_info.relocatable
       && link_info.combreloc
       && (s->flags & SEC_ALLOC)
       && strncmp (secname, ".rel", 4) == 0)
@@ -1158,34 +1337,49 @@ gld${EMULATION_NAME}_place_orphan (file, s)
       isdyn = 1;
     }
 
-  if (isdyn || (!config.unique_orphan_sections && !unique_section_p (secname)))
+  if (isdyn || (!config.unique_orphan_sections && !unique_section_p (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
+             || os->bfd_section->flags == 0
              || ((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.  */
+            name, and its bfd section, if any, has compatible flags.
+            If the section already exists but does not have any flags
+            set, then it has been created by the linker, probably as a
+            result of a --section-start command line switch.  */
          lang_add_section (&os->children, s, os, file);
          return TRUE;
        }
     }
 
-  if (hold_text.os == NULL)
-    hold_text.os = lang_output_section_find (".text");
+  if (!orphan_init_done)
+    {
+      struct orphan_save *ho;
+      for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho)
+       if (ho->name != NULL)
+         {
+           ho->os = lang_output_section_find (ho->name);
+           if (ho->os != NULL && ho->os->flags == 0)
+             ho->os->flags = ho->flags;
+         }
+      orphan_init_done = 1;
+    }
 
   /* If this is a final link, then always put .gnu.warning.SYMBOL
      sections into the .text section to get them out of the way.  */
-  if (! link_info.shared
-      && ! link_info.relocateable
+  if (link_info.executable
+      && ! link_info.relocatable
       && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
-      && hold_text.os != NULL)
+      && hold[orphan_text].os != NULL)
     {
-      lang_add_section (&hold_text.os->children, s, hold_text.os, file);
+      lang_add_section (&hold[orphan_text].os->children, s,
+                       hold[orphan_text].os, file);
       return TRUE;
     }
 
@@ -1194,251 +1388,187 @@ gld${EMULATION_NAME}_place_orphan (file, s)
      right after the .interp section, so that the PT_NOTE segment is
      stored right after the program headers where the OS can read it
      in the first page.  */
-#define HAVE_SECTION(hold, name) \
-(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
-
-  if ((s->flags & SEC_EXCLUDE) != 0 && !link_info.relocateable)
-    {
-      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", 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;
+          && strncmp (secname, ".note", 5) == 0)
+    place = &hold[orphan_interp];
+  else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+    place = &hold[orphan_bss];
+  else if ((s->flags & SEC_SMALL_DATA) != 0)
+    place = &hold[orphan_sdata];
+  else if ((s->flags & SEC_READONLY) == 0)
+    place = &hold[orphan_data];
   else if (strncmp (secname, ".rel", 4) == 0
-          && (s->flags & SEC_LOAD) != 0
-          && (hold_rel.os != NULL
-              || (hold_rel.os = output_rel_find (s)) != NULL))
-    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_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY)
-          && hold_text.os != NULL)
-    place = &hold_text;
-
-#undef HAVE_SECTION
+          && (s->flags & SEC_LOAD) != 0)
+    place = &hold[orphan_rel];
+  else if ((s->flags & SEC_CODE) == 0)
+    place = &hold[orphan_rodata];
+  else
+    place = &hold[orphan_text];
+
+  after = NULL;
+  if (place != NULL)
+    {
+      if (place->os == NULL)
+       {
+         if (place->name != NULL)
+           place->os = lang_output_section_find (place->name);
+         else
+           place->os = output_rel_find (s, isdyn);
+       }
+      after = place->os;
+      if (after == NULL)
+       after = lang_output_section_find_by_flags (s, &place->os);
+      if (after == NULL)
+       /* *ABS* is always the first output section statement.  */
+       after = &lang_output_section_statement.head->output_section_statement;
+    }
 
   /* 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 allocatable characteristics.  */
   if (bfd_get_section_by_name (output_bfd, secname) != NULL)
     {
+      static int count = 1;
       secname = bfd_get_unique_section_name (output_bfd, secname, &count);
       if (secname == 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;
+  lang_insert_orphan (file, s, secname, after, place, NULL, NULL);
 
-  /* 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)
+  return TRUE;
+}
+EOF
+fi
+
+if test x"$LDEMUL_FINISH" != xgld"$EMULATION_NAME"_finish; then
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static void
+gld${EMULATION_NAME}_provide_bound_symbols (const char *sec,
+                                           const char *start,
+                                           const char *end)
+{
+  asection *s;
+  bfd_vma start_val, end_val;
+
+  s = bfd_get_section_by_name (output_bfd, sec);
+  if (s != NULL)
     {
-      stat_ptr = &add;
-      lang_list_init (stat_ptr);
+      start_val = s->vma;
+      end_val = start_val + s->size;
     }
-
-  if (config.build_constructors)
+  else
     {
-      /* 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 = secname; *ps != '\0'; ps++)
-       if (! ISALNUM (*ps) && *ps != '_')
-         break;
-      if (*ps == '\0')
+      /* We have to choose those values very carefully.  Some targets,
+        like alpha, may have relocation overflow with 0.  We use the
+        first SEC_ALLOC section which isn't SEC_READONLY or the last
+        SEC_ALLOC section.   */
+      start_val = 0;
+      for (s = output_bfd->sections; s != NULL; s = s->next)
        {
-         char *symname;
-         etree_type *e_align;
-
-         symname = (char *) xmalloc (ps - secname + sizeof "__start_");
-         sprintf (symname, "__start_%s", secname);
-         e_align = exp_unop (ALIGN_K,
-                             exp_intop ((bfd_vma) 1 << s->alignment_power));
-         lang_add_assignment (exp_assop ('=', symname, e_align));
+         if ((s->flags & SEC_ALLOC) != 0)
+           {
+             start_val = s->vma;
+             if ((s->flags & SEC_READONLY) == 0)
+               break;
+           }
        }
+      end_val = start_val;
     }
+  _bfd_elf_provide_symbol (&link_info, start, start_val);
+  _bfd_elf_provide_symbol (&link_info, end, end_val);
+}
 
-  address = NULL;
-  if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
-    address = exp_intop ((bfd_vma) 0);
-
-  load_base = NULL;
-  if (place != NULL && place->os->load_base != NULL)
-    {
-      etree_type *lma_from_vma;
-      lma_from_vma = exp_binop ('-', place->os->load_base,
-                               exp_nameop (ADDR, place->os->name));
-      load_base = exp_binop ('+', lma_from_vma,
-                            exp_nameop (ADDR, secname));
-    }
-
-  os_tail = lang_output_section_statement.tail;
-  os = lang_enter_output_section_statement (secname, address, 0,
-                                           (bfd_vma) 0,
-                                           (etree_type *) NULL,
-                                           (etree_type *) NULL,
-                                           load_base);
+/* If not building a shared library, provide
 
-  lang_add_section (&os->children, s, os, file);
+   __preinit_array_start
+   __preinit_array_end
+   __init_array_start
+   __init_array_end
+   __fini_array_start
+   __fini_array_end
 
-  lang_leave_output_section_statement
-    ((bfd_vma) 0, "*default*",
-     (struct lang_output_section_phdr_list *) NULL, NULL);
+   They are set here rather than via PROVIDE in the linker
+   script, because using PROVIDE inside an output section
+   statement results in unnecessary output sections.  Using
+   PROVIDE outside an output section statement runs the risk of
+   section alignment affecting where the section starts.  */
 
-  if (config.build_constructors && *ps == '\0')
+static void
+gld${EMULATION_NAME}_provide_init_fini_syms (void)
+{
+  if (!link_info.relocatable && !link_info.shared)
     {
-      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 - secname + sizeof "__stop_");
-      sprintf (symname, "__stop_%s", secname);
-      lang_add_assignment (exp_assop ('=', symname,
-                                     exp_nameop (NAME, ".")));
+      gld${EMULATION_NAME}_provide_bound_symbols (".preinit_array",
+                                                 "__preinit_array_start",
+                                                 "__preinit_array_end");
+      gld${EMULATION_NAME}_provide_bound_symbols (".init_array",
+                                                 "__init_array_start",
+                                                 "__init_array_end");
+      gld${EMULATION_NAME}_provide_bound_symbols (".fini_array",
+                                                 "__fini_array_start",
+                                                 "__fini_array_end");
     }
+}
 
-  /* Restore the global list pointer.  */
-  stat_ptr = old;
-
-  if (place != NULL && os->bfd_section != NULL)
-    {
-      asection *snew, **pps;
-
-      snew = os->bfd_section;
-
-      /* Shuffle the bfd section list to make the output file look
-        neater.  This is really only cosmetic.  */
-      if (place->section == NULL)
-       {
-         asection *bfd_section = place->os->bfd_section;
+static void
+gld${EMULATION_NAME}_layout_sections_again (void)
+{
+  lang_reset_memory_regions ();
 
-         /* 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);
+  /* Resize the sections.  */
+  lang_size_sections (stat_ptr->head, abs_output_section,
+                     &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE);
 
-         if (bfd_section != NULL && bfd_section != snew)
-           place->section = &bfd_section->next;
-       }
+  /* Redo special stuff.  */
+  ldemul_after_allocation ();
 
-      if (place->section != NULL)
-       {
-         /* Unlink the section.  */
-         for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
-           ;
-         bfd_section_list_remove (output_bfd, pps);
+  /* Do the assignments again.  */
+  lang_do_assignments (stat_ptr->head, abs_output_section,
+                      (fill_type *) 0, (bfd_vma) 0);
+}
 
-         /* Now tack it on to the "place->os" section list.  */
-         bfd_section_list_insert (output_bfd, place->section, snew);
-       }
+static void
+gld${EMULATION_NAME}_strip_empty_sections (void)
+{
+  if (!link_info.relocatable)
+    {
+      lang_output_section_statement_type *os;
 
-      /* 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)
+      for (os = &lang_output_section_statement.head->output_section_statement;
+          os != NULL;
+          os = os->next)
        {
-         lang_statement_union_type *newly_added_os;
-
-         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;
-
-             place->os_tail = &place->os->next;
-           }
-         else
+         asection *s;
+
+         if (os == abs_output_section || os->constraint == -1)
+           continue;
+         s = os->bfd_section;
+         if (s != NULL
+             && s->size == 0
+             && (s->flags & SEC_KEEP) == 0
+             && !bfd_section_removed_from_list (output_bfd, s))
            {
-             /* Put it after the last orphan statement we added.  */
-             *add.tail = *place->stmt;
-             *place->stmt = add.head;
+             bfd_section_list_remove (output_bfd, s);
+             output_bfd->section_count--;
            }
-
-         /* 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;
-
-         /* Do the same for the list of output section statements.  */
-         newly_added_os = *os_tail;
-         *os_tail = NULL;
-         newly_added_os->output_section_statement.next = *place->os_tail;
-         *place->os_tail = newly_added_os;
-         place->os_tail = &newly_added_os->output_section_statement.next;
-
-         /* Fixing the global list pointer here is a little different.
-            We added to the list in lang_enter_output_section_statement,
-            trimmed off the new output_section_statment above when
-            assigning *os_tail = NULL, but possibly added it back in
-            the same place when assigning *place->os_tail.  */
-         if (*os_tail == NULL)
-           lang_output_section_statement.tail = os_tail;
        }
     }
-
-  return TRUE;
 }
-EOF
-fi
-
-if test x"$LDEMUL_FINISH" != xgld"$EMULATION_NAME"_finish; then
-cat >>e${EMULATION_NAME}.c <<EOF
 
 static void
-gld${EMULATION_NAME}_finish ()
+gld${EMULATION_NAME}_finish (void)
 {
-  if (bfd_elf${ELFSIZE}_discard_info (output_bfd, &link_info))
-    {
-      lang_reset_memory_regions ();
-
-      /* Resize the sections.  */
-      lang_size_sections (stat_ptr->head, abs_output_section,
-                         &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE);
+  if (bfd_elf_discard_info (output_bfd, &link_info))
+    gld${EMULATION_NAME}_layout_sections_again ();
 
-      /* Redo special stuff.  */
-      ldemul_after_allocation ();
-
-      /* Do the assignments again.  */
-      lang_do_assignments (stat_ptr->head, abs_output_section,
-                          (fill_type *) 0, (bfd_vma) 0);
-    }
+  gld${EMULATION_NAME}_strip_empty_sections ();
+  gld${EMULATION_NAME}_provide_init_fini_syms ();
 }
 EOF
 fi
@@ -1447,8 +1577,7 @@ 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)
-     int *isfile;
+gld${EMULATION_NAME}_get_script (int *isfile)
 EOF
 
 if test -n "$COMPILE_IN"
@@ -1462,33 +1591,52 @@ cat >>e${EMULATION_NAME}.c <<EOF
 {
   *isfile = 0;
 
-  if (link_info.relocateable && config.build_constructors)
+  if (link_info.relocatable && config.build_constructors)
     return
 EOF
-sed $sc ldscripts/${EMULATION_NAME}.xu                 >> e${EMULATION_NAME}.c
-echo '  ; else if (link_info.relocateable) return'     >> e${EMULATION_NAME}.c
-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
+sed $sc ldscripts/${EMULATION_NAME}.xu                 >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.relocatable) return'      >> e${EMULATION_NAME}.c
+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 : ; else
-echo '  ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xn                 >> e${EMULATION_NAME}.c
+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_PIE_SCRIPT" ; then
+if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
+echo '  ; else if (link_info.pie && link_info.combreloc' >> e${EMULATION_NAME}.c
+echo '             && link_info.relro' >> e${EMULATION_NAME}.c
+echo '             && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xdw                        >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.pie && link_info.combreloc) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xdc                        >> e${EMULATION_NAME}.c
+fi
+echo '  ; else if (link_info.pie) return'              >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xd                 >> e${EMULATION_NAME}.c
 fi
 if test -n "$GENERATE_SHLIB_SCRIPT" ; then
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
+echo '  ; else if (link_info.shared && link_info.combreloc' >> e${EMULATION_NAME}.c
+echo '             && link_info.relro' >> e${EMULATION_NAME}.c
+echo '             && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xsw                        >> e${EMULATION_NAME}.c
 echo '  ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xsc                >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xsc                        >> e${EMULATION_NAME}.c
 fi
-echo '  ; else if (link_info.shared) return'          >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xs                 >> 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
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
-echo '  ; else if (link_info.combreloc) return'        >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xc                 >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c
+echo '             && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xw                 >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.combreloc) return'                >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xc                 >> e${EMULATION_NAME}.c
 fi
-echo '  ; else return'                                 >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.x                  >> e${EMULATION_NAME}.c
-echo '; }'                                             >> 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
 # Scripts read from the filesystem.
@@ -1497,16 +1645,60 @@ cat >>e${EMULATION_NAME}.c <<EOF
 {
   *isfile = 1;
 
-  if (link_info.relocateable && config.build_constructors)
+  if (link_info.relocatable && config.build_constructors)
     return "ldscripts/${EMULATION_NAME}.xu";
-  else if (link_info.relocateable)
+  else if (link_info.relocatable)
     return "ldscripts/${EMULATION_NAME}.xr";
   else if (!config.text_read_only)
     return "ldscripts/${EMULATION_NAME}.xbn";
+EOF
+if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then :
+else
+cat >>e${EMULATION_NAME}.c <<EOF
   else if (!config.magic_demand_paged)
     return "ldscripts/${EMULATION_NAME}.xn";
+EOF
+fi
+if test -n "$GENERATE_PIE_SCRIPT" ; then
+if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+  else if (link_info.pie && link_info.combreloc
+          && link_info.relro && (link_info.flags & DT_BIND_NOW))
+    return "ldscripts/${EMULATION_NAME}.xdw";
+  else if (link_info.pie && link_info.combreloc)
+    return "ldscripts/${EMULATION_NAME}.xdc";
+EOF
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
+  else if (link_info.pie)
+    return "ldscripts/${EMULATION_NAME}.xd";
+EOF
+fi
+if test -n "$GENERATE_SHLIB_SCRIPT" ; then
+if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+  else if (link_info.shared && link_info.combreloc
+          && link_info.relro && (link_info.flags & DT_BIND_NOW))
+    return "ldscripts/${EMULATION_NAME}.xsw";
+  else if (link_info.shared && link_info.combreloc)
+    return "ldscripts/${EMULATION_NAME}.xsc";
+EOF
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
   else if (link_info.shared)
     return "ldscripts/${EMULATION_NAME}.xs";
+EOF
+fi
+if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+  else if (link_info.combreloc && link_info.relro
+          && (link_info.flags & DT_BIND_NOW))
+    return "ldscripts/${EMULATION_NAME}.xw";
+  else if (link_info.combreloc)
+    return "ldscripts/${EMULATION_NAME}.xc";
+EOF
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
   else
     return "ldscripts/${EMULATION_NAME}.x";
 }
@@ -1529,18 +1721,12 @@ cat >>e${EMULATION_NAME}.c <<EOF
 #define OPTION_ENABLE_NEW_DTAGS                (OPTION_DISABLE_NEW_DTAGS + 1)
 #define OPTION_GROUP                   (OPTION_ENABLE_NEW_DTAGS + 1)
 #define OPTION_EH_FRAME_HDR            (OPTION_GROUP + 1)
-
-static void gld${EMULATION_NAME}_add_options
-  PARAMS ((int, char **, int, struct option **, int, struct option **));
-
+#define OPTION_EXCLUDE_LIBS            (OPTION_EH_FRAME_HDR + 1)
+  
 static void
-gld${EMULATION_NAME}_add_options (ns, shortopts, nl, longopts, nrl, really_longopts)
-     int ns;
-     char **shortopts;
-     int nl;
-     struct option **longopts;
-     int nrl ATTRIBUTE_UNUSED;
-     struct option **really_longopts ATTRIBUTE_UNUSED;
+gld${EMULATION_NAME}_add_options
+  (int ns, char **shortopts, int nl, struct option **longopts,
+   int nrl ATTRIBUTE_UNUSED, struct option **really_longopts ATTRIBUTE_UNUSED)
 {
   static const char xtra_short[] = "${PARSE_AND_LIST_SHORTOPTS}z:";
   static const struct option xtra_long[] = {
@@ -1551,6 +1737,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
     {"disable-new-dtags", no_argument, NULL, OPTION_DISABLE_NEW_DTAGS},
     {"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
     {"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR},
+    {"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS},
     {"Bgroup", no_argument, NULL, OPTION_GROUP},
 EOF
 fi
@@ -1572,12 +1759,8 @@ cat >>e${EMULATION_NAME}.c <<EOF
   memcpy (*longopts + nl, &xtra_long, sizeof (xtra_long));
 }
 
-static bfd_boolean gld${EMULATION_NAME}_handle_option
-  PARAMS ((int));
-
 static bfd_boolean
-gld${EMULATION_NAME}_handle_option (optc)
-     int optc;
+gld${EMULATION_NAME}_handle_option (int optc)
 {
   switch (optc)
     {
@@ -1603,7 +1786,12 @@ cat >>e${EMULATION_NAME}.c <<EOF
     case OPTION_GROUP:
       link_info.flags_1 |= (bfd_vma) DF_1_GROUP;
       /* Groups must be self-contained.  */
-      link_info.no_undefined = TRUE;
+      link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR;
+      link_info.unresolved_syms_in_shared_libs = RM_GENERATE_ERROR;
+      break;
+
+    case OPTION_EXCLUDE_LIBS:
+      add_excluded_libs (optarg);
       break;
 
     case 'z':
@@ -1632,7 +1820,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
          link_info.flags_1 |= (bfd_vma) DF_1_ORIGIN;
        }
       else if (strcmp (optarg, "defs") == 0)
-       link_info.no_undefined = TRUE;
+       link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR;
       else if (strcmp (optarg, "muldefs") == 0)
        link_info.allow_multiple_definition = TRUE;
       else if (strcmp (optarg, "combreloc") == 0)
@@ -1640,7 +1828,21 @@ cat >>e${EMULATION_NAME}.c <<EOF
       else if (strcmp (optarg, "nocombreloc") == 0)
        link_info.combreloc = FALSE;
       else if (strcmp (optarg, "nocopyreloc") == 0)
-        link_info.nocopyreloc = TRUE;
+       link_info.nocopyreloc = TRUE;
+      else if (strcmp (optarg, "execstack") == 0)
+       {
+         link_info.execstack = TRUE;
+         link_info.noexecstack = FALSE;
+       }
+      else if (strcmp (optarg, "noexecstack") == 0)
+       {
+         link_info.noexecstack = TRUE;
+         link_info.execstack = FALSE;
+       }
+      else if (strcmp (optarg, "relro") == 0)
+       link_info.relro = TRUE;
+      else if (strcmp (optarg, "norelro") == 0)
+       link_info.relro = FALSE;
       /* What about the other Solaris -z options? FIXME.  */
       break;
 EOF
@@ -1663,11 +1865,8 @@ EOF
 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)
-     FILE * file;
+gld${EMULATION_NAME}_list_options (FILE * file)
 {
 EOF
 
@@ -1678,7 +1877,8 @@ cat >>e${EMULATION_NAME}.c <<EOF
   fprintf (file, _("  --enable-new-dtags\tEnable new dynamic tags\n"));
   fprintf (file, _("  --eh-frame-hdr\tCreate .eh_frame_hdr section\n"));
   fprintf (file, _("  -z combreloc\t\tMerge dynamic relocs into one section and sort\n"));
-  fprintf (file, _("  -z defs\t\tDisallows undefined symbols\n"));
+  fprintf (file, _("  -z defs\t\tReport unresolved symbols in object files.\n"));
+  fprintf (file, _("  -z execstack\t\tMark executable as requiring executable stack\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"));
@@ -1689,8 +1889,11 @@ cat >>e${EMULATION_NAME}.c <<EOF
   fprintf (file, _("  -z nodelete\t\tMark DSO non-deletable at runtime\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 noexecstack\tMark executable as not requiring executable stack\n"));
+  fprintf (file, _("  -z norelro\t\tDon't create RELRO program header\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\t\t\t  at runtime\n"));
+  fprintf (file, _("  -z relro\t\tCreate RELRO program header\n"));
   fprintf (file, _("  -z KEYWORD\t\tIgnored for Solaris compatibility\n"));
 EOF
 fi
@@ -1749,7 +1952,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   gld${EMULATION_NAME}_handle_option,
   ${LDEMUL_UNRECOGNIZED_FILE-NULL},
   ${LDEMUL_LIST_OPTIONS-gld${EMULATION_NAME}_list_options},
-  ${LDEMUL_RECOGNIZED_FILE-NULL},
+  ${LDEMUL_RECOGNIZED_FILE-gld${EMULATION_NAME}_load_symbols},
   ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
   ${LDEMUL_NEW_VERS_PATTERN-NULL}
 };
This page took 0.044235 seconds and 4 git commands to generate.