Fix for PR 19070 - add ability to detect and generate errors when sections
authorNick Clifton <nickc@redhat.com>
Thu, 11 Feb 1999 16:14:01 +0000 (16:14 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 11 Feb 1999 16:14:01 +0000 (16:14 +0000)
overlap.

ld/ChangeLog
ld/ldlang.c
ld/ldmain.c
ld/lexsup.c
ld/testsuite/.Sanitize
ld/testsuite/ChangeLog
ld/testsuite/ld-checks/.Sanitize [new file with mode: 0644]
ld/testsuite/ld-checks/asm.s [new file with mode: 0644]
ld/testsuite/ld-checks/checks.exp [new file with mode: 0644]
ld/testsuite/ld-checks/script [new file with mode: 0644]

index a73693c..8a72f81 100644 (file)
@@ -1,3 +1,20 @@
+1999-02-11  Nick Clifton  <nickc@cygnus.com>
+
+       * ldlang.c (lang_check_section_addresses): New function: Check
+       addresses assigned to section for overlaps.
+       (lang_process): Call lang_check_section_addresses if suitable.
+
+       * ld.h: Add new boolean field to args_type structure:
+       'check_section_addresses'.
+
+       * ldmain.c: Initialise check_section_addresses field to true.
+
+       * lexsup.c: Add new command line options '--no-check-sections' and
+       '--check-sections'.
+
+       * ld.texinfo: Document new command line options '--check-sections'
+       and '--no-check-sections'.
+
 1999-02-08  Nick Clifton  <nickc@cygnus.com>
 
        * configure.tgt: Add support for StrongARM target.
index 12d20cb..1ddc63b 100644 (file)
@@ -1,5 +1,5 @@
 /* Linker command language support.
-   Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 1998
+   Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 1999
    Free Software Foundation, Inc.
 
 This file is part of GLD, the Gnu Linker.
@@ -152,6 +152,7 @@ static void lang_gc_wild
 static void lang_gc_sections_1 PARAMS ((lang_statement_union_type *));
 static void lang_gc_sections PARAMS ((void));
 static void lang_do_version_exports_section PARAMS ((void));
+static void lang_check_section_addresses PARAMS ((void));
                                        
 
 /* EXPORTS */
@@ -2272,6 +2273,61 @@ size_input_section (this_ptr, output_section_statement, fill, dot, relax)
   return dot;
 }
 
+/* Check to see if any allocated sections overlap with other allocated
+   sections.  This can happen when the linker script specifically specifies
+   the output section addresses of the two sections.  */
+static void
+lang_check_section_addresses ()
+{
+  asection * s;
+
+  /* Scan all sections in the output list.  */
+  for (s = output_bfd->sections; s != NULL; s = s->next)
+    /* Ignore sections which are not loaded or which have no contents.  */
+    if ((bfd_get_section_flags (output_bfd, s) & (SEC_ALLOC | SEC_LOAD))
+       && bfd_section_size (output_bfd, s) != 0)
+      {
+       asection * os;
+
+       /* Once we reach section 's' stop our seach.  This prevents two
+          warning messages from being produced, one for 'section A overlaps
+          section B' and one for 'section B overlaps section A'.  */
+       for (os = output_bfd->sections; os != s; os = os->next)
+         {
+           bfd_vma s_start;
+           bfd_vma s_end;
+           bfd_vma os_start;
+           bfd_vma os_end;
+
+           /* Only consider loadable sections with real contents.  */
+           if (((bfd_get_section_flags (output_bfd, os)
+                 & (SEC_ALLOC | SEC_LOAD)) == 0)
+               || bfd_section_size (output_bfd, os) == 0)
+             continue;
+
+           /* We must check the sections' LMA addresses not their
+              VMA addresses because overlay sections can have
+              overlapping VMAs but they must have distinct LMAs.  */
+           s_start  = bfd_section_lma (output_bfd, s);
+           os_start = bfd_section_lma (output_bfd, os);
+           s_end    = s_start  + bfd_section_size (output_bfd, s) - 1;
+           os_end   = os_start + bfd_section_size (output_bfd, os) - 1;
+
+           /* Look for an overlap.  */
+           if ((s_end < os_start) || (s_start > os_end))
+             continue;
+           
+           einfo (_(\
+"%X%P: section %s [%V -> %V] overlaps section %s [%V -> %V]\n"),
+                  s->name, s_start, s_end, os->name, os_start, os_end);
+
+           /* Once we have found one overlap for this section,
+              stop looking for others.  */
+           break;
+         }
+      }
+}
+
 /* This variable indicates whether bfd_relax_section should be called
    again.  */
 
