Fix up dependencies and rules for ld.dvi, ld.info.
[deliverable/binutils-gdb.git] / ld / ldmain.c
index 6fb9bdb396c6accb2b21b696beb9c7aaec0d3753..5b00ad456035e8136873ede28476d65a0496a8c2 100644 (file)
@@ -1,10 +1,11 @@
 /* Copyright (C) 1991 Free Software Foundation, Inc.
-   
+   Written by Steve Chamberlain steve@cygnus.com
+
 This file is part of GLD, the Gnu Linker.
 
 GLD 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 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
 GLD is distributed in the hope that it will be useful,
@@ -16,17 +17,9 @@ You should have received a copy of the GNU General Public License
 along with GLD; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
-/* 
- *  Written by Steve Chamberlain steve@cygnus.com
- *
- * $Id$ 
- *
- *
- */
-
 
-#include "sysdep.h"
 #include "bfd.h"
+#include "sysdep.h"
 
 #include "config.h"
 #include "ld.h"
@@ -36,32 +29,53 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "ldgram.h"
 #include "ldsym.h"
 #include "ldlang.h"
-#include "ld-emul.h"
+#include "ldemul.h"
 #include "ldlex.h"
 #include "ldfile.h"
+#include "ldindr.h"
+#include "ldwarn.h"
+#include "ldctor.h"
+#include "lderror.h"
+
+/* Somewhere above, sys/stat.h got included . . . . */
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define        S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#include <string.h>
+
+static char *get_emulation ();
+static void set_scripts_dir ();
 
 /* IMPORTS */
 extern boolean lang_has_input_file;
-extern boolean trace_files;
+extern boolean force_make_executable;
+extern boolean relaxing;
+extern boolean had_script;
+
 /* EXPORTS */
 
 char *default_target;
 char *output_filename = "a.out";
+
 /* Name this program was invoked by.  */
 char *program_name;
 
 /* The file that we're creating */
-bfd *output_bfd;
+bfd *output_bfd = 0;
 
-extern boolean option_v;
+/* set if -y on the command line */
+int had_y;
 
 /* The local symbol prefix */
 char lprefix = 'L';
 
+/* Set by -G argument, for MIPS ECOFF target.  */
+int g_switch_value = 8;
+
 /* Count the number of global symbols multiply defined.  */
 int multiple_def_count;
 
-
 /* Count the number of symbols defined through common declarations.
    This count is referenced in symdef_library, linear_library, and
    modified by enter_global_ref.
@@ -70,54 +84,32 @@ int multiple_def_count;
    decremented when the common declaration is overridden
 
    Another way of thinking of it is that this is a count of
-   all ldsym_types with a ->scoms field
-*/
-unsigned int commons_pending;
+   all ldsym_types with a ->scoms field */
 
+unsigned int commons_pending;
 
-/* Count the number of global symbols referenced and not defined. 
-   common symbols are not included in this count.
-  */
+/* Count the number of global symbols referenced and not defined.
+   common symbols are not included in this count.   */
 
 unsigned int undefined_global_sym_count;
 
-
-
-/* Count the number of warning symbols encountered. */
-int warning_count;
-
-/* have we had a load script ? */
-extern boolean had_script;
-
-
-
 /* Nonzero means print names of input files as processed.  */
 boolean trace_files;
 
-
+/* Nonzero means same, but note open failures, too.  */
+boolean trace_file_tries;
 
 /* 1 => write load map.  */
 boolean write_map;
 
-
-int unix_relocate;
-
-
-
-
-
-
-
-
-/* Force the make_executable to be output, even if there are non-fatal
-   errors */
-boolean force_make_executable;
-
+#ifdef GNU960
+/* Indicates whether output file will be b.out (default) or coff */
+enum target_flavour output_flavor = BFD_BOUT_FORMAT;
+#endif
 
 /* A count of the total number of local symbols ever seen - by adding
  the symbol_count field of each newly read afile.*/
 
-
 unsigned int total_symbols_seen;
 
 /* A count of the number of read files - the same as the number of elements
@@ -125,143 +117,321 @@ unsigned int total_symbols_seen;
  */
 unsigned int total_files_seen;
 
-
-/* IMPORTS */
 args_type command_line;
+
 ld_config_type config;
