add -warn-common option
authorDavid MacKenzie <djm@cygnus>
Tue, 3 Aug 1993 22:47:28 +0000 (22:47 +0000)
committerDavid MacKenzie <djm@cygnus>
Tue, 3 Aug 1993 22:47:28 +0000 (22:47 +0000)
ld/ChangeLog
ld/ld.1
ld/ld.texinfo
ld/ldlex.l
ld/ldmain.c
ld/ldmisc.c

index 416af4d..1aa0eed 100644 (file)
@@ -1,3 +1,15 @@
+Tue Aug  3 10:57:41 1993  David J. Mackenzie  (djm@thepub.cygnus.com)
+
+       * ldgram.y, ldlex.l, mri.c, ldwrite.c: Change multiple commons
+       into externs.
+
+       * ldmisc.c (multiple_warn): New function.
+       * ldmisc.h: Declare it.
+       * ldmain.c (enter_global_ref): Call it.
+       * ld.h (ld_config_type): Add warn_common.
+       * ldlex.l, ldgram.y: Set it with -warn-common option.
+       * ldver.c (help): Document it.
+
 Mon Aug  2 12:04:36 1993  Ken Raeburn  (raeburn@cambridge.cygnus.com)
 
        * scripttempl/elf.sc: Add hooks for .sdata, .sbss, and
diff --git a/ld/ld.1 b/ld/ld.1
index adc619a..896320c 100644 (file)
--- a/ld/ld.1
+++ b/ld/ld.1
@@ -80,6 +80,7 @@ ld \- the GNU linker
 .RB "[\|" \-r | \-Ur "\|]" 
 .RB "[\|" \-S "\|]" 
 .RB "[\|" \-s "\|]" 
+.RB "[\|" \-sort\-common "\|]" 
 .RB "[\|" "\-T\ "\c
 .I commandfile\c
 \&\|]  
@@ -99,6 +100,7 @@ ld \- the GNU linker
 .RB "[\|" \-V "\|]"
 .RB "[\|" \-v "\|]"
 .RB "[\|" \-\-version "\|]"
+.RB "[\|" \-warn\-common "\|]" 
 .RB "[\|" \-X "\|]" 
 .RB "[\|" \-x "\|]" 
 .ad b
@@ -304,7 +306,7 @@ use will add another pair of name variants to search for when \c
 specifies a library.
 
 .TP
-.BI "-b " "input-format"\c
+.BI "\-b " "input-format"\c
 \&
 Specify the binary format for input object files that follow this option
 on the command line.  You don't usually need to specify this, as
@@ -349,7 +351,7 @@ but has no effect on \c
 \&.
 
 .TP
-.BI "-c " "commandfile"\c
+.BI "\-c " "commandfile"\c
 \&
 Directs \c
 .B ld\c
@@ -448,12 +450,12 @@ but it accepts (and ignores) the \c
 with scripts written to call the old linker.
 
 .TP
-.BI "-format " "input-format"\c
+.BI "\-format " "input\-format"\c
 \&
 Synonym for \c
 .B \-b\c
 \& \c
-.I input-format\c
+.I input\-format\c
 \&.
 
 .TP
@@ -483,7 +485,7 @@ Perform an incremental link (same as option \c
 \&).
 
 .TP
-.BI "-l" "ar"\c
+.BI "\-l" "ar"\c
 \& 
 Add an archive file \c
 .I ar\c
@@ -501,7 +503,7 @@ path-list for occurrences of \c
 specified.
 
 .TP
-.BI "-L" "searchdir"\c
+.BI "\-L" "searchdir"\c
 \& 
 This command adds path \c
 .I searchdir\c
@@ -576,13 +578,13 @@ sets the text segment to be read only, and \c
 if possible.
 
 .TP
-.B \-noinhibit-exec
+.B \-noinhibit\-exec
 Normally, the linker will not produce an output file if it encounters
 errors during the link process.  With this flag, you can specify that
 you wish the output file retained even after non-fatal errors.
 
 .TP
-.BI "-o " "output"\c
+.BI "\-o " "output"\c
 \&
 .I output\c
 \&
@@ -599,7 +601,7 @@ script command \c
 \& can also specify the output file name.
 
 .TP