@@ -2421,7 +2477,8 @@ lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
               since unallocated sections do not contribute to the region's
               overall size in memory.  */
            if (os->region != (lang_memory_region_type *) NULL
-               && bfd_get_section_flags (output_bfd, os->bfd_section) & SEC_ALLOC)
+               && (bfd_get_section_flags (output_bfd, os->bfd_section)
+               & (SEC_ALLOC | SEC_LOAD)))
              {
                os->region->current = dot;
                
@@ -3713,6 +3770,11 @@ lang_process ()
                       abs_output_section,
                       (fill_type) 0, (bfd_vma) 0);
 
+  /* Make sure that the section addresses make sense.  */
+  if (! link_info.relocateable
+      && command_line.check_section_addresses)
+    lang_check_section_addresses ();
+  
   /* Final stuffs */
 
   ldemul_finish ();
index 96f3279..b392563 100644 (file)
@@ -199,6 +199,7 @@ main (argc, argv)
   command_line.interpreter = NULL;
   command_line.rpath = NULL;
   command_line.warn_mismatch = true;
+  command_line.check_section_addresses = true;
 
   link_info.callbacks = &link_callbacks;
   link_info.relocateable = false;
@@ -246,9 +247,6 @@ main (argc, argv)
        einfo (_("%P%F: -r and -shared may not be used together\n"));
     }
 
-  if (command_line.gc_sections && config.dynamic_link)
-    einfo("%P%F: --gc-sections may only be performed for static links\n");
-
   /* Treat ld -r -s as ld -r -S -x (i.e., strip all local symbols).  I
      don't see how else this can be handled, since in this case we
      must preserve all externally visible symbols.  */
index 3a03f20..98b77e5 100644 (file)
@@ -101,7 +101,8 @@ int parsing_defsym = 0;
 #define OPTION_VERBOSE                 (OPTION_UR + 1)
 #define OPTION_VERSION                 (OPTION_VERBOSE + 1)
 #define OPTION_VERSION_SCRIPT          (OPTION_VERSION + 1)
-#define OPTION_WARN_COMMON             (OPTION_VERSION_SCRIPT + 1)
+#define OPTION_VERSION_EXPORTS_SECTION (OPTION_VERSION_SCRIPT + 1)
+#define OPTION_WARN_COMMON             (OPTION_VERSION_EXPORTS_SECTION + 1)
 #define OPTION_WARN_CONSTRUCTORS       (OPTION_WARN_COMMON + 1)
 #define OPTION_WARN_MULTIPLE_GP                (OPTION_WARN_CONSTRUCTORS + 1)
 #define OPTION_WARN_ONCE               (OPTION_WARN_MULTIPLE_GP + 1)
@@ -113,6 +114,8 @@ int parsing_defsym = 0;
 #define OPTION_FORCE_EXE_SUFFIX                (OPTION_WRAP + 1)
 #define OPTION_GC_SECTIONS             (OPTION_FORCE_EXE_SUFFIX + 1)
 #define OPTION_NO_GC_SECTIONS          (OPTION_GC_SECTIONS + 1)
+#define OPTION_CHECK_SECTIONS          (OPTION_NO_GC_SECTIONS + 1)
+#define OPTION_NO_CHECK_SECTIONS       (OPTION_CHECK_SECTIONS + 1)
 
 /* The long options.  This structure is used for both the option
    parsing and the help text.  */