-int
+\f
+void
 main (argc, argv)
      char **argv;
      int argc;
 {
   char *emulation;
-  program_name = argv[0];
-  output_filename = "a.out";
 
-#ifdef GNU960
-  check_v960( argc, argv );
-#endif
+  program_name = argv[0];
 
-  emulation =  (char *) getenv(EMULATION_ENVIRON); 
+  bfd_init ();
 
   /* Initialize the data about options.  */
-  strip_symbols = STRIP_NONE;
-  trace_files = false;
-  discard_locals = DISCARD_NONE;
 
+
+  trace_files = trace_file_tries = false;
   write_map = false;
   config.relocateable_output = false;
-  unix_relocate = 0;
   command_line.force_common_definition = false;
 
-  ldfile_add_arch("");
-  ldfile_add_library_path("./");
+  init_bfd_error_vector ();
+  ldsym_init ();
+  ldfile_add_arch ("");
+
+  set_scripts_dir ();
+
   config.make_executable = true;
   force_make_executable = false;
 
 
   /* Initialize the cumulative counts of symbols.  */
   undefined_global_sym_count = 0;
-  warning_count = 0;
   multiple_def_count = 0;
   commons_pending = 0;
 
-  config.magic_demand_paged = true ;
+  config.magic_demand_paged = true;
+  config.text_read_only = true;
   config.make_executable = true;
 
-#ifdef GNU960
-  ldemul_choose_mode(LNK960_EMULATION_NAME);
-#else
-  if (emulation == (char *)NULL) {
-    emulation= DEFAULT_EMULATION;
-  }
+  emulation = get_emulation (argc, argv);
+  ldemul_choose_mode (emulation);
+  default_target = ldemul_choose_target ();
+  lang_init ();
+  ldemul_before_parse ();
+  lang_has_input_file = false;
+  parse_args (argc, argv);
 
+  if (had_script == false)
+    {
+      /* Read the emulation's appropriate default script.  */
+      int isfile;
+      char *s = ldemul_get_script (&isfile);
 
-  ldemul_choose_mode(emulation);
-#endif
+      if (isfile)
+       {
+         /* sizeof counts the terminating NUL.  */
+         size_t size = strlen (s) + sizeof ("-T ");
+         char *buf = (char *) ldmalloc(size);
+         sprintf (buf, "-T %s", s);
+         parse_line (buf, 0);
+         free (buf);
+       }
+      else
+       parse_line (s, 1);
+    }
 
-  default_target =  ldemul_choose_target();
+  if (config.relocateable_output && command_line.relax)
+    {
+      einfo ("%P%F: -relax and -r may not be used together\n");
+    }
+  lang_final ();
 
-  lang_init();
-  ldemul_before_parse();
-  lang_has_input_file = false;
-  parse_args(argc, argv);
-  lang_final(); 
-  if (trace_files) {
-    info("%P: mode %s\n", emulation);
-  }
-  if (lang_has_input_file == false) {
-    info("%P%F: No input files\n");
-  }
+  if (lang_has_input_file == false)
+    {
+      einfo ("%P%F: No input files\n");
+    }
 
-  ldemul_after_parse();
+  if (trace_files)
+    {
+      info ("%P: mode %s\n", emulation);
+    }
+
+  ldemul_after_parse ();
 
-  lang_process();
 
+  if (config.map_filename)
+    {
+      if (strcmp (config.map_filename, "-") == 0)
+       {
+         config.map_file = stdout;
+       }
+      else
+       {
+         config.map_file = fopen (config.map_filename, FOPEN_WT);
+         if (config.map_file == (FILE *) NULL)
+           {
+             einfo ("%P%F: cannot open map file %s: %E\n",
+                    config.map_filename);
+           }
+       }
+    }
 
 
+  lang_process ();
 
   /* Print error messages for any missing symbols, for any warning
      symbols, and possibly multiple definitions */
 
-  /* Print a map, if requested.  */
 
-  if (write_map) {
-    ldsym_print_symbol_table ();
-    lang_map(stdout);
-  }
+  if (config.text_read_only)
+    {
+      /* Look for a text section and mark the readonly attribute in it */
+      asection *found = bfd_get_section_by_name (output_bfd, ".text");
 
+      if (found != (asection *) NULL)
+       {
+         found->flags |= SEC_READONLY;
+       }
+    }
 
-  if (config.relocateable_output) {
-    output_bfd->flags &=  ~( D_PAGED);
-    output_bfd->flags |= EXEC_P;
-    ldwrite();
-    bfd_close(output_bfd);
-  }
-  else {
+  if (config.relocateable_output)
+    output_bfd->flags &= ~EXEC_P;
+  else
     output_bfd->flags |= EXEC_P;
 
-    ldwrite();
-    bfd_close(output_bfd);
-    if (config.make_executable == false && force_make_executable == false) {
-      unlink(output_filename);
+  ldwrite ();
+
+  /* Even if we're producing relocateable output, some non-fatal errors should
+     be reported in the exit status.  (What non-fatal errors, if any, do we
+     want to ignore for relocateable output?)  */
+
+  if (config.make_executable == false && force_make_executable == false)
+    {
+      if (trace_files == true)
+       {
+         einfo ("%P: Link errors found, deleting executable `%s'\n",
+                output_filename);
+       }
+
+      if (output_bfd->iostream)
+       fclose ((FILE *) (output_bfd->iostream));
+
+      unlink (output_filename);
+      exit (1);
+    }
+  else
+    {
+      bfd_close (output_bfd);
+    }
+
+  exit (0);
+}
+
+/* We need to find any explicitly given emulation in order to initialize the
+   state that's needed by the lex&yacc argument parser (parse_args).  */
+
+static char *
+get_emulation (argc, argv)
+     int argc;
+     char **argv;
+{
+  char *emulation;
+  int i;
+
+#ifdef GNU960
+  check_v960 (argc, argv);
+  emulation = "gld960";
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (argv[i], "-Fcoff"))
+       {
+         emulation = "lnk960";
+         output_flavor = BFD_COFF_FORMAT;
+         break;
+       }
+    }
+#else
+  emulation = (char *) getenv (EMULATION_ENVIRON);
+  if (emulation == NULL)
+    emulation = DEFAULT_EMULATION;
+#endif
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strncmp (argv[i], "-m", 2))
+       {
+         if (argv[i][2] == '\0')
+           {
+             /* -m EMUL */
+             if (i < argc - 1)
+               {
+                 emulation = argv[i + 1];
+                 i++;
+               }
+             else
+               {
+                 einfo("%P%F missing argument to -m\n");
+               }
+           }
+         else
+           {
+             /* -mEMUL */
+             emulation = &argv[i][2];
+           }
+       }
+    }
+
+  return emulation;
+}
+
+/* If directory DIR contains an "ldscripts" subdirectory,
+   add DIR to the library search path and return true,
+   else return false.  */
+
+static boolean
+check_for_scripts_dir (dir)
+     char *dir;
+{
+  size_t dirlen;
+  char *buf;
+  struct stat s;
+  boolean res;
+
+  dirlen = strlen (dir);
+  /* sizeof counts the terminating NUL.  */
+  buf = (char *) ldmalloc (dirlen + sizeof("/ldscripts"));
+  sprintf (buf, "%s/ldscripts", dir);
+
+  res = stat (buf, &s) == 0 && S_ISDIR (s.st_mode);
+  free (buf);
+  if (res)
+    ldfile_add_library_path (dir);
+  return res;
+}
+
+/* Set the default directory for finding script files.
+   Libraries will be searched for here too, but that's ok.
+   We look for the "ldscripts" directory in:
+
+   SCRIPTDIR (passed from Makefile)
+   the dir where this program is (for using it from the build tree)
+   the dir where this program is/../lib (for installing the tool suite elsewhere) */
+
+static void
+set_scripts_dir ()
+{
+  char *end, *dir;
+  size_t dirlen;
+
+  if (check_for_scripts_dir (SCRIPTDIR))
+    return;                    /* We've been installed normally.  */
+
+  /* Look for "ldscripts" in the dir where our binary is.  */
+  end = strrchr (program_name, '/');
+  if (end)
+    {
+      dirlen = end - program_name;
+      /* Make a copy of program_name in dir.
+        Leave room for later "/../lib".  */
+      dir = (char *) ldmalloc (dirlen + 8);
+      strncpy (dir, program_name, dirlen);
+      dir[dirlen] = '\0';
     }
-    return (!config.make_executable);
-  }
+  else
+    {
+      dirlen = 1;
+      dir = (char *) ldmalloc (dirlen + 8);
+      strcpy (dir, ".");
+    }
+
+  if (check_for_scripts_dir (dir))
+    return;                    /* Don't free dir.  */
 
