diff --git a/gold/output.cc b/gold/output.cc index 8e043d7..fca1aa8 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -4397,7 +4397,7 @@ Output_segment::set_section_addresses(const Target* target, this->offset_ = orig_off; - off_t off = 0; + off_t off = orig_off; uint64_t ret = 0; for (int i = 0; i < static_cast(ORDER_MAX); ++i) { @@ -4414,16 +4414,11 @@ Output_segment::set_section_addresses(const Target* target, } } addr = this->set_section_list_addresses(layout, reset, - &this->output_lists_[i], - addr, poff, pshndx, &in_tls); - if (i < static_cast(ORDER_SMALL_BSS)) - { - this->filesz_ = *poff - orig_off; - off = *poff; - } - + &this->output_lists_[i], addr, + poff, &off, pshndx, &in_tls); ret = addr; } + this->filesz_ = off - orig_off; // If the last section was a TLS section, align upward to the // alignment of the TLS segment, so that the overall size of the TLS @@ -4480,18 +4475,25 @@ Output_segment::set_section_addresses(const Target* target, // Set the addresses and file offsets in a list of Output_data // structures. +// There are two variables to store offsets: +// * poff_mem is used to calculate addresses and the memory size of the segment +// and keeps track of all sections, including BSS. +// * poff_file is used to calculate the file size of the segment and does not +// include BSS segments which are located at the end of the list. uint64_t Output_segment::set_section_list_addresses(Layout* layout, bool reset, Output_data_list* pdl, - uint64_t addr, off_t* poff, + uint64_t addr, off_t* poff_mem, + off_t* poff_file, unsigned int* pshndx, bool* in_tls) { - off_t startoff = *poff; + off_t startoff = *poff_mem; // For incremental updates, we may allocate non-fixed sections from // free space in the file. This keeps track of the high-water mark. - off_t maxoff = startoff; + off_t maxoff_mem = startoff; + off_t maxoff_file = *poff_file; off_t off = startoff; for (Output_data_list::iterator p = pdl->begin(); @@ -4622,8 +4624,11 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, || !(*p)->is_section_type(elfcpp::SHT_NOBITS)) off += (*p)->data_size(); - if (off > maxoff) - maxoff = off; + if (off > maxoff_mem) + maxoff_mem = off; + + if (off > maxoff_file && !(*p)->is_section_type(elfcpp::SHT_NOBITS)) + maxoff_file = off; if ((*p)->is_section()) { @@ -4632,8 +4637,9 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, } } - *poff = maxoff; - return addr + (maxoff - startoff); + *poff_mem = maxoff_mem; + *poff_file = maxoff_file; + return addr + (maxoff_mem - startoff); } // For a non-PT_LOAD segment, set the offset from the sections, if diff --git a/gold/output.h b/gold/output.h index 6b9186b..7b66194 100644 --- a/gold/output.h +++ b/gold/output.h @@ -4851,8 +4851,8 @@ class Output_segment // Set the section addresses in an Output_data_list. uint64_t set_section_list_addresses(Layout*, bool reset, Output_data_list*, - uint64_t addr, off_t* poff, unsigned int* pshndx, - bool* in_tls); + uint64_t addr, off_t* poff_mem, off_t* poff_file, + unsigned int* pshndx, bool* in_tls); // Return the number of Output_sections in an Output_data_list. unsigned int diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index f9f707e..35aa2f0 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 that a BSS section doesn't occupy space in the output file. +check_SCRIPTS += pr16711.sh +check_DATA += pr16711.stdout +MOSTLYCLEANFILES += pr16711 +pr16711.o: pr16711.s + $(TEST_AS) -o $@ $< +pr16711: pr16711.o $(srcdir)/pr16711.t gcctestdir/ld + gcctestdir/ld -o $@ $< -T $(srcdir)/pr16711.t +pr16711.stdout: pr16711 + $(TEST_READELF) -lW $< > $@ + # 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..71313d2 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -769,9 +769,13 @@ 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 that a BSS section doesn't occupy space in the output file. +@NATIVE_OR_CROSS_LINKER_TRUE@am__append_79 = script_test_10.sh \ +@NATIVE_OR_CROSS_LINKER_TRUE@ pr16711.sh +@NATIVE_OR_CROSS_LINKER_TRUE@am__append_80 = script_test_10.stdout \ +@NATIVE_OR_CROSS_LINKER_TRUE@ pr16711.stdout +@NATIVE_OR_CROSS_LINKER_TRUE@am__append_81 = script_test_10 pr16711 # These tests work with cross linkers only. @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_82 = split_i386.sh @@ -5133,6 +5137,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) +pr16711.sh.log: pr16711.sh + @p='pr16711.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 +7139,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@pr16711.o: pr16711.s +@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $< +@NATIVE_OR_CROSS_LINKER_TRUE@pr16711: pr16711.o $(srcdir)/pr16711.t gcctestdir/ld +@NATIVE_OR_CROSS_LINKER_TRUE@ gcctestdir/ld -o $@ $< -T $(srcdir)/pr16711.t +@NATIVE_OR_CROSS_LINKER_TRUE@pr16711.stdout: pr16711 +@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -lW $< > $@ @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/pr16711.s b/gold/testsuite/pr16711.s new file mode 100644 index 0000000..e6cab14 --- /dev/null +++ b/gold/testsuite/pr16711.s @@ -0,0 +1,8 @@ +.globl _start +.text +_start: + nop +.data + .space 8 +.bss + .space 4 diff --git a/gold/testsuite/pr16711.sh b/gold/testsuite/pr16711.sh new file mode 100755 index 0000000..c62c699 --- /dev/null +++ b/gold/testsuite/pr16711.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +# pr16711.sh -- test the file size of a segment with a BSS section. + +# 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. + +# If the .bss section is handled properly, there should be +# a writable LOAD segment which has FileSize less than MemSize. + +file="pr16711.stdout" + +check() +{ + egrep "LOAD.*W" $file | while read -r line; do + file_size=`echo $line | awk '{print $5}'` + mem_size=`echo $line | awk '{print $6}'` + if test $(($file_size)) -lt $(($mem_size)); then + echo OK + break + fi + done +} + +if test -z "$(check)"; then + echo "Can't find a segment with a properly handled BSS section" + echo "" + echo "Actual output below:" + cat "$file" + exit 1 +fi + +exit 0 diff --git a/gold/testsuite/pr16711.t b/gold/testsuite/pr16711.t new file mode 100644 index 0000000..5da36da --- /dev/null +++ b/gold/testsuite/pr16711.t @@ -0,0 +1,6 @@ +SECTIONS +{ + .text : { *(.text) } + .data : { *(.data) } + .bss : { *(.bss) } +}