@@ -158,6 +161,10 @@ static const struct ld_option ld_options[] =
       'e', N_("ADDRESS"), N_("Set start address"), TWO_DASHES },
   { {"export-dynamic", no_argument, NULL, OPTION_EXPORT_DYNAMIC},
       'E', NULL, N_("Export all dynamic symbols"), TWO_DASHES },
+  { {"EB", no_argument, NULL, OPTION_EB},
+      '\0', NULL, N_("Link big-endian objects"), ONE_DASH },
+  { {"EL", no_argument, NULL, OPTION_EL},
+      '\0', NULL, N_("Link little-endian objects"), ONE_DASH },
   { {"auxiliary", required_argument, NULL, 'f'},
       'f', N_("SHLIB"), N_("Auxiliary filter for shared object symbol table"),
       TWO_DASHES },
@@ -165,12 +172,6 @@ static const struct ld_option ld_options[] =
       'F', N_("SHLIB"), N_("Filter for shared object symbol table"), TWO_DASHES },
   { {NULL, no_argument, NULL, '\0'},
       'g', NULL, N_("Ignored"), ONE_DASH },
-  { {"gc-sections", no_argument, NULL, OPTION_GC_SECTIONS},
-      '\0', NULL, N_("Remove unused sections on certain targets"),
-      TWO_DASHES },
-  { {"no-gc-sections", no_argument, NULL, OPTION_NO_GC_SECTIONS},
-      '\0', NULL, N_("(Don't) Remove unused sections on certain targets"),
-      TWO_DASHES },
   { {"gpsize", required_argument, NULL, 'G'},
       'G', N_("SIZE"), N_("Small data size (if no size, same as --shared)"),
       TWO_DASHES },
@@ -192,7 +193,9 @@ static const struct ld_option ld_options[] =
   { {"output", required_argument, NULL, 'o'},
       'o', N_("FILE"), N_("Set output file name"), TWO_DASHES },
   { {NULL, required_argument, NULL, '\0'},
-      'O', NULL, N_("Ignored"), ONE_DASH },
+      'O', NULL, N_("Optimize output file"), ONE_DASH },
+  { {"Qy", no_argument, NULL, OPTION_IGNORE},
+      '\0', NULL, N_("Ignored for SVR4 compatibility"), ONE_DASH },
   { {"relocateable", no_argument, NULL, 'r'},
       'r', NULL, N_("Generate relocateable output"), TWO_DASHES },
   { {NULL, no_argument, NULL, '\0'},
@@ -210,6 +213,8 @@ static const struct ld_option ld_options[] =
       'T', N_("FILE"), N_("Read linker script"), TWO_DASHES },
   { {"undefined", required_argument, NULL, 'u'},
       'u', N_("SYMBOL"), N_("Start with undefined reference to SYMBOL"), TWO_DASHES },
+  { {"Ur", no_argument, NULL, OPTION_UR},
+      '\0', NULL, N_("Build global constructor/destructor tables"), ONE_DASH },
   { {"version", no_argument, NULL, OPTION_VERSION},
       'v', NULL, N_("Print version information"), TWO_DASHES },
   { {NULL, no_argument, NULL, '\0'},
@@ -246,20 +251,27 @@ static const struct ld_option ld_options[] =
       '\0', NULL, NULL, ONE_DASH },
   { {"Bsymbolic", no_argument, NULL, OPTION_SYMBOLIC},
       '\0', NULL, N_("Bind global references locally"), ONE_DASH },
+  { {"check-sections", no_argument, NULL, OPTION_CHECK_SECTIONS},
+      '\0', NULL, N_("Check section addresses for overlaps (default)"), TWO_DASHES },
+  { {"no-check-sections", no_argument, NULL, OPTION_NO_CHECK_SECTIONS},
+      '\0', NULL, N_("Do not check section addresses for overlaps"),
+      TWO_DASHES },
   { {"cref", no_argument, NULL, OPTION_CREF},
       '\0', NULL, N_("Output cross reference table"), TWO_DASHES },
   { {"defsym", required_argument, NULL, OPTION_DEFSYM},
       '\0', N_("SYMBOL=EXPRESSION"), N_("Define a symbol"), TWO_DASHES },
   { {"dynamic-linker", required_argument, NULL, OPTION_DYNAMIC_LINKER},
       '\0', N_("PROGRAM"), N_("Set the dynamic linker to use"), TWO_DASHES },