-  return(0);
-} /* main() */
+  /* Look for "ldscripts" in <the dir where our binary is>/../lib.  */
+  strcpy (dir + dirlen, "/../lib");
+  if (check_for_scripts_dir (dir))
+    return;
 
+  free (dir);                  /* Well, we tried.  */
+}
 
 void
-Q_read_entry_symbols (desc, entry)
+read_entry_symbols (desc, entry)
      bfd *desc;
      struct lang_input_statement_struct *entry;
 {
-  if (entry->asymbols == (asymbol **)NULL) {
-    size_t table_size = get_symtab_upper_bound(desc);
-    entry->asymbols = (asymbol **)ldmalloc(table_size);
+  if (entry->asymbols == (asymbol **) NULL)
+    {
+      bfd_size_type table_size = get_symtab_upper_bound (desc);
 
-    entry->symbol_count =  bfd_canonicalize_symtab(desc, entry->asymbols) ;
-  }
+      entry->asymbols = (asymbol **) ldmalloc (table_size);
+      entry->symbol_count = bfd_canonicalize_symtab (desc, entry->asymbols);
+    }
 }
 
-
 /*
- * turn this item into a reference 
+ * turn this item into a reference
  */
-static void
-refize(sp, nlist_p)
-ldsym_type *sp;
-asymbol **nlist_p;
+void
+refize (sp, nlist_p)
+     ldsym_type *sp;
+     asymbol **nlist_p;
 {
   asymbol *sym = *nlist_p;
+
   sym->value = 0;
-  sym->flags = BSF_UNDEFINED;
-  sym->section = (asection *)NULL;
-  sym->udata =(PTR)( sp->srefs_chain);
+  sym->flags = 0;
+  sym->section = &bfd_und_section;
+  sym->udata = (PTR) (sp->srefs_chain);
   sp->srefs_chain = nlist_p;
 }
+
 /*
 This function is called for each name which is seen which has a global
 scope. It enters the name into the global symbol table in the correct
@@ -285,149 +455,257 @@ Whilst all this is going on we keep a count of the number of multiple
 definitions seen, undefined global symbols and pending commons.
 */
 
-
 void