-.BI "-oformat " "output-format"\c
+.BI "\-oformat " "output\-format"\c
 \&
 Specify the binary format for the output object file.
 You don't usually need to specify this, as
@@ -615,7 +617,7 @@ The script command
 can also specify the output format, but this option overrides it.
 
 .TP
-.BI "-R " "filename"\c
+.BI "\-R " "filename"\c
 \&
 .I file\c
 \&
@@ -674,11 +676,20 @@ Omits debugger symbol information (but not all symbols) from the output file.
 Omits all symbol information from the output file.
 
 .TP
-.BI "-Tbss " "org"\c
+.B \-sort\-common
+Normally, when
+.B ld
+places the global common symbols in the appropriate output sections,
+it sorts them by size.  First come all the one byte symbols, then all
+the two bytes, then all the four bytes, and then everything else.
+This option disables that sorting.
+
+.TP
+.BI "\-Tbss " "org"\c
 .TP
-.BI "-Tdata " "org"\c
+.BI "\-Tdata " "org"\c
 .TP
-.BI "-Ttext " "org"\c
+.BI "\-Ttext " "org"\c
 Use \c
 .I org\c
 \& as the starting address for\(em\&respectively\(em\&the
@@ -694,10 +705,10 @@ Use \c
 \& must be a hexadecimal integer.
 
 .TP
-.BI "-T " "commandfile"\c
+.BI "\-T " "commandfile"\c
 \&
 .TP
-.BI "-T" "commandfile"\c
+.BI "\-T" "commandfile"\c
 Equivalent to \c
 .B \-c \c
 .I commandfile\c
@@ -712,7 +723,7 @@ Prints names of input files as \c
 \& processes them.
 
 .TP
-.BI "-u " "sym"
+.BI "\-u " "sym"
 Forces \c
 .I sym\c
 \& to be entered in the output file as an undefined symbol.
@@ -759,6 +770,13 @@ Display the version number for \c
 and exit.
 
 .TP
+.B \-warn\-common
+Warn when a common symbol is combined with another common symbol or with
+a symbol definition.  Unix linkers allow this somewhat sloppy practice,
+but linkers on some other operating systems do not.  This option allows
+you to find potential problems from combining global symbols.
+
+.TP
 .B \-X 
 If \c
 .B \-s\c
index 0a53346..d2ce592 100644 (file)
@@ -172,10 +172,10 @@ ld [ -o @var{output} ]  @var{objfile}@dots{}
   [ -l@var{archive} ]  [ -L@var{searchdir} ]  [ -M ]  [ -Map @var{mapfile} ]
   [ -m @var{emulation} ]  [ -N | -n ]  [ -noinhibit-exec ]
   [ -oformat @var{output-format} ]  [ -R @var{filename} ]  [ -relax ]
-  [ -r | -Ur ]  [ -S ]  [ -s ]  [ -T @var{commandfile} ]
+  [ -r | -Ur ]  [ -S ]  [ -s ]  [ -sort-common ]  [ -T @var{commandfile} ]
   [ -Ttext @var{textorg} ]  [ -Tdata @var{dataorg} ]
   [ -Tbss @var{bssorg} ]  [ -t ]  [ -u @var{symbol}]  [-V]  [-v]  [ --version ]
-  [ -y@var{symbol} ]  [ -X ]  [-x ]
+  [ -warn-common ]  [ -y@var{symbol} ]  [ -X ]  [-x ]
 @end smallexample
 
 This plethora of command-line options may seem intimidating, but in
@@ -508,6 +508,12 @@ Omit debugger symbol information (but not all symbols) from the output file.
 @cindex strip all symbols
 Omit all symbol information from the output file.
 
+@item -sort-common
+Normally, when @code{ld} places the global common symbols in the
+appropriate output sections, it sorts them by size.  First come all the
+one byte symbols, then all the two bytes, then all the four bytes, and
+then everything else.  This option disables that sorting.
+
 @item -Tbss @var{bssorg}
 @kindex -Tbss @var{bssorg}
 @itemx -Tdata @var{dataorg}
@@ -575,6 +581,81 @@ Display the version number for @code{ld}.
 @kindex --version
 Display the version number for @code{ld} and exit.
 
+@item -warn-common
+Warn when a common symbol is combined with another common symbol or with
+a symbol definition.  Unix linkers allow this somewhat sloppy practice,
+but linkers on some other operating systems do not.  This option allows
+you to find potential problems from combining global symbols.
+
+There are three kinds of global symbols, illustrated here by C examples:
+
+@table @samp
+@item int i = 1;
+A definition, which goes in the initialized data section of the output
+file.
+
+@item extern int i;
+An undefined reference, which does not allocate space.
+There must be either a definition or a common symbol for the
+variable somewhere.
+
+@item int i;
+A common symbol.  If there are only (one or more) common symbols for a
+variable, it goes in the uninitialized data area of the output file.
+The linker merges multiple common symbols for the same variable into a
+single symbol.  If they are of different sizes, it picks the largest
+size.  The linker turns a common symbol into a declaration, if there is
+a definition of the same variable.
+@end table
+
+The @samp{-warn-common} option can produce five kinds of warnings.  Each
+warning consists of a pair of lines: the first describes the symbol just
+encountered, and the second describes the previous symbol encountered
+with the same name.  One or both of the two symbols will be a common
+symbol.
+
+@enumerate
+@item
+Turning a common symbol into a reference, because there is already a
+definition for the symbol.
+@smallexample
+@var{file}(@var{section}): warning: common of `@var{symbol}' overridden by definition
+@var{file}(@var{section}): warning: defined here
+@end smallexample
+
+@item
+Turning a common symbol into a reference, because a later definition for
+the symbol is encountered.  This is the same as the previous case,
+except that the symbols are encountered in a different order.
+@smallexample
+@var{file}(@var{section}): warning: definition of `@var{symbol}' overriding common
+@var{file}(@var{section}): warning: common is here
+@end smallexample
+
+@item
+Merging a common symbol with a previous same-sized common symbol.
+@smallexample
+@var{file}(@var{section}): warning: multiple common of `@var{symbol}'
+@var{file}(@var{section}): warning: previous common is here
+@end smallexample
+
+@item
+Merging a common symbol with a previous larger common symbol.
+@smallexample
+@var{file}(@var{section}): warning: common of `@var{symbol}' overridden by larger common
+@var{file}(@var{section}): warning: larger common is here
+@end smallexample
+
+@item
+Merging a common symbol with a previous smaller common symbol.  This is
+the same as the previous case, except that the symbols are
+encountered in a different order.
+@smallexample
+@var{file}(@var{section}): warning: common of `@var{symbol}' overriding smaller common
+@var{file}(@var{section}): warning: smaller common is here
+@end smallexample
+@end enumerate
+
 @item -X 
 @kindex -X
 @cindex local symbols, deleting
index 74ecf34..ef1275b 100644 (file)
@@ -29,8 +29,8 @@ This was written by steve chamberlain
 #include "ldgram.h"
 
 int ldgram_in_defsym;
-int ldgram_had_equals;
-int ldgram_in_script;
+extern int ldgram_had_equals;
+extern int ldgram_in_script;
 
 int hex_mode;
 extern int fgetc();
@@ -107,6 +107,7 @@ NOCFILENAMECHAR     [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~]
 <COMMAND>"-oformat"            { return OPTION_oformat; }
 <COMMAND>"-sort-common"                { return OPTION_sort_common;}
 <COMMAND>"-sort_common"                { return OPTION_sort_common;}
+<COMMAND>"-warn-common"                { return OPTION_warn_common;}
 <COMMAND>"-n"                  { return OPTION_n; }
 <COMMAND>"-N"                  { return OPTION_N; }
 <COMMAND>"-r"                  { return OPTION_r; }
@@ -143,8 +144,9 @@ NOCFILENAMECHAR     [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~]
 
 <COMMAND>"-L"{FILENAME}        { 
                                        yylval.name = buystring(yytext+2);
-                                       return OPTION_L
+                                       return OPTION_Lfile;
                                }
+<COMMAND>"-L"                  { return OPTION_L; }
 <COMMAND>"-Ttext"              {
                                 yylval.name = ".text";
                                 return OPTION_Texp;
@@ -202,6 +204,15 @@ NOCFILENAMECHAR    [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~]
                                        yylval.integer = atoi (yytext + 2);
                                        return OPTION_Gval;
                                }
+
+<COMMAND>"-Qy"                 {       return OPTION_Qy; }
+<COMMAND>"-dn"                 {       return OPTION_dn; }
+<COMMAND>"-Y"                  {       return OPTION_Y;  }
+<COMMAND>"-YP,"{FILENAME}      {
+                                       yylval.name = buystring (yytext+4);
+                                       return OPTION_YP;
+                               }
+
 <MRI,EXPRESSION>"$"([0-9A-Fa-f])+ {
                                yylval.integer = strtoul(yytext+1, 0,16);
                                return INT;
index 39fc2df..5b00ad4 100644 (file)
@@ -170,14 +170,20 @@ main (argc, argv)
   if (had_script == false)
     {
       /* Read the emulation's appropriate default script.  */
-      char *scriptname = ldemul_get_script ();
-      /* sizeof counts the terminating NUL.  */
-      size_t size = strlen (scriptname) + sizeof ("-T /ldscripts/");
-      char *buf = (char *) ldmalloc(size);
-      /* The initial slash prevents finding the script in `.' first.  */
-      sprintf (buf, "-T /ldscripts/%s", scriptname);
-      parse_line (buf, 0);
-      free (buf);
+      int isfile;
+      char *s = ldemul_get_script (&isfile);
+
+      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);
     }
 
   if (config.relocateable_output && command_line.relax)