-  { {"EB", no_argument, NULL, OPTION_EB},
-      '\0', NULL, N_("Link big-endian objects"), ONE_DASH },
-  { {"EL", no_argument, NULL, OPTION_EL},
-      '\0', NULL, N_("Link little-endian objects"), ONE_DASH },
   { {"embedded-relocs", no_argument, NULL, OPTION_EMBEDDED_RELOCS},
       '\0', NULL, N_("Generate embedded relocs"), TWO_DASHES},
   { {"force-exe-suffix", no_argument, NULL, OPTION_FORCE_EXE_SUFFIX},
       '\0', NULL, N_("Force generation of file with .exe suffix"), TWO_DASHES},
+  { {"gc-sections", no_argument, NULL, OPTION_GC_SECTIONS},
+      '\0', NULL, N_("Remove unused sections (on some targets)"),
+      TWO_DASHES },
+  { {"no-gc-sections", no_argument, NULL, OPTION_NO_GC_SECTIONS},
+      '\0', NULL, N_("Don't remove unused sections (default)"),
+      TWO_DASHES },
   { {"help", no_argument, NULL, OPTION_HELP},
       '\0', NULL, N_("Print option help"), TWO_DASHES },
   { {"Map", required_argument, NULL, OPTION_MAP},
@@ -278,8 +290,6 @@ static const struct ld_option ld_options[] =
       '\0', N_("TARGET"), N_("Specify target of output file"), TWO_DASHES },
   { {"qmagic", no_argument, NULL, OPTION_IGNORE},
       '\0', NULL, N_("Ignored for Linux compatibility"), ONE_DASH },
