diff --git a/gold/script-sections.cc b/gold/script-sections.cc index bf25391..e65dc73 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -1913,6 +1913,12 @@ class Output_section_definition : public Sections_element Output_section_definition(const char* name, size_t namelen, const Parser_output_section_header* header); + // Update the section properties if an extra definition for the + // section with the same name is found. + // Check that the new header is compatible with the existing settings. + void + update_header(const Parser_output_section_header* header); + // Finish the output section with the information in the trailer. void finish(const Parser_output_section_trailer* trailer); @@ -1989,6 +1995,12 @@ class Output_section_definition : public Sections_element Section_constraint check_constraint(Output_section_definition** posd); + // Check if the specified constraint is compatible with the current + // section definitions, i. e. this definition may be updated with the + // additional options. + bool + is_constraint_compatible(Section_constraint constraint) const; + // See if this is the alternate output section for a constrained // output section. If it is, transfer the Output_section and return // true. Otherwise return false. @@ -2102,13 +2114,96 @@ Output_section_definition::Output_section_definition( { } +// Update the section properties. + +void +Output_section_definition::update_header( + const Parser_output_section_header* header) +{ + if (header->address) + { + if (this->address_) + gold_error(_("Duplicate address definition for output section '%s'"), + this->name_.c_str()); + else + this->address_ = header->address; + } + if (header->load_address) + { + if (this->load_address_) + gold_error( + _("Duplicate load address definition for output section '%s'"), + this->name_.c_str()); + else + this->load_address_ = header->load_address; + } + if (header->align) + { + if (this->align_) + gold_error( + _("Duplicate definition of alignment for output section '%s'"), + this->name_.c_str()); + else + this->align_ = header->align; + } + if (header->subalign) + { + if (this->subalign_) + gold_error( + _("Duplicate definition of input section alignment " + "for output section '%s'"), + this->name_.c_str()); + else + this->subalign_ = header->subalign; + } + if (header->constraint != CONSTRAINT_NONE) + { + gold_assert(this->is_constraint_compatible(header->constraint)); + this->constraint_ = header->constraint; + } + if (header->section_type != SCRIPT_SECTION_TYPE_NONE) + { + if (this->script_section_type_ != SCRIPT_SECTION_TYPE_NONE + && this->script_section_type_ != header->section_type) + gold_error(_("Incompatible section type definitions " + "for output section '%s'"), + this->name_.c_str()); + else + this->script_section_type_ = header->section_type; + } +} + // Finish an output section. void Output_section_definition::finish(const Parser_output_section_trailer* trailer) { - this->fill_ = trailer->fill; - this->phdrs_ = trailer->phdrs; + if (trailer->fill) + { + if (this->fill_) + gold_error( + _("Duplicate definition of fill value for output section '%s'"), + this->name_.c_str()); + else + this->fill_ = trailer->fill; + } + if (trailer->phdrs) + { + if (!this->phdrs_) + this->phdrs_ = trailer->phdrs; + else + { + for (String_list::iterator i = trailer->phdrs->begin(); + i != trailer->phdrs->end(); + ++i) + { + if (std::find(this->phdrs_->begin(), + this->phdrs_->end(), + *i) == this->phdrs_->end()) + this->phdrs_->push_back(*i); + } + } + } } // Add a symbol to be defined. @@ -2694,6 +2789,28 @@ Output_section_definition::check_constraint(Output_section_definition** posd) } } +// Check if the specified constraint is compatible with the current +// section definitions, i. e. this definition may be updated with the +// additional options. + +bool +Output_section_definition::is_constraint_compatible( + Section_constraint constraint) const +{ + switch (constraint) + { + case CONSTRAINT_NONE: + return true; + case CONSTRAINT_ONLY_IF_RO: + case CONSTRAINT_ONLY_IF_RW: + return this->constraint_ == CONSTRAINT_NONE || + this->constraint_ == constraint; + case CONSTRAINT_SPECIAL: + return this->constraint_ == CONSTRAINT_NONE; + } + gold_unreachable(); +} + // See if this is the alternate output section for a constrained // output section. If it is, transfer the Output_section and return // true. Otherwise return false. @@ -3378,12 +3495,35 @@ Script_sections::start_output_section( size_t namelen, const Parser_output_section_header* header) { + // Try to update settings of an existing section with the same name + // if their constraints are compatible. + std::string name_str(name, namelen); + std::pair< + Known_output_sections_map::iterator, + Known_output_sections_map::iterator> posd_range = + this->known_output_sections_.equal_range(name_str); + for (Known_output_sections_map::iterator it = posd_range.first; + it != posd_range.second; + ++it) + { + Output_section_definition* posd = it->second; + if (posd->is_constraint_compatible(header->constraint)) + { + posd->update_header(header); + gold_assert(this->output_section_ == NULL); + this->output_section_ = posd; + return; + } + } + Output_section_definition* posd = new Output_section_definition(name, namelen, header); this->sections_elements_->push_back(posd); gold_assert(this->output_section_ == NULL); this->output_section_ = posd; + + this->known_output_sections_.insert(std::make_pair(name_str, posd)); } // Stop processing entries for an output section. diff --git a/gold/script-sections.h b/gold/script-sections.h index 30fd96d..3349632 100644 --- a/gold/script-sections.h +++ b/gold/script-sections.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace gold { @@ -304,6 +305,10 @@ class Script_sections Sections_elements* sections_elements_; // The current output section, if there is one. Output_section_definition* output_section_; + // All known output sections, indexed by their names. + typedef std::multimap + Known_output_sections_map; + Known_output_sections_map known_output_sections_; // The list of memory regions in the MEMORY clause. Memory_regions* memory_regions_; // The list of program headers in the PHDRS clause. diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index f9f707e..7fb929b 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -2991,6 +2991,17 @@ script_test_10: $(srcdir)/script_test_10.t script_test_10.o gcctestdir/ld script_test_10.stdout: script_test_10 $(TEST_READELF) -SW script_test_10 > $@ +# Test combining definitions for an output section from a number of input scripts. +check_SCRIPTS += script_test_17.sh +check_DATA += script_test_17.stdout +MOSTLYCLEANFILES += script_test_17 +script_test_17.o: script_test_17.s + $(TEST_AS) -o $@ $< +script_test_17: $(srcdir)/script_test_17.t $(srcdir)/script_test_17a.t script_test_17.o gcctestdir/ld + gcctestdir/ld -o $@ $(srcdir)/script_test_17a.t script_test_17.o -T $(srcdir)/script_test_17.t +script_test_17.stdout: script_test_17 + $(TEST_READELF) -sW $< > $@ + # These tests work with cross linkers only. if DEFAULT_TARGET_I386 diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index a200540..dfbe770 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -769,9 +769,14 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ # These tests work with native and cross linkers. # Test script section order. -@NATIVE_OR_CROSS_LINKER_TRUE@am__append_79 = script_test_10.sh -@NATIVE_OR_CROSS_LINKER_TRUE@am__append_80 = script_test_10.stdout -@NATIVE_OR_CROSS_LINKER_TRUE@am__append_81 = script_test_10 + +# Test combining definitions for an output section from a number of input scripts. +@NATIVE_OR_CROSS_LINKER_TRUE@am__append_79 = script_test_10.sh \ +@NATIVE_OR_CROSS_LINKER_TRUE@ script_test_17.sh +@NATIVE_OR_CROSS_LINKER_TRUE@am__append_80 = script_test_10.stdout \ +@NATIVE_OR_CROSS_LINKER_TRUE@ script_test_17.stdout +@NATIVE_OR_CROSS_LINKER_TRUE@am__append_81 = script_test_10 \ +@NATIVE_OR_CROSS_LINKER_TRUE@ script_test_17 # These tests work with cross linkers only. @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_82 = split_i386.sh @@ -5133,6 +5138,8 @@ defsym_test.sh.log: defsym_test.sh @p='defsym_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) script_test_10.sh.log: script_test_10.sh @p='script_test_10.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) +script_test_17.sh.log: script_test_17.sh + @p='script_test_17.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) split_i386.sh.log: split_i386.sh @p='split_i386.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) split_x86_64.sh.log: split_x86_64.sh @@ -7133,6 +7140,12 @@ uninstall-am: @NATIVE_OR_CROSS_LINKER_TRUE@ gcctestdir/ld -o $@ script_test_10.o -T $(srcdir)/script_test_10.t @NATIVE_OR_CROSS_LINKER_TRUE@script_test_10.stdout: script_test_10 @NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -SW script_test_10 > $@ +@NATIVE_OR_CROSS_LINKER_TRUE@script_test_17.o: script_test_17.s +@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $< +@NATIVE_OR_CROSS_LINKER_TRUE@script_test_17: $(srcdir)/script_test_17.t $(srcdir)/script_test_17a.t script_test_17.o gcctestdir/ld +@NATIVE_OR_CROSS_LINKER_TRUE@ gcctestdir/ld -o $@ $(srcdir)/script_test_17a.t script_test_17.o -T $(srcdir)/script_test_17.t +@NATIVE_OR_CROSS_LINKER_TRUE@script_test_17.stdout: script_test_17 +@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -sW $< > $@ @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_1.o: split_i386_1.s @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $< @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_2.o: split_i386_2.s diff --git a/gold/testsuite/script_test_17.s b/gold/testsuite/script_test_17.s new file mode 100644 index 0000000..9cf964b --- /dev/null +++ b/gold/testsuite/script_test_17.s @@ -0,0 +1,8 @@ + .section .sec0, "a" + .word 0 + + .section .sec1, "a" + .word 0x11 + + .section .sec2, "a" + .word 0x22 diff --git a/gold/testsuite/script_test_17.sh b/gold/testsuite/script_test_17.sh new file mode 100755 index 0000000..3f742b1 --- /dev/null +++ b/gold/testsuite/script_test_17.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# script_test_17.sh -- test combining section definitions. + +# Copyright (C) 2016 Free Software Foundation, Inc. +# Written by Igor Kudrin . + +# This file is part of gold. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 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., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + +file="script_test_17.stdout" + +read_symbol() +{ + symbol=$1 + var=$2 + found=`fgrep "$symbol" $file` + if test -z "$found"; then + echo "Symbol \"$symbol\" not found in file $file" + echo "" + echo "Actual output below:" + cat "$file" + exit 1 + fi + eval $var=`echo $found | awk '{ print $7 }'` +} + +read_symbol "_start_sec0" "sec0_sec" +read_symbol "_start_sec1" "sec1_sec" +read_symbol "_start_sec2" "sec2_sec" + +if test "$sec0_sec" = "$sec1_sec"; then + echo "The content of input sections .sec0 and .sec1 is expected to be put in different output sections" + echo "" + echo "Actual output below:" + cat "$file" + exit 1 +fi + +if test "$sec0_sec" != "$sec2_sec"; then + echo "The content of input sections .sec0 and .sec2 is expected to be put into the same output section" + echo "" + echo "Actual output below:" + cat "$file" + exit 1 +fi diff --git a/gold/testsuite/script_test_17.t b/gold/testsuite/script_test_17.t new file mode 100644 index 0000000..96f958f --- /dev/null +++ b/gold/testsuite/script_test_17.t @@ -0,0 +1,15 @@ +SECTIONS +{ + .sec : + { + _start_sec0 = .; + *(.sec0) + _end_sec0 = .; + } + .sec1 : { + _start_sec1 = .; + *(.sec1) + _end_sec1 = .; + } +} + diff --git a/gold/testsuite/script_test_17a.t b/gold/testsuite/script_test_17a.t new file mode 100644 index 0000000..c8b99fd --- /dev/null +++ b/gold/testsuite/script_test_17a.t @@ -0,0 +1,10 @@ +SECTIONS +{ + .sec : + { + _start_sec2 = .; + *(.sec2) + _end_sec2 = .; + } +} +