@@ -490,23 +496,26 @@ enter_global_ref (nlist_p, name)
          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. */
+            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  */
+                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)
@@ -515,11 +524,29 @@ enter_global_ref (nlist_p, name)
              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;
                }
@@ -527,10 +554,9 @@ enter_global_ref (nlist_p, name)
          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 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 */
@@ -547,27 +573,17 @@ enter_global_ref (nlist_p, name)
                }
            }
        }
-
       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 */
-             asymbol *sy = *(sp->sdefs_chain);
-             lang_input_statement_type *stat =
-             (lang_input_statement_type *) bfd_asymbol_bfd (sy)->usrdata;
-             lang_input_statement_type *stat1 =
-             (lang_input_statement_type *) bfd_asymbol_bfd (sym)->usrdata;
-             asymbol **stat1_symbols = stat1 ? stat1->asymbols : 0;
-             asymbol **stat_symbols = stat ? stat->asymbols : 0;
-
+             multiple_warn("%X%C: multiple definition of `%s'\n",
+                           sym,
+                           "%X%C: first defined here\n",
+                           *(sp->sdefs_chain));
              multiple_def_count++;
-             einfo ("%X%C: multiple definition of `%T'\n",
-                    bfd_asymbol_bfd (sym), sym->section, stat1_symbols, sym->value, sym);
-
-             einfo ("%X%C: first seen here\n",
-               bfd_asymbol_bfd (sy), sy->section, stat_symbols, sy->value);
            }
          else
            {
@@ -577,6 +593,11 @@ enter_global_ref (nlist_p, name)
          /* 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--;
@@ -595,7 +616,6 @@ enter_global_ref (nlist_p, name)
            {
              /* And it's the first time we've seen it */
              undefined_global_sym_count++;
-
            }
 
          refize (sp, nlist_p);