-  { {"Qy", no_argument, NULL, OPTION_IGNORE},
-      '\0', NULL, N_("Ignored for SVR4 compatibility"), ONE_DASH },
   { {"relax", no_argument, NULL, OPTION_RELAX},
       '\0', NULL, N_("Relax branches on certain targets"), TWO_DASHES },
   { {"retain-symbols-file", required_argument, NULL,
@@ -313,14 +323,16 @@ static const struct ld_option ld_options[] =
       '\0', N_("ADDRESS"), N_("Set address of .data section"), ONE_DASH },
   { {"Ttext", required_argument, NULL, OPTION_TTEXT},
       '\0', N_("ADDRESS"), N_("Set address of .text section"), ONE_DASH },
-  { {"Ur", no_argument, NULL, OPTION_UR},
-      '\0', NULL, N_("Build global constructor/destructor tables"), ONE_DASH },
   { {"verbose", no_argument, NULL, OPTION_VERBOSE},
       '\0', NULL, N_("Output lots of information during link"), TWO_DASHES },
   { {"dll-verbose", no_argument, NULL, OPTION_VERBOSE}, /* Linux.  */
       '\0', NULL, NULL, NO_HELP },
   { {"version-script", required_argument, NULL, OPTION_VERSION_SCRIPT },
       '\0', N_("FILE"), N_("Read version information script"), TWO_DASHES },
+  { {"version-exports-section", required_argument, NULL,
+     OPTION_VERSION_EXPORTS_SECTION },
+    '\0', N_("SYMBOL"), N_("Take export symbols list from .exports, using SYMBOL as the version."),
+    TWO_DASHES },
   { {"warn-common", no_argument, NULL, OPTION_WARN_COMMON},
       '\0', NULL, N_("Warn about duplicate common symbols"), TWO_DASHES },
   { {"warn-constructors", no_argument, NULL, OPTION_WARN_CONSTRUCTORS},
@@ -636,6 +648,9 @@ parse_args (argc, argv)
             something, or can we create a new option to do that
             (with a syntax similar to -defsym)?
             getopt can't handle two args to an option without kludges.  */
+
+         /* Enable optimizations of output files.  */
+         link_info.optimize = strtoul (optarg, NULL, 0) ? true : false;
          break;
        case 'o':
          lang_add_output (optarg, 0); 
@@ -677,14 +692,36 @@ parse_args (argc, argv)
            command_line.rpath = buystring (optarg);
          else
            {
+             size_t rpath_len = strlen (command_line.rpath);
+             size_t optarg_len = strlen (optarg);
              char *buf;
+             char *cp = command_line.rpath;
 
-             buf = xmalloc (strlen (command_line.rpath)
-                            + strlen (optarg)
-                            + 2);
-             sprintf (buf, "%s:%s", command_line.rpath, optarg);
-             free (command_line.rpath);
-             command_line.rpath = buf;
+             /* First see whether OPTARG is already in the path.  */
+             do
+               {
+                 size_t idx = 0;
+                 while (optarg[idx] != '\0' && optarg[idx] == cp[idx])
+                   ++idx;
+                 if (optarg[idx] == '\0'
+                     && (cp[idx] == '\0' || cp[idx] == ':'))
+                   /* We found it.  */
+                   break;
+
+                 /* Not yet found.  */
+                 cp = strchr (cp, ':');
+                 if (cp != NULL)
+                   ++cp;
+               }
+             while (cp != NULL);
+
+             if (cp == NULL)
+               {
+                 buf = xmalloc (rpath_len + optarg_len + 2);
+                 sprintf (buf, "%s:%s", command_line.rpath, optarg);
+                 free (command_line.rpath);
+                 command_line.rpath = buf;
+               }
            }
          break;
        case OPTION_RPATH_LINK:
@@ -812,6 +849,12 @@ the GNU General Public License.  This program has absolutely no warranty.\n"));
            yyparse ();
          }
          break;
+       case OPTION_VERSION_EXPORTS_SECTION:
+         /* This option records a version symbol to be applied to the
+            symbols listed for export to be found in the object files
+            .exports sections.  */
+         command_line.version_exports_section = optarg;
+         break;
        case OPTION_WARN_COMMON:
          config.warn_common = true;
          break;
@@ -858,6 +901,12 @@ the GNU General Public License.  This program has absolutely no warranty.\n"));
        case OPTION_SPLIT_BY_FILE:
          config.split_by_file = true;
          break; 
+       case OPTION_CHECK_SECTIONS:
+         command_line.check_section_addresses = true;
+         break;
+       case OPTION_NO_CHECK_SECTIONS:
+         command_line.check_section_addresses = false;
+         break;
        case '(':
          if (ingroup)
            {
index 93f85c1..a0c5713 100644 (file)
@@ -37,6 +37,7 @@ ld-shared
 ld-srec
 ld-undefined
 ld-versados
+ld-checks
 
 Things-to-lose:
 
index fb9a0f3..76de4b5 100644 (file)
@@ -1,3 +1,23 @@
+1999-02-11  Nick Clifton  <nickc@cygnus.com>
+
+       * ld-checks: New directory:  Tests for the linker's
+       --check-sections option.
+       * ld-checks/checks.exp: New file.
+       * ld-checks/script: Bogus linker script.
+       * ld-checks/asm.s: Simple test assembler file.
+
+Tue Feb  2 19:15:02 1999  Catherine Moore  <clm@cygnus.com>
+
+        * ld-selective/selective.exp:  Disable test for unsupported
+        targets.  Change tests to check for absence of symbols instead
+        of address zero.
+
+Mon Jan 18 03:44:52 1999  Ian Lance Taylor  <ian@cygnus.com>
+
+       * config/default.exp (get_link_files): Quote target_triplet and CC
+       when invoking shell.
+       (get_target_emul): Likewise.
+
 1999-01-03  Ken Raeburn  <raeburn@cygnus.com>
 
        * config/default.exp (get_link_files, get_target_emul): New procs;
diff --git a/ld/testsuite/ld-checks/.Sanitize b/ld/testsuite/ld-checks/.Sanitize
new file mode 100644 (file)
index 0000000..f644200
--- /dev/null
@@ -0,0 +1,45 @@
+# .Sanitize for ld dejagnu testsuites
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order..
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this directory.
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Do-last:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+asm.s
+script
+checks.exp
+
+Things-to-lose:
+
+# The lines between the "Do-last:" line and the end of the file
+# are executed as a /bin/sh shell script after everything else is
+# done.
+
+Do-last:
+
+
+for i in * ; do
+       if test ! -d $i && (grep sanitize $i > /dev/null) ; then
+               echo '***' Some mentions of Sanitize are still left in $i! 1>&2
+       fi
+done
+
+#eof
diff --git a/ld/testsuite/ld-checks/asm.s b/ld/testsuite/ld-checks/asm.s
new file mode 100644 (file)
index 0000000..51c5197
--- /dev/null
@@ -0,0 +1,21 @@
+       .section .foo,"ax",@progbits
+       .global foo
+foo:
+       .word 0x12345678
+
+       .section .bar,"ax",@progbits
+       .global bar
+bar:
+       .word 0x87654321
+
+       .section .overlay1,"ax",@progbits;
+       .global jim
+jim:
+       .word 0xdeadbeef
+
+       .section .overlay2,"ax",@progbits
+       .global harry
+harry:
+       .word 0x99119911
+
+       
\ No newline at end of file
diff --git a/ld/testsuite/ld-checks/checks.exp b/ld/testsuite/ld-checks/checks.exp
new file mode 100644 (file)
index 0000000..840853b
--- /dev/null
@@ -0,0 +1,72 @@
+# Expect script for LD section checks tests
+#   Copyright (C) 1999 Free Software Foundation
+#
+# This file 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.
+#
+# Written by Nick Clifton (nickc@cygnus.com)
+
+proc section_check {} {
+    global ld_flags
+    global as
+    global ld
+    global srcdir
+    global subdir
+    
+    set test "check sections"
+    
+    set ldflags "--check-sections"
+
+    if { ![ld_assemble $as $srcdir/$subdir/asm.s tmpdir/asm.o]} {
+       unresolved $test
+       return
+    }
+
+    if ![ld_simple_link $ld tmpdir/asm.x "$ldflags tmpdir/asm.o"] {
+       fail "$test : using default linker script"
+    } else {
+       pass $test
+    }
+
+    # Change the linker flags so that our "buggy" linker
+    # script is used.
+    set ldflags "--check-sections -T $srcdir/$subdir/script -e foo"
+
+    # Perform the equivalent of invoking ld_simple_link
+    # except that we need to massage the output futher.
+    
+    catch "exec $ld -o tmpdir/asm.x $ldflags tmpdir/asm.o" exec_output
+    set exec_output [prune_warnings $exec_output]
+
+    # Make sure that we got some output from the linker
+    if [string match "" $exec_output] then {
+       fail "$test - error message expected but not found"
+    } 
+
+    # Now remove our expected error message
+    regsub -all ".*: section .bar .* overlaps section .foo .*" $exec_output "" exec_output
+
+    # And check to see if anything else, (unexpected) was left
+    if [string match "" $exec_output] then {
+       pass $test
+    } else {
+       verbose -log "Unexpected linker message(s): $exec_output"
+       
+       fail "$test - using erroneous linker script"
+    }
+}
+
+section_check
+
+
diff --git a/ld/testsuite/ld-checks/script b/ld/testsuite/ld-checks/script
new file mode 100644 (file)
index 0000000..db6c039
--- /dev/null
@@ -0,0 +1,8 @@
+SECTIONS {
+        .foo 0x100 : { *(.foo) }
+       .bar 0x100 : AT (0x100) { *(.bar) }
+
+       .overlay1 0x100 : AT (0x4000) { *(.overlay1) }
+       .overlay2 0x100 : AT (0x4004) { *(.overlay2) }
+}
+