-Q_enter_global_ref (nlist_p)
-     asymbol **nlist_p;
-
+enter_global_ref (nlist_p, name)
+     asymbol ** nlist_p;       /* pointer into symbol table from incoming bfd */
+     CONST char *name; /* name of symbol in linker table */
 {
   asymbol *sym = *nlist_p;
-  CONST char *name = sym->name;
-  ldsym_type *sp = ldsym_get (name);
+  ldsym_type *sp;
+
+  /* Lookup the name from the incoming bfd's symbol table in the
+     linker's global symbol table */
+
 
   flagword this_symbol_flags = sym->flags;
 
+  sp = ldsym_get (name);
+
+
+  /* If this symbol already has udata, it means that something strange
+     has happened.
+
+     The strange thing is that we've had an undefined symbol resolved by
+     an alias, but the thing the alias defined wasn't in the file. So
+     the symbol got a udata entry, but the file wasn't loaded.  Then
+     later on the file was loaded, but we don't need to do this
+     processing again */
+
+
+  if (sym->udata)
+    return;
 
-  ASSERT(sym->udata == 0);
-
-  /* Just place onto correct chain */
-  if (flag_is_common(this_symbol_flags)) {
-    /* If we have a definition of this symbol already then
-     * this common turns into a reference. Also we only
-     * ever point to the largest common, so if we
-     * have a common, but it's bigger that the new symbol
-     * the turn this into a reference too.
-     */
-    if (sp->sdefs_chain)  
-      {
-       /* This is a common symbol, but we already have a definition
-          for it, so just link it into the ref chain as if
-          it were a reference
-          */
-       refize(sp, nlist_p);
-      }
-    else  if (sp->scoms_chain) {
-      /* If we have a previous common, keep only the biggest */
-      if ( (*(sp->scoms_chain))->value > sym->value) {
-       /* other common is bigger, throw this one away */
-       refize(sp, nlist_p);
-      }
-      else if (sp->scoms_chain != nlist_p) {
-       /* other common is smaller, throw that away */
-       refize(sp, sp->scoms_chain);
-       sp->scoms_chain = nlist_p;
-      }
-    }
-    else {
-      /* This is the first time we've seen a common, so
-       * remember it - if it was undefined before, we know it's defined now
-       */
-      if (sp->srefs_chain)
-       undefined_global_sym_count--;
-
-      commons_pending++;
-      sp->scoms_chain = nlist_p;
-    }
-  }
-
-  else if (flag_is_defined(this_symbol_flags)) {
-    /* This is the definition of a symbol, add to def chain */
-    if (sp->sdefs_chain && (*(sp->sdefs_chain))->section != sym->section) {
-      /* Multiple definition */
-      asymbol *sy = *(sp->sdefs_chain);
-      lang_input_statement_type *stat = (lang_input_statement_type *) sy->the_bfd->usrdata;
-      lang_input_statement_type *stat1 = (lang_input_statement_type *) sym->the_bfd->usrdata;
-      asymbol ** stat1_symbols  = stat1 ? stat1->asymbols: 0;
-      asymbol ** stat_symbols = stat ? stat->asymbols:0;
-      
-      multiple_def_count++;
-      info("%C: multiple definition of `%T'\n",
-          sym->the_bfd,
-          sym->section,
-          stat1_symbols,
-          sym->value,
-          sym);
-          
-      info("%C: first seen here\n",
-          sy->the_bfd,
-          sy->section,
-          stat_symbols,
-          sy->value);
-    }
-    else {
-      sym->udata =(PTR)( sp->sdefs_chain);
-      sp->sdefs_chain = nlist_p;
-    }
-    /* A definition overrides a common symbol */
-    if (sp->scoms_chain) {
-      refize(sp, sp->scoms_chain);
-      sp->scoms_chain = 0;
-      commons_pending--;
-    }
-    else if (sp->srefs_chain) {
-      /* If previously was undefined, then remember as defined */
-      undefined_global_sym_count--;
-    }
-  }
-  else {
-    if (sp->scoms_chain == (asymbol **)NULL 
-       && sp->srefs_chain == (asymbol **)NULL 
-       && sp->sdefs_chain == (asymbol **)NULL) {
-      /* And it's the first time we've seen it */
-      undefined_global_sym_count++;
 
+  if (flag_is_constructor (this_symbol_flags))
+    {
+      /* Add this constructor to the list we keep */
+      ldlang_add_constructor (sp);
+      /* Turn any commons into refs */
+      if (sp->scoms_chain != (asymbol **) NULL)
+       {
+         refize (sp, sp->scoms_chain);
+         sp->scoms_chain = 0;
+       }
     }
+  else
+    {
+      if (bfd_is_com_section (sym->section))
+       {
+         /* If we have a definition of this symbol already then
+            this common turns into a reference. Also we only
+            ever point to the largest common, so if we
+            have a common, but it's bigger that the new symbol
+            the turn this into a reference too. */
+         if (sp->sdefs_chain)
+           {
+             /* This is a common symbol, but we already have a definition
+                for it, so just link it into the ref chain as if
+                it were a reference  */
+             if (config.warn_common)
+               multiple_warn("%C: warning: common of `%s' overridden by definition\n",
+                             sym,
+                             "%C: warning: defined here\n",
+                             *(sp->sdefs_chain));
+             refize (sp, nlist_p);
+           }
+         else if (sp->scoms_chain)
+           {
+             /* If we have a previous common, keep only the biggest */
+             if ((*(sp->scoms_chain))->value > sym->value)
+               {
+                 /* other common is bigger, throw this one away */
+                 if (config.warn_common)
+                   multiple_warn("%C: warning: common of `%s' overridden by larger common\n",
+                                 sym,
+                                 "%C: warning: larger common is here\n",
+                                 *(sp->scoms_chain));
+                 refize (sp, nlist_p);
+               }
+             else if (sp->scoms_chain != nlist_p)
+               {
+                 /* other common is smaller, throw that away */
+                 if (config.warn_common)
+                   {
+                     if ((*(sp->scoms_chain))->value < sym->value)
+                       multiple_warn("%C: warning: common of `%s' overriding smaller common\n",
+                                     sym,
+                                     "%C: warning: smaller common is here\n",
+                                     *(sp->scoms_chain));
+                     else
+                       multiple_warn("%C: warning: multiple common of `%s'\n",
+                                     sym,
+                                     "%C: warning: previous common is here\n",
+                                     *(sp->scoms_chain));
+                   }
+                 refize (sp, sp->scoms_chain);
+                 sp->scoms_chain = nlist_p;
+               }
+           }
+         else
+           {
+             /* This is the first time we've seen a common, so remember it
+                - if it was undefined before, we know it's defined now. If
+                the symbol has been marked as really being a constructor,
+                then treat this as a ref.  */
+             if (sp->flags & SYM_CONSTRUCTOR)
+               {
+                 /* Turn this into a ref */
+                 refize (sp, nlist_p);
+               }
+             else
+               {
+                 /* treat like a common */
+                 if (sp->srefs_chain)
+                   undefined_global_sym_count--;
 
-    refize(sp, nlist_p);
-  }
+                 commons_pending++;
+                 sp->scoms_chain = nlist_p;
+               }
+           }
+       }
+      else if (sym->section != &bfd_und_section)
+       {
+         /* This is the definition of a symbol, add to def chain */
+         if (sp->sdefs_chain && (*(sp->sdefs_chain))->section != sym->section)
+           {
+             /* Multiple definition */
+             multiple_warn("%X%C: multiple definition of `%s'\n",
+                           sym,
+                           "%X%C: first defined here\n",
+                           *(sp->sdefs_chain));
+             multiple_def_count++;
+           }
+         else
+           {
+             sym->udata = (PTR) (sp->sdefs_chain);
+             sp->sdefs_chain = nlist_p;
+           }
+         /* A definition overrides a common symbol */
+         if (sp->scoms_chain)
+           {
+             if (config.warn_common)
+               multiple_warn("%C: warning: definition of `%s' overriding common\n",
+                             sym,
+                             "%C: warning: common is here\n",
+                             *(sp->scoms_chain));
+             refize (sp, sp->scoms_chain);
+             sp->scoms_chain = 0;
+             commons_pending--;
+           }
+         else if (sp->srefs_chain && relaxing == false)
+           {
+             /* If previously was undefined, then remember as defined */
+             undefined_global_sym_count--;
+           }
+       }
+      else
+       {
+         if (sp->scoms_chain == (asymbol **) NULL
+             && sp->srefs_chain == (asymbol **) NULL
+             && sp->sdefs_chain == (asymbol **) NULL)
+           {
+             /* And it's the first time we've seen it */
+             undefined_global_sym_count++;
+           }
 
-  ASSERT(sp->sdefs_chain == 0 || sp->scoms_chain == 0);
-  ASSERT(sp->scoms_chain ==0 || (*(sp->scoms_chain))->udata == 0);
+         refize (sp, nlist_p);
+       }
+    }
+
+  ASSERT (sp->sdefs_chain == 0 || sp->scoms_chain == 0);
+  ASSERT (sp->scoms_chain == 0 || (*(sp->scoms_chain))->udata == 0);
 
 
 }
 
 static void
-Q_enter_file_symbols (entry)
-lang_input_statement_type *entry;
+enter_file_symbols (entry)
+     lang_input_statement_type *entry;
 {
-  asymbol **q ;
+  asymbol **q;
+
   entry->common_section =
-    bfd_make_section(entry->the_bfd, "COMMON");
-  
-  ldlang_add_file(entry);
+    bfd_make_section_old_way (entry->the_bfd, "COMMON");
+  entry->common_section->flags = SEC_NEVER_LOAD;
+  ldlang_add_file (entry);
 
 
-  if (trace_files || option_v) {
-    info("%I\n", entry);
-  }
+  if (trace_files || trace_file_tries)
+    {
+      info ("%I\n", entry);
+    }
 
   total_symbols_seen += entry->symbol_count;
-  total_files_seen ++;
-  for (q = entry->asymbols; *q; q++)
+  total_files_seen++;
+  if (entry->symbol_count)
     {
-      asymbol *p = *q;
-
-      if (flag_is_undefined_or_global_or_common(p->flags))
+      for (q = entry->asymbols; *q; q++)
        {
-         Q_enter_global_ref(q);
+         asymbol *p = *q;
+
+         if (had_y && p->name)
+           {
+             /* look up the symbol anyway to see if the trace bit was
+          set */
+             ldsym_type *s = ldsym_get (p->name);
+             if (s->flags & SYM_Y)
+               {
+                 einfo ("%B: %s %T\n", entry->the_bfd,
+                        p->section == &bfd_und_section ? "reference to" : "definition of ",
+                        p);
+               }
+           }
+
+         if (p->section == &bfd_ind_section)
+           {
+             add_indirect (q);
+           }
+         else if (p->flags & BSF_WARNING)
+           {
+             add_warning (p);
+           }
+         else if (p->section == &bfd_und_section
+                  || (p->flags & BSF_GLOBAL)
+                  || bfd_is_com_section (p->section)
+                  || (p->flags & BSF_CONSTRUCTOR))
+
+           {
+
+             asymbol *p = *q;
+
+             if (p->flags & BSF_INDIRECT)
+               {
+                 add_indirect (q);
+               }
+             else if (p->flags & BSF_WARNING)
+               {
+                 add_warning (p);
+               }
+             else if (p->section == &bfd_und_section
+                      || (p->flags & BSF_GLOBAL)
+                      || bfd_is_com_section (p->section)
+                      || (p->flags & BSF_CONSTRUCTOR))
+               {
+                 enter_global_ref (q, p->name);
+               }
+
+           }
+
        }
-      ASSERT(p->flags != 0);
     }
 }
 
 
-
 /* Searching libraries */
 
 struct lang_input_statement_struct *decode_library_subfile ();
@@ -444,75 +722,85 @@ search_library (entry)
 {
 
   /* No need to load a library if no undefined symbols */
-  if (!undefined_global_sym_count) return;
+  if (!undefined_global_sym_count)
+    return;
 
-  if (bfd_has_map(entry->the_bfd)) 
+  if (bfd_has_map (entry->the_bfd))
     symdef_library (entry);
   else
     linear_library (entry);
 
 }
 
-
 #ifdef GNU960
 static
-boolean
+  boolean
 gnu960_check_format (abfd, format)
-bfd *abfd;
-bfd_format format;
+     bfd *abfd;
+     bfd_format format;
 {
   boolean retval;
 
-  if ((bfd_check_format(abfd,format) == true) && BFD_COFF_FILE_P(abfd)) {
-       return true;
-  }
+  if ((bfd_check_format (abfd, format) == true)
+      && (abfd->xvec->flavour == output_flavor))
+    {
+      return true;
+    }
+
+
   return false;
 }
+
 #endif
 
 void
 ldmain_open_file_read_symbol (entry)
-struct lang_input_statement_struct *entry;
+     struct lang_input_statement_struct *entry;
 {
-  if (entry->asymbols == (asymbol **)NULL
-      &&entry->real == true 
-      && entry->filename != (char *)NULL)
+  if (entry->asymbols == (asymbol **) NULL
+      && entry->real == true
+      && entry->filename != (char *) NULL)
     {
       ldfile_open_file (entry);
 
+
 #ifdef GNU960
-      if (gnu960_check_format(entry->the_bfd, bfd_object))
+      if (gnu960_check_format (entry->the_bfd, bfd_object))
 #else
-      if (bfd_check_format(entry->the_bfd, bfd_object))
+      if (bfd_check_format (entry->the_bfd, bfd_object))
 #endif
        {
-         entry->the_bfd->usrdata = (PTR)entry;
+         entry->the_bfd->usrdata = (PTR) entry;
+
 
+         read_entry_symbols (entry->the_bfd, entry);
 
-         Q_read_entry_symbols (entry->the_bfd, entry);
-         Q_enter_file_symbols (entry);
+         /* look through the sections in the file and see if any of them
+            are constructors */
+         ldlang_check_for_constructors (entry);
+
+         enter_file_symbols (entry);
        }
 #ifdef GNU960
-      else if (gnu960_check_format(entry->the_bfd, bfd_archive)) 
+      else if (gnu960_check_format (entry->the_bfd, bfd_archive))
 #else
-      else if (bfd_check_format(entry->the_bfd, bfd_archive)) 
+      else if (bfd_check_format (entry->the_bfd, bfd_archive))
 #endif
        {
-         entry->the_bfd->usrdata = (PTR)entry;
+         entry->the_bfd->usrdata = (PTR) entry;
 
-         entry->subfiles = (lang_input_statement_type *)NULL;
+         entry->subfiles = (lang_input_statement_type *) NULL;
          search_library (entry);
        }
-      else 
+      else
        {
-         info("%F%B: malformed input file (not rel or archive) \n",
-                                               entry->the_bfd);
+         einfo ("%F%B: malformed input file (not rel or archive) \n",
+                entry->the_bfd);
        }
     }
 
 }
 
-
 /* Construct and return a lang_input_statement_struct for a library member.
    The library's lang_input_statement_struct is library_entry,
    and the library is open on DESC.
@@ -525,39 +813,59 @@ decode_library_subfile (library_entry, subfile_offset)
      bfd *subfile_offset;
 {
   register struct lang_input_statement_struct *subentry;
-  subentry = (struct lang_input_statement_struct *) ldmalloc (sizeof (struct lang_input_statement_struct));
-  subentry->filename = subfile_offset -> filename;
-  subentry->local_sym_name  = subfile_offset->filename;
-  subentry->asymbols = 0;
-  subentry->the_bfd = subfile_offset;
-  subentry->subfiles = 0;
-  subentry->next = 0;
-  subentry->superfile = library_entry;
-  subentry->is_archive = false;
-
-  subentry->just_syms_flag = false;
-  subentry->loaded = false;
-  subentry->chain = 0;
 
+
+  /* First, check if we already have a loaded
+     lang_input_statement_struct  for this library subfile.  If so,
+     just return it.  Otherwise, allocate some space and build a new one. */
+
+  if (subfile_offset->usrdata
+      && ((struct lang_input_statement_struct *) subfile_offset->usrdata)->
+      loaded == true)
+    {
+      subentry = (struct lang_input_statement_struct *) subfile_offset->usrdata;
+    }
+  else
+    {
+      subentry =
+       (struct lang_input_statement_struct *)
+       ldmalloc ((bfd_size_type) (sizeof (struct lang_input_statement_struct)));
+
+      subentry->filename = subfile_offset->filename;
+      subentry->local_sym_name = subfile_offset->filename;
+      subentry->asymbols = 0;
+      subentry->the_bfd = subfile_offset;
+      subentry->subfiles = 0;
+      subentry->next = 0;
+      subentry->superfile = library_entry;
+      subentry->is_archive = false;
+
+      subentry->just_syms_flag = false;
+      subentry->loaded = false;
+      subentry->chain = 0;
+    }
   return subentry;
 }
 