index 8af24d9..60df285 100644 (file)
@@ -87,6 +87,7 @@ vfinfo(fp, fmt, arg)
      va_list arg;
 {
   boolean fatal = false;
+
   while (*fmt) 
   {
     while (*fmt != '%' && *fmt != '\0') 
@@ -94,6 +95,7 @@ vfinfo(fp, fmt, arg)
       putc(*fmt, fp);
       fmt++;
     }
+
     if (*fmt == '%') 
     {
       fmt ++;
@@ -102,12 +104,14 @@ vfinfo(fp, fmt, arg)
        case 'X':
        config.make_executable = false;
        break;
+
        case 'V':
-       {
-        bfd_vma value = va_arg(arg, bfd_vma);
-        fprintf_vma(fp, value);
-       }
+       {
+         bfd_vma value = va_arg(arg, bfd_vma);
+         fprintf_vma(fp, value);
+       }
        break;
+
       case 'v':
        {
          char buf[100];
@@ -121,13 +125,12 @@ vfinfo(fp, fmt, arg)
          fputs (p, fp);
        }
        break;
+
        case 'T':
        {
         asymbol *symbol = va_arg(arg, asymbol *);
         if (symbol) 
         {
-
-           
           asection *section = symbol->section;
           char *cplusname =   demangle(symbol->name, 1);
           CONST char *section_name =  section->name;
@@ -146,6 +149,7 @@ vfinfo(fp, fmt, arg)
         }
        }
        break;
+
        case 'B':
        { 
         bfd *abfd = va_arg(arg, bfd *);
@@ -155,24 +159,23 @@ vfinfo(fp, fmt, arg)
         }
         else {
           fprintf(fp,"%s", abfd->filename);
-
         }
        }
        break;
+
        case 'F':
        fatal = true;
        break;
+
        case 'P':
        fprintf(fp,"%s", program_name);
        break;
+
        case 'E':
        /* Replace with the most recent errno explanation */
-
-
        fprintf(fp, bfd_errmsg(bfd_error));
-
-
        break;
+
        case 'I':
        {
         lang_input_statement_type *i =
@@ -181,12 +184,10 @@ vfinfo(fp, fmt, arg)
         fprintf(fp,"%s", i->local_sym_name);
        }
        break;
+
        case 'S':
        /* Print source script file and line number */
-
        {
-       
-        
         extern unsigned int lineno;
         if (ldfile_input_filename == (char *)NULL) {
           fprintf(fp,"command line");
@@ -195,7 +196,6 @@ vfinfo(fp, fmt, arg)
           fprintf(fp,"%s:%u", ldfile_input_filename, lineno );
         }
        }
-       
        break;
 
        case 'R':
@@ -210,9 +210,6 @@ vfinfo(fp, fmt, arg)
        }
        break;
        
