From 22f94ab06cc7802c14175f2f4dcfa73aa983aca2 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 11 Feb 1999 16:14:01 +0000 Subject: [PATCH] Fix for PR 19070 - add ability to detect and generate errors when sections overlap. --- ld/ChangeLog | 17 ++++++ ld/ldlang.c | 66 +++++++++++++++++++++- ld/ldmain.c | 4 +- ld/lexsup.c | 93 +++++++++++++++++++++++-------- ld/testsuite/.Sanitize | 1 + ld/testsuite/ChangeLog | 20 +++++++ ld/testsuite/ld-checks/.Sanitize | 45 +++++++++++++++ ld/testsuite/ld-checks/asm.s | 21 +++++++ ld/testsuite/ld-checks/checks.exp | 72 ++++++++++++++++++++++++ ld/testsuite/ld-checks/script | 8 +++ 10 files changed, 320 insertions(+), 27 deletions(-) create mode 100644 ld/testsuite/ld-checks/.Sanitize create mode 100644 ld/testsuite/ld-checks/asm.s create mode 100644 ld/testsuite/ld-checks/checks.exp create mode 100644 ld/testsuite/ld-checks/script diff --git a/ld/ChangeLog b/ld/ChangeLog index a73693c07e..8a72f815ef 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,20 @@ +1999-02-11 Nick Clifton + + * 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 * configure.tgt: Add support for StrongARM target. diff --git a/ld/ldlang.c b/ld/ldlang.c index 12d20cb3ba..1ddc63bc07 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -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 (); diff --git a/ld/ldmain.c b/ld/ldmain.c index 96f32799e4..b392563a7e 100644 --- a/ld/ldmain.c +++ b/ld/ldmain.c @@ -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. */ diff --git a/ld/lexsup.c b/ld/lexsup.c index 3a03f20388..98b77e5887 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -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) { diff --git a/ld/testsuite/.Sanitize b/ld/testsuite/.Sanitize index 93f85c1eef..a0c5713d0f 100644 --- a/ld/testsuite/.Sanitize +++ b/ld/testsuite/.Sanitize @@ -37,6 +37,7 @@ ld-shared ld-srec ld-undefined ld-versados +ld-checks Things-to-lose: diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index fb9a0f3d98..76de4b5d4c 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,23 @@ +1999-02-11 Nick Clifton + + * 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 + + * 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 + + * config/default.exp (get_link_files): Quote target_triplet and CC + when invoking shell. + (get_target_emul): Likewise. + 1999-01-03 Ken Raeburn * 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 index 0000000000..f644200761 --- /dev/null +++ b/ld/testsuite/ld-checks/.Sanitize @@ -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 index 0000000000..51c5197166 --- /dev/null +++ b/ld/testsuite/ld-checks/asm.s @@ -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 index 0000000000..840853ba79 --- /dev/null +++ b/ld/testsuite/ld-checks/checks.exp @@ -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 index 0000000000..db6c039e78 --- /dev/null +++ b/ld/testsuite/ld-checks/script @@ -0,0 +1,8 @@ +SECTIONS { + .foo 0x100 : { *(.foo) } + .bar 0x100 : AT (0x100) { *(.bar) } + + .overlay1 0x100 : AT (0x4000) { *(.overlay1) } + .overlay2 0x100 : AT (0x4004) { *(.overlay2) } +} +