-boolean  subfile_wanted_p ();
+boolean subfile_wanted_p ();
 void
-clear_syms(entry, offset)
-struct lang_input_statement_struct *entry;
-file_ptr offset;
+clear_syms (entry, offset)
+     struct lang_input_statement_struct *entry;
+     file_ptr offset;
 {
   carsym *car;
-  unsigned long indx = bfd_get_next_mapent(entry->the_bfd,
-                                          BFD_NO_MORE_SYMBOLS,
-                                          &car);
-  while (indx != BFD_NO_MORE_SYMBOLS) {
-    if (car->file_offset == offset) {
-      car->name = 0;
+  unsigned long indx = bfd_get_next_mapent (entry->the_bfd,
+                                           BFD_NO_MORE_SYMBOLS,
+                                           &car);
+
+  while (indx != BFD_NO_MORE_SYMBOLS)
+    {
+      if (car->file_offset == offset)
+       {
+         car->name = 0;
+       }
+      indx = bfd_get_next_mapent (entry->the_bfd, indx, &car);
     }
-    indx = bfd_get_next_mapent(entry->the_bfd, indx, &car);
-  }
 
 }
 
@@ -572,44 +880,43 @@ symdef_library (entry)
 
   boolean not_finished = true;
 
-
   while (not_finished == true)
     {
       carsym *exported_library_name;
-      bfd *prev_archive_member_bfd = 0;    
+      bfd *prev_archive_member_bfd = 0;
 
-      int idx = bfd_get_next_mapent(entry->the_bfd,
-                                   BFD_NO_MORE_SYMBOLS,
-                                   &exported_library_name);
+      int idx = bfd_get_next_mapent (entry->the_bfd,
+                                    BFD_NO_MORE_SYMBOLS,
+                                    &exported_library_name);
 
       not_finished = false;
 
-      while (idx != BFD_NO_MORE_SYMBOLS  && undefined_global_sym_count)
+      while (idx != BFD_NO_MORE_SYMBOLS && undefined_global_sym_count)
        {
 
-         if (exported_library_name->name) 
+         if (exported_library_name->name)
            {
 
-             ldsym_type *sp =  ldsym_get_soft (exported_library_name->name);
+             ldsym_type *sp = ldsym_get_soft (exported_library_name->name);
 
              /* If we find a symbol that appears to be needed, think carefully
-                about the archive member that the symbol is in.  */
+                about the archive member that the symbol is in.  */
              /* So - if it exists, and is referenced somewhere and is
-                undefined or */
+                undefined or */
              if (sp && sp->srefs_chain && !sp->sdefs_chain)
                {
-                 bfd *archive_member_bfd = bfd_get_elt_at_index(entry->the_bfd, idx);
+                 bfd *archive_member_bfd = bfd_get_elt_at_index (entry->the_bfd, idx);
                  struct lang_input_statement_struct *archive_member_lang_input_statement_struct;
 
 #ifdef GNU960
-                 if (archive_member_bfd && gnu960_check_format(archive_member_bfd, bfd_object)) 
+                 if (archive_member_bfd && gnu960_check_format (archive_member_bfd, bfd_object))
 #else
-                 if (archive_member_bfd && bfd_check_format(archive_member_bfd, bfd_object)) 
+                 if (archive_member_bfd && bfd_check_format (archive_member_bfd, bfd_object))
 #endif
                    {
 
                      /* Don't think carefully about any archive member
-                        more than once in a given pass.  */
+                        more than once in a given pass.  */
                      if (prev_archive_member_bfd != archive_member_bfd)
                        {
 
@@ -617,28 +924,30 @@ symdef_library (entry)
 
                          /* Read the symbol table of the archive member.  */
 
-                         if (archive_member_bfd->usrdata != (PTR)NULL) {
+                         if (archive_member_bfd->usrdata != (PTR) NULL)
+                           {
 
-                           archive_member_lang_input_statement_struct =(lang_input_statement_type *) archive_member_bfd->usrdata;
-                         }
-                         else {
+                             archive_member_lang_input_statement_struct = (lang_input_statement_type *) archive_member_bfd->usrdata;
+                           }
+                         else
+                           {
 
-                           archive_member_lang_input_statement_struct =
-                             decode_library_subfile (entry, archive_member_bfd);
-                           archive_member_bfd->usrdata = (PTR) archive_member_lang_input_statement_struct;
+                             archive_member_lang_input_statement_struct =
+                               decode_library_subfile (entry, archive_member_bfd);
+                             archive_member_bfd->usrdata = (PTR) archive_member_lang_input_statement_struct;
 
-                         }
+                           }
 
-         if (archive_member_lang_input_statement_struct == 0) {
-           info ("%F%I contains invalid archive member %s\n",
-                   entry,
-                   sp->name);
-         }
+                         if (archive_member_lang_input_statement_struct == 0)
+                           {
+                             einfo ("%F%I contains invalid archive member %s\n",
+                                    entry, sp->name);
+                           }
 
-                         if (archive_member_lang_input_statement_struct->loaded == false)  
+                         if (archive_member_lang_input_statement_struct->loaded == false)
                            {
 
-                             Q_read_entry_symbols (archive_member_bfd, archive_member_lang_input_statement_struct);
+                             read_entry_symbols (archive_member_bfd, archive_member_lang_input_statement_struct);
                              /* Now scan the symbol table and decide whether to load.  */
 
 
@@ -646,12 +955,12 @@ symdef_library (entry)
 
                                {
                                  /* This member is needed; load it.
-                                    Since we are loading something on this pass,
-                                    we must make another pass through the symdef data.  */
+                                    Since we are loading something on this pass,
+                                    we must make another pass through the symdef data.  */
 
                                  not_finished = true;
 
-                                 Q_enter_file_symbols (archive_member_lang_input_statement_struct);
+                                 enter_file_symbols (archive_member_lang_input_statement_struct);
 
                                  if (prev)
                                    prev->chain = archive_member_lang_input_statement_struct;
@@ -663,8 +972,8 @@ symdef_library (entry)
 
 
                                  /* Clear out this member's symbols from the symdef data
-                                    so that following passes won't waste time on them.  */
-                                 clear_syms(entry, exported_library_name->file_offset);
+                                    so that following passes won't waste time on them.  */
+                                 clear_syms (entry, exported_library_name->file_offset);
                                  archive_member_lang_input_statement_struct->loaded = true;
                                }
                            }
@@ -672,72 +981,99 @@ symdef_library (entry)
                    }
                }
            }
-         idx = bfd_get_next_mapent(entry->the_bfd, idx, &exported_library_name);
+         idx = bfd_get_next_mapent (entry->the_bfd, idx, &exported_library_name);
        }
     }
 }
 
 void
 linear_library (entry)
-struct lang_input_statement_struct *entry;
+     struct lang_input_statement_struct *entry;
 {
   boolean more_to_do = true;
   register struct lang_input_statement_struct *prev = 0;
 
-  while (more_to_do) {
+  if (entry->complained == false)
+    {
+      if (entry->the_bfd->xvec->flavour != bfd_target_ieee_flavour)
+
+       {
+         /* IEEE can use table of contents, so this message is bogus */
+         einfo ("%P: library %s has bad table of contents, rerun ranlib\n",
+                entry->the_bfd->filename);
+       }
+      entry->complained = true;
+
+    }
+  while (more_to_do)
+    {
+
+      bfd *archive = bfd_openr_next_archived_file (entry->the_bfd, 0);
 
-    bfd *  archive = bfd_openr_next_archived_file(entry->the_bfd,0);
+      more_to_do = false;
+      while (archive)
+       {
+         /* Don't check this file if it's already been read in
+            once */
 
-    more_to_do = false;
-    while (archive) {
+         if (!archive->usrdata ||
+             !((lang_input_statement_type *) (archive->usrdata))->loaded)
+           {
 #ifdef GNU960
-      if (gnu960_check_format(archive, bfd_object)) 
+             if (gnu960_check_format (archive, bfd_object))
 #else
-      if (bfd_check_format(archive, bfd_object)) 
+             if (bfd_check_format (archive, bfd_object))
 #endif
-       {
-         register struct lang_input_statement_struct *subentry;
-
-         subentry = decode_library_subfile (entry,
-                                            archive);
-
-         archive->usrdata = (PTR) subentry;
-         if (!subentry) return;
-         if (subentry->loaded == false) {
-           Q_read_entry_symbols (archive, subentry);
-
-           if (subfile_wanted_p (subentry) == true)
-             {
-               Q_enter_file_symbols (subentry);
-
-               if (prev)
-                 prev->chain = subentry;
-               else 
-                 entry->subfiles = subentry;
-               prev = subentry;
-
-               more_to_do = true;
-               subentry->loaded = true;
-             }
-         }
+               {
+                 register struct lang_input_statement_struct *subentry;
+
+                 subentry = decode_library_subfile (entry,
+                                                    archive);
+
+                 archive->usrdata = (PTR) subentry;
+                 if (!subentry)
+                   return;
+                 if (subentry->loaded == false)
+                   {
+                     read_entry_symbols (archive, subentry);
+
+                     if (subfile_wanted_p (subentry) == true)
+                       {
+                         enter_file_symbols (subentry);
+
+                         if (prev)
+                           prev->chain = subentry;
+                         else
+                           entry->subfiles = subentry;
+                         prev = subentry;
+
+                         more_to_do = true;
+                         subentry->loaded = true;
+                       }
+                   }
+               }
+           }
+         archive = bfd_openr_next_archived_file (entry->the_bfd, archive);
+
        }
-      archive = bfd_openr_next_archived_file(entry->the_bfd,archive);
-    }
 
-  }
+    }
 }
 
-  /* ENTRY is an entry for a library member.
-     Its symbols have been read into core, but not entered.
-     Return nonzero if we ought to load this member.  */
+/* ENTRY is an entry for a file inside an archive
+    Its symbols have been read into core, but not entered into the
+    linker ymbol table
+    Return nonzero if we ought to load this file */
 
 boolean
 subfile_wanted_p (entry)
-struct lang_input_statement_struct *entry;
+     struct lang_input_statement_struct *entry;
 {
   asymbol **q;
 
+  if (entry->symbol_count == 0)
+    return false;
+
   for (q = entry->asymbols; *q; q++)
     {
       asymbol *p = *q;
@@ -745,77 +1081,110 @@ struct lang_input_statement_struct *entry;
       /* If the symbol has an interesting definition, we could
         potentially want it.  */
 
-      if (p->flags & BSF_FORT_COMM 
-         || p->flags & BSF_GLOBAL)
+      if (p->flags & BSF_INDIRECT)
        {
-         register ldsym_type *sp = ldsym_get_soft (p->name);
+         /**   add_indirect(q);*/
+       }
 
+      if (bfd_is_com_section (p->section)
+         || (p->flags & BSF_GLOBAL)
+         || (p->flags & BSF_INDIRECT))
+       {
+         register ldsym_type *sp = ldsym_get_soft (p->name);
 
          /* If this symbol has not been hashed,
             we can't be looking for it. */
-         if (sp != (ldsym_type *)NULL 
-             && sp->sdefs_chain == (asymbol **)NULL) {
-           if (sp->srefs_chain  != (asymbol **)NULL
-               || sp->scoms_chain != (asymbol **)NULL)
-             {
-               /* This is a symbol we are looking for.  It is either
-                  not yet defined or common.  */
-
-               if (flag_is_common(p->flags))
-                 {
-                   /* This libary member has something to
-                      say about this element. We should 
-                      remember if its a new size  */
-                   /* Move something from the ref list to the com list */
-                   if(sp->scoms_chain) {
-                     /* Already a common symbol, maybe update it */
-                     if (p->value > (*(sp->scoms_chain))->value) {
-                       (*(sp->scoms_chain))->value = p->value;
-                     }
-                   }
-                   else {
-                     /* Take a value from the ref chain
-                        Here we are moving a symbol from the owning bfd
-                        to another bfd. We must set up the
-                        common_section portion of the bfd thing */
-
-                     
-
-                     sp->scoms_chain = sp->srefs_chain;
-                     sp->srefs_chain =
-                       (asymbol **)((*(sp->srefs_chain))->udata);
-                     (*(sp->scoms_chain))->udata = (PTR)NULL;
-
-                     (*(  sp->scoms_chain))->flags = BSF_FORT_COMM;
-                     /* Remember the size of this item */
-                     sp->scoms_chain[0]->value = p->value;
-                     commons_pending++;
-                     undefined_global_sym_count--;
-                   } {
-                     asymbol *com = *(sp->scoms_chain);
-                     if (((lang_input_statement_type *)
-                          (com->the_bfd->usrdata))->common_section ==
-                         (asection *)NULL) {
-                       ((lang_input_statement_type *)
-                        (com->the_bfd->usrdata))->common_section = 
-                          bfd_make_section(com->the_bfd, "COMMON");
-                     }
+         if (sp != (ldsym_type *) NULL
+             && sp->sdefs_chain == (asymbol **) NULL)
+           {
+             if (sp->srefs_chain != (asymbol **) NULL
+                 || sp->scoms_chain != (asymbol **) NULL)
+               {
+                 /* This is a symbol we are looking for.  It is
+                    either not yet defined or common.  If this is a
+                    common symbol, then if the symbol in the object
+                    file is common, we need to combine sizes.  But if
+                    we already have a common symbol, and the symbol
+                    in the object file is not common, we don't want
+                    the object file: it is providing a definition for
+                    a symbol that we already have a definition for
+                    (this is the else condition below).  */
+                 if (bfd_is_com_section (p->section))
+                   {
+
+                     /* If the symbol in the table is a constructor, we won't to
+                        anything fancy with it */
+                     if ((sp->flags & SYM_CONSTRUCTOR) == 0)
+                       {
+                         /* This libary member has something to
+                            say about this element. We should
+                            remember if its a new size  */
+                         /* Move something from the ref list to the com list */
+                         if (sp->scoms_chain)
+                           {
+                             /* Already a common symbol, maybe update it */
+                             if (p->value > (*(sp->scoms_chain))->value)
+                               {
+                                 (*(sp->scoms_chain))->value = p->value;
+                               }
+                           }
+                         else
+                           {
+                             /* Take a value from the ref chain
+                                Here we are moving a symbol from the owning bfd
+                                to another bfd. We must set up the
+                                common_section portion of the bfd thing */
+
+
+
+                             sp->scoms_chain = sp->srefs_chain;
+                             sp->srefs_chain =
+                               (asymbol **) ((*(sp->srefs_chain))->udata);
+                             (*(sp->scoms_chain))->udata = (PTR) NULL;
+
+                             (*(sp->scoms_chain))->section = p->section;
+                             (*(sp->scoms_chain))->flags = 0;
+                             /* Remember the size of this item */
+                             sp->scoms_chain[0]->value = p->value;
+                             commons_pending++;
+                             undefined_global_sym_count--;
+                           }
+                         {
+                           asymbol *com = *(sp->scoms_chain);
+
+                           if (((lang_input_statement_type *)
+                                (bfd_asymbol_bfd (com)->usrdata))->common_section ==
+                               (asection *) NULL)
+                             {
+                               ((lang_input_statement_type *)
+                                (bfd_asymbol_bfd (com)->usrdata))->common_section =
+                                 bfd_make_section_old_way (bfd_asymbol_bfd (com), "COMMON");
+                             }
+                         }
+                       }
+                     ASSERT (p->udata == 0);
                    }
-                   ASSERT(p->udata == 0);
-                 }
-             
-               else {
-                 if (write_map)
+                 else if (sp->scoms_chain == (asymbol **) NULL)
                    {
-                     info("%I needed due to %s\n",entry, sp->name);
+                     if (write_map)
+                       {
+                         info ("%I needed due to %s\n", entry, sp->name);
+                       }
+                     return true;
                    }
-                 return true;
                }
-             }
-         }
+           }
        }
     }
 
   return false;
 }
 
+void
+add_ysym (text)
+     char *text;
+{
+  ldsym_type *lookup = ldsym_get (text);
+  lookup->flags |= SYM_Y;
+  had_y = 1;
+}
This page took 0.05404 seconds and 4 git commands to generate.