-
-
-       
        case 'C':
        {
         CONST char *filename;
@@ -237,8 +234,7 @@ vfinfo(fp, fmt, arg)
            filename = abfd->filename;
           if (functionname != (char *)NULL) 
           {
-            /* There is no initial '_' to remove here. */
-            cplus_name = demangle(functionname, 0);
+            cplus_name = demangle(functionname, 1);
             fprintf(fp,"%s:%u: (%s)", filename, linenumber, cplus_name);
           }
                
@@ -256,15 +252,18 @@ vfinfo(fp, fmt, arg)
        case 's':
        fprintf(fp,"%s", va_arg(arg, char *));
        break;
+
        case 'd':
        fprintf(fp,"%d", va_arg(arg, int));
        break;
+
        default:
        fprintf(fp,"%s", va_arg(arg, char *));
        break;
       }
     }
   }
+
   if (fatal == true) 
   {
     extern char *output_filename;
@@ -308,10 +307,39 @@ va_dcl
   va_end(arg);
 }
 
+/* Warn about a symbol NEWSYM being multiply defined with another symbol OLDSYM.
+   MESSAGE1 and MESSAGE2 should look something like:
+   "%C: warning: multiple commons of `%s'\n"
+   "%C: warning: previous common here\n"  */
+
+void
+multiple_warn (message1, newsym, message2, oldsym)
+     char *message1;
+     asymbol *newsym;
+     char *message2;
+     asymbol *oldsym;
+{
+  lang_input_statement_type *stat;
+  asymbol **stat_symbols;
+
+  stat = (lang_input_statement_type *) bfd_asymbol_bfd (newsym)->usrdata;
+  stat_symbols = stat ? stat->asymbols : 0;
+
+  einfo (message1,
+        bfd_asymbol_bfd (newsym), newsym->section, stat_symbols, newsym->value,
+        demangle (newsym->name, 1));
+
+  stat = (lang_input_statement_type *) bfd_asymbol_bfd (oldsym)->usrdata;
+  stat_symbols = stat ? stat->asymbols : 0;
+
+  einfo (message2,
+        bfd_asymbol_bfd (oldsym), oldsym->section, stat_symbols, oldsym->value);
+}
+
 void 
 info_assert(file, line)
-char *file;
-unsigned int line;
+     char *file;
+     unsigned int line;
 {
   einfo("%F%P internal error %s %d\n", file,line);
 }