aboutsummaryrefslogtreecommitdiff
path: root/ld/emultempl/sunos.em
diff options
context:
space:
mode:
Diffstat (limited to 'ld/emultempl/sunos.em')
-rw-r--r--ld/emultempl/sunos.em1037
1 files changed, 1037 insertions, 0 deletions
diff --git a/ld/emultempl/sunos.em b/ld/emultempl/sunos.em
new file mode 100644
index 0000000..8e9599c
--- /dev/null
+++ b/ld/emultempl/sunos.em
@@ -0,0 +1,1037 @@
+# This shell script emits a C file. -*- C -*-
+# It does some substitutions.
+cat >e${EMULATION_NAME}.c <<EOF
+/* This file is is generated by a shell script. DO NOT EDIT! */
+
+/* SunOS emulation code for ${EMULATION_NAME}
+ Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 1999
+ Free Software Foundation, Inc.
+ Written by Steve Chamberlain <sac@cygnus.com>
+ SunOS shared library support by Ian Lance Taylor <ian@cygnus.com>
+
+This file is part of GLD, the Gnu Linker.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#define TARGET_IS_${EMULATION_NAME}
+
+#include <ctype.h>
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libiberty.h"
+
+#include "ld.h"
+#include "ldmain.h"
+#include "ldemul.h"
+#include "ldfile.h"
+#include "ldmisc.h"
+#include "ldexp.h"
+#include "ldlang.h"
+
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#else
+# define dirent direct
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif
+
+static void gld${EMULATION_NAME}_before_parse PARAMS ((void));
+static void gld${EMULATION_NAME}_set_symbols PARAMS ((void));
+static void gld${EMULATION_NAME}_create_output_section_statements
+ PARAMS ((void));
+static void gld${EMULATION_NAME}_find_so
+ PARAMS ((lang_input_statement_type *));
+static char *gld${EMULATION_NAME}_search_dir
+ PARAMS ((const char *, const char *, boolean *));
+static void gld${EMULATION_NAME}_after_open PARAMS ((void));
+static void gld${EMULATION_NAME}_check_needed
+ PARAMS ((lang_input_statement_type *));
+static boolean gld${EMULATION_NAME}_search_needed
+ PARAMS ((const char *, const char *));
+static boolean gld${EMULATION_NAME}_try_needed
+ PARAMS ((const char *, const char *));
+static void gld${EMULATION_NAME}_before_allocation PARAMS ((void));
+static void gld${EMULATION_NAME}_find_assignment
+ PARAMS ((lang_statement_union_type *));
+static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *));
+static void gld${EMULATION_NAME}_count_need
+ PARAMS ((lang_input_statement_type *));
+static void gld${EMULATION_NAME}_set_need
+ PARAMS ((lang_input_statement_type *));
+static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile));
+
+static void
+gld${EMULATION_NAME}_before_parse()
+{
+ ldfile_output_architecture = bfd_arch_${ARCH};
+ config.dynamic_link = true;
+ config.has_shared = true;
+}
+
+/* This is called after the command line arguments have been parsed,
+ but before the linker script has been read. If this is a native
+ linker, we add the directories in LD_LIBRARY_PATH to the search
+ list. */
+
+static void
+gld${EMULATION_NAME}_set_symbols ()
+{
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+ if [ "x${DEFAULT_EMULATION}" = "x${EMULATION_NAME}" ] ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ const char *env;
+
+ env = (const char *) getenv ("LD_LIBRARY_PATH");
+ if (env != NULL)
+ {
+ char *l;
+
+ l = xstrdup (env);
+ while (1)
+ {
+ char *c;
+
+ c = strchr (l, ':');
+ if (c != NULL)
+ *c++ = '\0';
+ if (*l != '\0')
+ ldfile_add_library_path (l, false);
+ if (c == NULL)
+ break;
+ l = c;
+ }
+ }
+EOF
+ fi
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
+}
+
+/* Despite the name, we use this routine to search for dynamic
+ libraries. On SunOS this requires a directory search. We need to
+ find the .so file with the highest version number. The user may
+ restrict the major version by saying, e.g., -lc.1. Also, if we
+ find a .so file, we need to look for a the same file after
+ replacing .so with .sa; if it exists, it will be an archive which
+ provide some initializations for data symbols, and we need to
+ search it after including the .so file. */
+
+static void
+gld${EMULATION_NAME}_create_output_section_statements ()
+{
+ lang_for_each_input_file (gld${EMULATION_NAME}_find_so);
+}
+
+/* Search the directory for a .so file for each library search. */
+
+static void
+gld${EMULATION_NAME}_find_so (inp)
+ lang_input_statement_type *inp;
+{
+ search_dirs_type *search;
+ char *found = NULL;
+ char *alc;
+ struct stat st;
+
+ if (! inp->search_dirs_flag
+ || ! inp->is_archive
+ || ! inp->dynamic)
+ return;
+
+ ASSERT (strncmp (inp->local_sym_name, "-l", 2) == 0);
+
+ for (search = search_head; search != NULL; search = search->next)
+ {
+ boolean found_static;
+
+ found = gld${EMULATION_NAME}_search_dir (search->name, inp->filename,
+ &found_static);
+ if (found != NULL || found_static)
+ break;
+ }
+
+ if (found == NULL)
+ {
+ /* We did not find a matching .so file. This isn't an error,
+ since there might still be a matching .a file, which will be
+ found by the usual search. */
+ return;
+ }
+
+ /* Replace the filename with the one we have found. */
+ alc = (char *) xmalloc (strlen (search->name) + strlen (found) + 2);
+ sprintf (alc, "%s/%s", search->name, found);
+ inp->filename = alc;
+
+ /* Turn off the search_dirs_flag to prevent ldfile_open_file from
+ searching for this file again. */
+ inp->search_dirs_flag = false;
+
+ free (found);
+
+ /* Now look for the same file name, but with .sa instead of .so. If
+ found, add it to the list of input files. */
+ alc = (char *) xmalloc (strlen (inp->filename) + 1);
+ strcpy (alc, inp->filename);
+ strstr (alc + strlen (search->name), ".so")[2] = 'a';
+ if (stat (alc, &st) != 0)
+ free (alc);
+ else
+ {
+ lang_input_statement_type *sa;
+
+ /* Add the .sa file to the statement list just before the .so
+ file. This is really a hack. */
+ sa = ((lang_input_statement_type *)
+ xmalloc (sizeof (lang_input_statement_type)));
+ *sa = *inp;
+
+ inp->filename = alc;
+ inp->local_sym_name = alc;
+
+ inp->header.next = (lang_statement_union_type *) sa;
+ inp->next_real_file = (lang_statement_union_type *) sa;
+ }
+}
+
+/* Search a directory for a .so file. */
+
+static char *
+gld${EMULATION_NAME}_search_dir (dirname, filename, found_static)
+ const char *dirname;
+ const char *filename;
+ boolean *found_static;
+{
+ int force_maj, force_min;
+ const char *dot;
+ unsigned int len;
+ char *alc;
+ char *found;
+ int max_maj, max_min;
+ DIR *dir;
+ struct dirent *entry;
+ unsigned int dirnamelen;
+ char *full_path;
+ int statval;
+ struct stat st;
+
+ *found_static = false;
+
+ force_maj = -1;
+ force_min = -1;
+ dot = strchr (filename, '.');
+ if (dot == NULL)
+ {
+ len = strlen (filename);
+ alc = NULL;
+ }
+ else
+ {
+ force_maj = atoi (dot + 1);
+
+ len = dot - filename;
+ alc = (char *) xmalloc (len + 1);
+ strncpy (alc, filename, len);
+ alc[len] = '\0';
+ filename = alc;
+
+ dot = strchr (dot + 1, '.');
+ if (dot != NULL)
+ force_min = atoi (dot + 1);
+ }
+
+ found = NULL;
+ max_maj = max_min = 0;
+
+ dir = opendir (dirname);
+ if (dir == NULL)
+ return NULL;
+ dirnamelen = strlen (dirname);
+
+ while ((entry = readdir (dir)) != NULL)
+ {
+ const char *s;
+ int found_maj, found_min;
+
+ if (strncmp (entry->d_name, "lib", 3) != 0
+ || strncmp (entry->d_name + 3, filename, len) != 0)
+ continue;
+
+ if (dot == NULL
+ && strcmp (entry->d_name + 3 + len, ".a") == 0)
+ {
+ *found_static = true;
+ continue;
+ }
+
+ /* We accept libfoo.so without a version number, even though the
+ native linker does not. This is more convenient for packages
+ which just generate .so files for shared libraries, as on ELF
+ systems. */
+ if (strncmp (entry->d_name + 3 + len, ".so", 3) != 0)
+ continue;
+ if (entry->d_name[6 + len] == '\0')
+ ;
+ else if (entry->d_name[6 + len] == '.'
+ && isdigit ((unsigned char) entry->d_name[7 + len]))
+ ;
+ else
+ continue;
+
+ for (s = entry->d_name + 6 + len; *s != '\0'; s++)
+ if (*s != '.' && ! isdigit ((unsigned char) *s))
+ break;
+ if (*s != '\0')
+ continue;
+
+ /* We've found a .so file. Work out the major and minor
+ version numbers. */
+ found_maj = 0;
+ found_min = 0;
+ sscanf (entry->d_name + 3 + len, ".so.%d.%d",
+ &found_maj, &found_min);
+
+ if ((force_maj != -1 && force_maj != found_maj)
+ || (force_min != -1 && force_min != found_min))
+ continue;
+
+ /* Make sure the file really exists (ignore broken symlinks). */
+ full_path = xmalloc (dirnamelen + 1 + strlen (entry->d_name) + 1);
+ sprintf (full_path, "%s/%s", dirname, entry->d_name);
+ statval = stat (full_path, &st);
+ free (full_path);
+ if (statval != 0)
+ continue;
+
+ /* We've found a match for the name we are searching for. See
+ if this is the version we should use. If the major and minor
+ versions match, we use the last entry in alphabetical order;
+ I don't know if this is how SunOS distinguishes libc.so.1.8
+ from libc.so.1.8.1, but it ought to suffice. */
+ if (found == NULL
+ || (found_maj > max_maj)
+ || (found_maj == max_maj
+ && (found_min > max_min
+ || (found_min == max_min
+ && strcmp (entry->d_name, found) > 0))))
+ {
+ if (found != NULL)
+ free (found);
+ found = (char *) xmalloc (strlen (entry->d_name) + 1);
+ strcpy (found, entry->d_name);
+ max_maj = found_maj;
+ max_min = found_min;
+ }
+ }
+
+ closedir (dir);
+
+ if (alc != NULL)
+ free (alc);
+
+ return found;
+}
+
+/* These variables are required to pass information back and forth
+ between after_open and check_needed. */
+
+static struct bfd_link_needed_list *global_needed;
+static boolean global_found;
+
+/* 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 ld_need entries in dynamic
+ objects included in the link. 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_sunos_get_needed_list (output_bfd, &link_info);
+ for (l = needed; l != NULL; l = l->next)
+ {
+ struct bfd_link_needed_list *ll;
+ const char *lname;
+ search_dirs_type *search;
+
+ lname = l->name;
+
+ /* If we've already seen this file, skip it. */
+ for (ll = needed; ll != l; ll = ll->next)
+ if (strcmp (ll->name, lname) == 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;
+
+ if (strncmp (lname, "-l", 2) != 0)
+ {
+ bfd *abfd;
+
+ abfd = bfd_openr (lname, bfd_get_target (output_bfd));
+ if (abfd != NULL)
+ {
+ if (! bfd_check_format (abfd, bfd_object))
+ {
+ (void) bfd_close (abfd);
+ abfd = NULL;
+ }
+ }
+ if (abfd != NULL)
+ {
+ if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0)
+ {
+ (void) bfd_close (abfd);
+ abfd = NULL;
+ }
+ }
+ if (abfd != NULL)
+ {
+ /* We've found the needed dynamic object. */
+ if (! bfd_link_add_symbols (abfd, &link_info))
+ einfo ("%F%B: could not read symbols: %E\n", abfd);
+ }
+ else
+ {
+ einfo ("%P: warning: %s, needed by %B, not found\n",
+ lname, l->by);
+ }
+
+ continue;
+ }
+
+ lname += 2;
+
+ /* 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 or -L, then the environment variable
+ LD_LIBRARY_PATH (native only), then (if rpath was used) the
+ linker script LIB_SEARCH_DIRS. */
+ if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
+ lname))
+ continue;
+ if (command_line.rpath != NULL)
+ {
+ if (gld${EMULATION_NAME}_search_needed (command_line.rpath, lname))
+ continue;
+ }
+ else
+ {
+ for (search = search_head; search != NULL; search = search->next)
+ if (gld${EMULATION_NAME}_try_needed (search->name, lname))
+ break;
+ if (search != NULL)
+ continue;
+ }
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+ if [ "x${DEFAULT_EMULATION}" = "x${EMULATION_NAME}" ] ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ {
+ const char *lib_path;
+
+ lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
+ if (gld${EMULATION_NAME}_search_needed (lib_path, lname))
+ continue;
+ }
+EOF
+ fi
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
+ if (command_line.rpath != NULL)
+ {
+ for (search = search_head; search != NULL; search = search->next)
+ {
+ if (search->cmdline)
+ continue;
+ if (gld${EMULATION_NAME}_try_needed (search->name, lname))
+ break;
+ }
+ if (search != NULL)
+ continue;
+ }
+
+ einfo ("%P: warning: %s, needed by %B, not found\n",
+ l->name, l->by);
+ }
+}
+
+/* Search for a needed file in a path. */
+
+static boolean
+gld${EMULATION_NAME}_search_needed (path, name)
+ const char *path;
+ const char *name;
+{
+ const char *s;
+
+ if (path == NULL || *path == '\0')
+ return false;
+ while (1)
+ {
+ const char *dir;
+ char *dircopy;
+
+ s = strchr (path, ':');
+ if (s == NULL)
+ {
+ dircopy = NULL;
+ dir = path;
+ }
+ else
+ {
+ dircopy = (char *) xmalloc (s - path + 1);
+ memcpy (dircopy, path, s - path);
+ dircopy[s - path] = '\0';
+ dir = dircopy;
+ }
+
+ if (gld${EMULATION_NAME}_try_needed (dir, name))
+ return true;
+
+ if (dircopy != NULL)
+ free (dircopy);
+
+ if (s == NULL)
+ break;
+ path = s + 1;
+ }
+
+ return false;
+}
+
+/* This function is called for each possible directory for a needed
+ dynamic object. */
+
+static boolean
+gld${EMULATION_NAME}_try_needed (dir, name)
+ const char *dir;
+ const char *name;
+{
+ char *file;
+ char *alc;
+ boolean ignore;
+ bfd *abfd;
+
+ file = gld${EMULATION_NAME}_search_dir (dir, name, &ignore);
+ if (file == NULL)
+ return false;
+
+ alc = (char *) xmalloc (strlen (dir) + strlen (file) + 2);
+ sprintf (alc, "%s/%s", dir, file);
+ free (file);
+ abfd = bfd_openr (alc, bfd_get_target (output_bfd));
+ if (abfd == NULL)
+ return false;
+ if (! bfd_check_format (abfd, bfd_object))
+ {
+ (void) bfd_close (abfd);
+ return false;
+ }
+ if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0)
+ {
+ (void) bfd_close (abfd);
+ return false;
+ }
+
+ /* We've found the needed dynamic object. */
+
+ /* Add this file into the symbol table. */
+ if (! bfd_link_add_symbols (abfd, &link_info))
+ einfo ("%F%B: could not read symbols: %E\n", abfd);
+
+ return true;
+}
+
+/* See if we have already included a needed object in the link. This
+ does not have to be precise, as it does no harm to include a
+ dynamic object more than once. */
+
+static void
+gld${EMULATION_NAME}_check_needed (s)
+ lang_input_statement_type *s;
+{
+ if (s->filename == NULL)
+ return;
+ if (strncmp (global_needed->name, "-l", 2) != 0)
+ {
+ if (strcmp (s->filename, global_needed->name) == 0)
+ global_found = true;
+ }
+ else
+ {
+ const char *sname, *lname;
+ const char *sdot, *ldot;
+ int lmaj, lmin, smaj, smin;
+
+ lname = global_needed->name + 2;
+
+ sname = strrchr (s->filename, '/');
+ if (sname == NULL)
+ sname = s->filename;
+ else
+ ++sname;
+
+ if (strncmp (sname, "lib", 3) != 0)
+ return;
+ sname += 3;
+
+ ldot = strchr (lname, '.');
+ if (ldot == NULL)
+ ldot = lname + strlen (lname);
+
+ sdot = strstr (sname, ".so.");
+ if (sdot == NULL)
+ return;
+
+ if (sdot - sname != ldot - lname
+ || strncmp (lname, sname, sdot - sname) != 0)
+ return;
+
+ lmaj = lmin = -1;
+ sscanf (ldot, ".%d.%d", &lmaj, &lmin);
+ smaj = smin = -1;
+ sscanf (sdot, ".so.%d.%d", &smaj, &smin);
+ if ((smaj != lmaj && smaj != -1 && lmaj != -1)
+ || (smin != lmin && smin != -1 && lmin != -1))
+ return;
+
+ global_found = true;
+ }
+}
+
+/* We need to use static variables to pass information around the call
+ to lang_for_each_statement. Ick. */
+
+static const char *find_assign;
+static boolean found_assign;
+
+/* We need to use static variables to pass information around the call
+ to lang_for_each_input_file. Ick. */
+
+static bfd_size_type need_size;
+static bfd_size_type need_entries;
+static bfd_byte *need_contents;
+static bfd_byte *need_pinfo;
+static bfd_byte *need_pnames;
+
+/* The size of one entry in the .need section, not including the file
+ name. */
+
+#define NEED_ENTRY_SIZE (16)
+
+/* This is called after the sections have been attached to output
+ sections, but before any sizes or addresses have been set. */
+
+static void
+gld${EMULATION_NAME}_before_allocation ()
+{
+ struct bfd_link_hash_entry *hdyn = NULL;
+ asection *sneed;
+ asection *srules;
+ asection *sdyn;
+
+ /* The SunOS native linker creates a shared library whenever there
+ are any undefined symbols in a link, unless -e is used. This is
+ pretty weird, but we are compatible. */
+ if (! link_info.shared && ! link_info.relocateable && ! entry_from_cmdline)
+ {
+ struct bfd_link_hash_entry *h;
+
+ for (h = link_info.hash->undefs; h != NULL; h = h->next)
+ {
+ if (h->type == bfd_link_hash_undefined
+ && h->u.undef.abfd != NULL
+ && (h->u.undef.abfd->flags & DYNAMIC) == 0
+ && strcmp (h->root.string, "__DYNAMIC") != 0
+ && strcmp (h->root.string, "__GLOBAL_OFFSET_TABLE_") != 0)
+ {
+ find_assign = h->root.string;
+ found_assign = false;
+ lang_for_each_statement (gld${EMULATION_NAME}_find_assignment);
+ if (! found_assign)
+ {
+ link_info.shared = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (link_info.shared)
+ {
+ lang_output_section_statement_type *os;
+
+ /* Set the .text section to start at 0x20, not 0x2020. FIXME:
+ This is too magical. */
+ os = lang_output_section_statement_lookup (".text");
+ if (os->addr_tree == NULL)
+ os->addr_tree = exp_intop (0x20);
+ }
+
+ /* We need to create a __DYNAMIC symbol. We don't do this in the
+ linker script because we want to set the value to the start of
+ the dynamic section if there is one, or to zero if there isn't
+ one. We need to create the symbol before calling
+ size_dynamic_sections, although we can't set the value until
+ afterward. */
+ if (! link_info.relocateable)
+ {
+ hdyn = bfd_link_hash_lookup (link_info.hash, "__DYNAMIC", true, false,
+ false);
+ if (hdyn == NULL)
+ einfo ("%P%F: bfd_link_hash_lookup: %E\n");
+ if (! bfd_sunos_record_link_assignment (output_bfd, &link_info,
+ "__DYNAMIC"))
+ einfo ("%P%F: failed to record assignment to __DYNAMIC: %E\n");
+ }
+
+ /* If we are going to make any variable assignments, we need to let
+ the backend linker know about them in case the variables are
+ referred to by dynamic objects. */
+ lang_for_each_statement (gld${EMULATION_NAME}_find_assignment);
+
+ /* Let the backend linker work out the sizes of any sections
+ required by dynamic linking. */
+ if (! bfd_sunos_size_dynamic_sections (output_bfd, &link_info, &sdyn,
+ &sneed, &srules))
+ einfo ("%P%F: failed to set dynamic section sizes: %E\n");
+
+ if (sneed != NULL)
+ {
+ /* Set up the .need section. See the description of the ld_need
+ field in include/aout/sun4.h. */
+
+ need_entries = 0;
+ need_size = 0;
+
+ lang_for_each_input_file (gld${EMULATION_NAME}_count_need);
+
+ /* We should only have a .need section if we have at least one
+ dynamic object. */
+ ASSERT (need_entries != 0);
+
+ sneed->_raw_size = need_size;
+ sneed->contents = (bfd_byte *) xmalloc (need_size);
+
+ need_contents = sneed->contents;
+ need_pinfo = sneed->contents;
+ need_pnames = sneed->contents + need_entries * 16;
+
+ lang_for_each_input_file (gld${EMULATION_NAME}_set_need);
+
+ ASSERT ((bfd_size_type) (need_pnames - sneed->contents) == need_size);
+ }
+
+ if (srules != NULL)
+ {
+ /* Set up the .rules section. This is just a PATH like string
+ of the -L arguments given on the command line. We permit the
+ user to specify the directories using the -rpath command line
+ option. */
+ if (command_line.rpath)
+ {
+ srules->_raw_size = strlen (command_line.rpath);
+ srules->contents = (bfd_byte *) command_line.rpath;
+ }
+ else
+ {
+ unsigned int size;
+ search_dirs_type *search;
+
+ size = 0;
+ for (search = search_head; search != NULL; search = search->next)
+ if (search->cmdline)
+ size += strlen (search->name) + 1;
+ srules->_raw_size = size;
+ if (size > 0)
+ {
+ char *p;
+
+ srules->contents = (bfd_byte *) xmalloc (size);
+ p = (char *) srules->contents;
+ *p = '\0';
+ for (search = search_head; search != NULL; search = search->next)
+ {
+ if (search->cmdline)
+ {
+ if (p != (char *) srules->contents)
+ *p++ = ':';
+ strcpy (p, search->name);
+ p += strlen (p);
+ }
+ }
+ }
+ }
+ }
+
+ /* We must assign a value to __DYNAMIC. It should be zero if we are
+ not doing a dynamic link, or the start of the .dynamic section if
+ we are doing one. */
+ if (! link_info.relocateable)
+ {
+ hdyn->type = bfd_link_hash_defined;
+ hdyn->u.def.value = 0;
+ if (sdyn != NULL)
+ hdyn->u.def.section = sdyn;
+ else
+ hdyn->u.def.section = bfd_abs_section_ptr;
+ }
+}
+
+/* This is called by the before_allocation routine via
+ lang_for_each_statement. It does one of two things: if the
+ variable find_assign is set, it sets found_assign if it finds an
+ assignment to that variable; otherwise it tells the backend linker
+ about all assignment statements, in case they are assignments to
+ symbols which are referred to by dynamic objects. */
+
+static void
+gld${EMULATION_NAME}_find_assignment (s)
+ lang_statement_union_type *s;
+{
+ if (s->header.type == lang_assignment_statement_enum
+ && (find_assign == NULL || ! found_assign))
+ gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
+}
+
+/* Look through an expression for an assignment statement. */
+
+static void
+gld${EMULATION_NAME}_find_exp_assignment (exp)
+ etree_type *exp;
+{
+ switch (exp->type.node_class)
+ {
+ case etree_assign:
+ if (find_assign != NULL)
+ {
+ if (strcmp (find_assign, exp->assign.dst) == 0)
+ found_assign = true;
+ return;
+ }
+
+ if (strcmp (exp->assign.dst, ".") != 0)
+ {
+ if (! bfd_sunos_record_link_assignment (output_bfd, &link_info,
+ exp->assign.dst))
+ 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;
+ }
+}
+
+/* Work out the size of the .need section, and the number of entries.
+ The backend will set the ld_need field of the dynamic linking
+ information to point to the .need section. See include/aout/sun4.h
+ for more information. */
+
+static void
+gld${EMULATION_NAME}_count_need (inp)
+ lang_input_statement_type *inp;
+{
+ if (inp->the_bfd != NULL
+ && (inp->the_bfd->flags & DYNAMIC) != 0)
+ {
+ ++need_entries;
+ need_size += NEED_ENTRY_SIZE;
+ if (! inp->is_archive)
+ need_size += strlen (inp->filename) + 1;
+ else
+ {
+ ASSERT (inp->local_sym_name[0] == '-'
+ && inp->local_sym_name[1] == 'l');
+ need_size += strlen (inp->local_sym_name + 2) + 1;
+ }
+ }
+}
+
+/* Fill in the contents of the .need section. */
+
+static void
+gld${EMULATION_NAME}_set_need (inp)
+ lang_input_statement_type *inp;
+{
+ if (inp->the_bfd != NULL
+ && (inp->the_bfd->flags & DYNAMIC) != 0)
+ {
+ bfd_size_type c;
+
+ /* To really fill in the .need section contents, we need to know
+ the final file position of the section, but we don't.
+ Instead, we use offsets, and rely on the BFD backend to
+ finish the section up correctly. FIXME: Talk about lack of
+ referential locality. */
+ bfd_put_32 (output_bfd, need_pnames - need_contents, need_pinfo);
+ if (! inp->is_archive)
+ {
+ bfd_put_32 (output_bfd, (bfd_vma) 0, need_pinfo + 4);
+ bfd_put_16 (output_bfd, (bfd_vma) 0, need_pinfo + 8);
+ bfd_put_16 (output_bfd, (bfd_vma) 0, need_pinfo + 10);
+ strcpy (need_pnames, inp->filename);
+ }
+ else
+ {
+ char *verstr;
+ int maj, min;
+
+ bfd_put_32 (output_bfd, (bfd_vma) 0x80000000, need_pinfo + 4);
+ maj = 0;
+ min = 0;
+ verstr = strstr (inp->filename, ".so.");
+ if (verstr != NULL)
+ sscanf (verstr, ".so.%d.%d", &maj, &min);
+ bfd_put_16 (output_bfd, (bfd_vma) maj, need_pinfo + 8);
+ bfd_put_16 (output_bfd, (bfd_vma) min, need_pinfo + 10);
+ strcpy (need_pnames, inp->local_sym_name + 2);
+ }
+
+ c = (need_pinfo - need_contents) / NEED_ENTRY_SIZE;
+ if (c + 1 >= need_entries)
+ bfd_put_32 (output_bfd, (bfd_vma) 0, need_pinfo + 12);
+ else
+ bfd_put_32 (output_bfd, (bfd_vma) (c + 1) * NEED_ENTRY_SIZE,
+ need_pinfo + 12);
+
+ need_pinfo += NEED_ENTRY_SIZE;
+ need_pnames += strlen (need_pnames) + 1;
+ }
+}
+
+static char *
+gld${EMULATION_NAME}_get_script(isfile)
+ int *isfile;
+EOF
+
+if test -n "$COMPILE_IN"
+then
+# Scripts compiled in.
+
+# sed commands to quote an ld script as a C string.
+sc='s/["\\]/\\&/g
+s/$/\\n\\/
+1s/^/"/
+$s/$/n"/
+'
+
+cat >>e${EMULATION_NAME}.c <<EOF
+{
+ *isfile = 0;
+
+ if (link_info.relocateable == true && config.build_constructors == true)
+ return `sed "$sc" ldscripts/${EMULATION_NAME}.xu`;
+ else if (link_info.relocateable == true)
+ return `sed "$sc" ldscripts/${EMULATION_NAME}.xr`;
+ else if (!config.text_read_only)
+ return `sed "$sc" ldscripts/${EMULATION_NAME}.xbn`;
+ else if (!config.magic_demand_paged)
+ return `sed "$sc" ldscripts/${EMULATION_NAME}.xn`;
+ else
+ return `sed "$sc" ldscripts/${EMULATION_NAME}.x`;
+}
+EOF
+
+else
+# Scripts read from the filesystem.
+
+cat >>e${EMULATION_NAME}.c <<EOF
+{
+ *isfile = 1;
+
+ if (link_info.relocateable == true && config.build_constructors == true)
+ return "ldscripts/${EMULATION_NAME}.xu";
+ else if (link_info.relocateable == true)
+ return "ldscripts/${EMULATION_NAME}.xr";
+ else if (!config.text_read_only)
+ return "ldscripts/${EMULATION_NAME}.xbn";
+ else if (!config.magic_demand_paged)
+ return "ldscripts/${EMULATION_NAME}.xn";
+ else
+ return "ldscripts/${EMULATION_NAME}.x";
+}
+EOF
+
+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,
+ "${EMULATION_NAME}",
+ "${OUTPUT_FORMAT}",
+ NULL, /* finish */
+ gld${EMULATION_NAME}_create_output_section_statements,
+ NULL, /* open_dynamic_library */
+ NULL, /* place_orphan */
+ gld${EMULATION_NAME}_set_symbols
+};
+EOF