Fix problems with bss handling in linker scripts.
authorCary Coutant <ccoutant@gmail.com>
Mon, 12 Dec 2016 01:31:25 +0000 (17:31 -0800)
committerCary Coutant <ccoutant@gmail.com>
Mon, 12 Dec 2016 01:31:25 +0000 (17:31 -0800)
PR 16711 noted that gold allocates file space for BSS sections when using
a linker script. I've fixed that by rewriting set_section_addresses and
set_section_list_addresses to track the file offset separate from the
current virtual address, so that BSS sections do not move the file offset.
Now, if a series of BSS sections come at the end of a segment, we do not
allocate file space; but if a script forces them into the middle of a
segment, we will still allocate file space (matching Gnu ld behavior).
I've also added a warning when that happens.

That exposed another problem where orphan .bss sections were sometimes
placed in the middle of a segment. For example, if the script mentions
the .got section, but both .data and .bss are orphans, gold would put
both .data and .bss in front of .got. I've fixed that by ensuring that
orphan BSS sections are always placed after all other allocated sections.

It also exposed a problem where the SUBALIGN property is not handled
properly. The ld manual clearly states that it should override input section
alignment, whether greater or less than the given alignment, but gold would
only increase an input section's alignment. Gold would also place the output
section based on its original alignment before the SUBALIGN property took
effect, leading to a misaligned output section (where the input section
was properly aligned in memory, but was not aligned relative to the start
of the section), in violation of the ELF/gABI spec. I've fixed that by
making sure that the SUBALIGN property overrides the internal alignment of
the input sections as well as the external alignment of the output section.
This affected the behavior of script_test_2, which was written to expect
a misaligned section.

The net effect is, I think, improved compatibility with the BFD linker.
There are still cases where orphan placement differs, but the differences
should be rarer and less important. ALIGN and SUBALIGN behavior is closer,
but still not an exact match -- I still found cases where ld would create
a misaligned output section, and where gold will properly align it.

gold/
PR gold/16711
* output.cc (Output_section::set_final_data_size): Calculate data size
based on relative offset rather than file offset.
(Output_segment::set_section_addresses): Track file offset separately
from address offset.
(Output_segment::set_section_list_addresses): Add pfoff parameter.
Track file offset separately.  Don't move file offset for BSS
sections.
* output.h (Output_segment::set_section_list_addresses): Add pfoff
parameter.
* script-sections.cc (Orphan_section_placement): Add PLACE_LAST_ALLOC.
(Orphan_section_placement::Orphan_section_placement): Initialize it.
(Orphan_section_placement::output_section_init): Track last allocated
section.
(Orphan_section_placement::find_place): Place BSS after last allocated
section.
(Output_section_element_input::set_section_addresses): Always override
input section alignment when SUBALIGN is specified.
(Output_section_definition::set_section_addresses): Override alignment
of output section when SUBALIGN is specified.

* testsuite/Makefile.am (script_test_15a, script_test_15b)
(script_test_15c): New test cases.
* testsuite/Makefile.in: Regenerate.
* testsuite/script_test_2.cc: Adjust expected layout.
* testsuite/script_test_15.c: New source file.
* testsuite/script_test_15a.sh: New shell script.
* testsuite/script_test_15a.t: New linker script.
* testsuite/script_test_15b.sh: New shell script.
* testsuite/script_test_15b.t: New linker script.
* testsuite/script_test_15c.sh: New shell script.
* testsuite/script_test_15c.t: New linker script.

14 files changed:
gold/ChangeLog
gold/output.cc
gold/output.h
gold/script-sections.cc
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/script_test_15.c [new file with mode: 0644]
gold/testsuite/script_test_15a.sh [new file with mode: 0755]
gold/testsuite/script_test_15a.t [new file with mode: 0644]
gold/testsuite/script_test_15b.sh [new file with mode: 0755]
gold/testsuite/script_test_15b.t [new file with mode: 0644]
gold/testsuite/script_test_15c.sh [new file with mode: 0755]
gold/testsuite/script_test_15c.t [new file with mode: 0644]
gold/testsuite/script_test_2.cc

index 7ff70b22f74ca8a2b2b289bd9be982ed11ff6ba1..d129ddf09468c60e105e29378e4c98461a1bad7e 100644 (file)
@@ -1,6 +1,37 @@
 2016-12-11  Cary Coutant  <ccoutant@gmail.com>
 
-       * Makefile.in: Regenerate.
+       PR gold/16711
+       * output.cc (Output_section::set_final_data_size): Calculate data size
+       based on relative offset rather than file offset.
+       (Output_segment::set_section_addresses): Track file offset separately
+       from address offset.
+       (Output_segment::set_section_list_addresses): Add pfoff parameter.
+       Track file offset separately.  Don't move file offset for BSS
+       sections.
+       * output.h (Output_segment::set_section_list_addresses): Add pfoff
+       parameter.
+       * script-sections.cc (Orphan_section_placement): Add PLACE_LAST_ALLOC.
+       (Orphan_section_placement::Orphan_section_placement): Initialize it.
+       (Orphan_section_placement::output_section_init): Track last allocated
+       section.
+       (Orphan_section_placement::find_place): Place BSS after last allocated
+       section.
+       (Output_section_element_input::set_section_addresses): Always override
+       input section alignment when SUBALIGN is specified.
+       (Output_section_definition::set_section_addresses): Override alignment
+       of output section when SUBALIGN is specified.
+
+       * testsuite/Makefile.am (script_test_15a, script_test_15b)
+       (script_test_15c): New test cases.
+       * testsuite/Makefile.in: Regenerate.
+       * testsuite/script_test_2.cc: Adjust expected layout.
+       * testsuite/script_test_15.c: New source file.
+       * testsuite/script_test_15a.sh: New shell script.
+       * testsuite/script_test_15a.t: New linker script.
+       * testsuite/script_test_15b.sh: New shell script.
+       * testsuite/script_test_15b.t: New linker script.
+       * testsuite/script_test_15c.sh: New shell script.
+       * testsuite/script_test_15c.t: New linker script.
 
 2016-12-08  Alan Modra  <amodra@gmail.com>
 
index 8e043d7cedc642b84b9dede0283aaf5b76eb00df..cf934fb61a33b2a5b14a16af3c88ff9721540e76 100644 (file)
@@ -3165,17 +3165,17 @@ Output_section::set_final_data_size()
 
       uint64_t address = this->address();
       off_t startoff = this->offset();
-      off_t off = startoff + this->first_input_offset_;
+      off_t off = this->first_input_offset_;
       for (Input_section_list::iterator p = this->input_sections_.begin();
           p != this->input_sections_.end();
           ++p)
        {
          off = align_address(off, p->addralign());
-         p->set_address_and_file_offset(address + (off - startoff), off,
+         p->set_address_and_file_offset(address + off, startoff + off,
                                         startoff);
          off += p->data_size();
        }
-      data_size = off - startoff;
+      data_size = off;
     }
 
   // For full incremental links, we want to allocate some patch space
@@ -4398,12 +4398,14 @@ Output_segment::set_section_addresses(const Target* target,
   this->offset_ = orig_off;
 
   off_t off = 0;
+  off_t foff = *poff;
   uint64_t ret = 0;
   for (int i = 0; i < static_cast<int>(ORDER_MAX); ++i)
     {
       if (i == static_cast<int>(ORDER_RELRO_LAST))
        {
          *poff += last_relro_pad;
+         foff += last_relro_pad;
          addr += last_relro_pad;
          if (this->output_lists_[i].empty())
            {
@@ -4415,12 +4417,20 @@ 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<int>(ORDER_SMALL_BSS))
-       {
-         this->filesz_ = *poff - orig_off;
-         off = *poff;
-       }
+                                             addr, poff, &foff, pshndx,
+                                             &in_tls);
+
+      // FOFF tracks the last offset used for the file image,
+      // and *POFF tracks the last offset used for the memory image.
+      // When not using a linker script, bss sections should all
+      // be processed in the ORDER_SMALL_BSS and later buckets.
+      gold_assert(*poff == foff
+                 || i == static_cast<int>(ORDER_TLS_BSS)
+                 || i >= static_cast<int>(ORDER_SMALL_BSS)
+                 || layout->script_options()->saw_sections_clause());
+
+      this->filesz_ = foff - orig_off;
+      off = foff;
 
       ret = addr;
     }
@@ -4485,6 +4495,7 @@ uint64_t
 Output_segment::set_section_list_addresses(Layout* layout, bool reset,
                                           Output_data_list* pdl,
                                           uint64_t addr, off_t* poff,
+                                          off_t* pfoff,
                                           unsigned int* pshndx,
                                           bool* in_tls)
 {
@@ -4494,10 +4505,14 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
   off_t maxoff = startoff;
 
   off_t off = startoff;
+  off_t foff = *pfoff;
   for (Output_data_list::iterator p = pdl->begin();
        p != pdl->end();
        ++p)
     {
+      bool is_bss = (*p)->is_section_type(elfcpp::SHT_NOBITS);
+      bool is_tls = (*p)->is_section_flag_set(elfcpp::SHF_TLS);
+
       if (reset)
        (*p)->reset_address_and_file_offset();
 
@@ -4507,7 +4522,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
        {
          uint64_t align = (*p)->addralign();
 
-         if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+         if (is_tls)
            {
              // Give the first TLS section the alignment of the
              // entire TLS segment.  Otherwise the TLS segment as a
@@ -4542,8 +4557,11 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
 
          if (!parameters->incremental_update())
            {
+             gold_assert(off == foff || is_bss);
              off = align_address(off, align);
-             (*p)->set_address_and_file_offset(addr + (off - startoff), off);
+             if (is_tls || !is_bss)
+               foff = off;
+             (*p)->set_address_and_file_offset(addr + (off - startoff), foff);
            }
          else
            {
@@ -4551,6 +4569,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
              (*p)->pre_finalize_data_size();
              off_t current_size = (*p)->current_data_size();
              off = layout->allocate(current_size, align, startoff);
+             foff = off;
              if (off == -1)
                {
                  gold_assert((*p)->output_section() != NULL);
@@ -4558,7 +4577,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
                                  "relink with --incremental-full"),
                                (*p)->output_section()->name());
                }
-             (*p)->set_address_and_file_offset(addr + (off - startoff), off);
+             (*p)->set_address_and_file_offset(addr + (off - startoff), foff);
              if ((*p)->data_size() > current_size)
                {
                  gold_assert((*p)->output_section() != NULL);
@@ -4573,13 +4592,22 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
          // For incremental updates, use the fixed offset for the
          // high-water mark computation.
          off = (*p)->offset();
+         foff = off;
        }
       else
        {
          // The script may have inserted a skip forward, but it
          // better not have moved backward.
          if ((*p)->address() >= addr + (off - startoff))
-           off += (*p)->address() - (addr + (off - startoff));
+           {
+             if (!is_bss && off > foff)
+               gold_warning(_("script places BSS section in the middle "
+                              "of a LOAD segment; space will be allocated "
+                              "in the file"));
+             off += (*p)->address() - (addr + (off - startoff));
+             if (is_tls || !is_bss)
+               foff = off;
+           }
          else
            {
              if (!layout->script_options()->saw_sections_clause())
@@ -4603,7 +4631,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
                               os->name(), previous_dot, dot);
                }
            }
-         (*p)->set_file_offset(off);
+         (*p)->set_file_offset(foff);
          (*p)->finalize_data_size();
        }
 
@@ -4618,10 +4646,14 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
       // We want to ignore the size of a SHF_TLS SHT_NOBITS
       // section.  Such a section does not affect the size of a
       // PT_LOAD segment.
-      if (!(*p)->is_section_flag_set(elfcpp::SHF_TLS)
-         || !(*p)->is_section_type(elfcpp::SHT_NOBITS))
+      if (!is_tls || !is_bss)
        off += (*p)->data_size();
 
+      // We don't allocate space in the file for SHT_NOBITS sections,
+      // unless a script has force-placed one in the middle of a segment.
+      if (!is_bss)
+       foff = off;
+
       if (off > maxoff)
        maxoff = off;
 
@@ -4633,6 +4665,7 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset,
     }
 
   *poff = maxoff;
+  *pfoff = foff;
   return addr + (maxoff - startoff);
 }
 
index 62386a6abdcc19790a0e66a1c1f6abc0b3d6698f..9083b5ac74d98d6916debe8e8cfafd3b8631e474 100644 (file)
@@ -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, off_t* fpoff,
+                            unsigned int* pshndx, bool* in_tls);
 
   // Return the number of Output_sections in an Output_data_list.
   unsigned int
index f35ecc11778bd1ceb1091199bf56a00ad506d76c..ae81f89fcc99b4d27def8f3b7162546bd658e9f1 100644 (file)
@@ -329,6 +329,7 @@ class Orphan_section_placement
     PLACE_TLS,
     PLACE_TLS_BSS,
     PLACE_BSS,
+    PLACE_LAST_ALLOC,
     PLACE_REL,
     PLACE_INTERP,
     PLACE_NONALLOC,
@@ -368,6 +369,7 @@ Orphan_section_placement::Orphan_section_placement()
   this->initialize_place(PLACE_TLS, NULL);
   this->initialize_place(PLACE_TLS_BSS, NULL);
   this->initialize_place(PLACE_BSS, ".bss");
+  this->initialize_place(PLACE_LAST_ALLOC, NULL);
   this->initialize_place(PLACE_REL, NULL);
   this->initialize_place(PLACE_INTERP, ".interp");
   this->initialize_place(PLACE_NONALLOC, NULL);
@@ -396,6 +398,15 @@ Orphan_section_placement::output_section_init(const std::string& name,
   bool first_init = this->first_init_;
   this->first_init_ = false;
 
+  // Remember the last allocated section. Any orphan bss sections
+  // will be placed after it.
+  if (os != NULL
+      && (os->flags() & elfcpp::SHF_ALLOC) != 0)
+    {
+      this->places_[PLACE_LAST_ALLOC].location = location;
+      this->places_[PLACE_LAST_ALLOC].have_location = true;
+    }
+
   for (int i = 0; i < PLACE_MAX; ++i)
     {
       if (this->places_[i].name != NULL && this->places_[i].name == name)
@@ -509,7 +520,7 @@ Orphan_section_placement::find_place(Output_section* os,
          follow = PLACE_TEXT;
          break;
        case PLACE_BSS:
-         follow = PLACE_DATA;
+         follow = PLACE_LAST_ALLOC;
          break;
        case PLACE_REL:
          follow = PLACE_TEXT;
@@ -1751,16 +1762,16 @@ Output_section_element_input::set_section_addresses(
           p != matching_sections[i].end();
           ++p)
        {
-         // Override the original address alignment if SUBALIGN is specified
-         // and is greater than the original alignment.  We need to make a
-         // copy of the input section to modify the alignment.
+         // Override the original address alignment if SUBALIGN is specified.
+         // We need to make a copy of the input section to modify the
+         // alignment.
          Output_section::Input_section sis(p->input_section());
 
          uint64_t this_subalign = sis.addralign();
          if (!sis.is_input_section())
            sis.output_section_data()->finalize_data_size();
          uint64_t data_size = sis.data_size();
-         if (this_subalign < subalign)
+         if (subalign > 0)
            {
              this_subalign = subalign;
              sis.set_addralign(subalign);
@@ -2463,6 +2474,35 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
        this->output_section_->set_addralign(align);
     }
 
+  uint64_t subalign;
+  if (this->subalign_ == NULL)
+    subalign = 0;
+  else
+    {
+      Output_section* subalign_section;
+      subalign = this->subalign_->eval_with_dot(symtab, layout, true,
+                                               *dot_value, NULL,
+                                               &subalign_section, NULL,
+                                               false);
+      if (subalign_section != NULL)
+       gold_warning(_("subalign of section %s is not absolute"),
+                    this->name_.c_str());
+
+      // Reserve a value of 0 to mean there is no SUBALIGN property.
+      if (subalign == 0)
+       subalign = 1;
+
+      // The external alignment of the output section must be at least
+      // as large as that of the input sections.  If there is no
+      // explicit ALIGN property, we set the output section alignment
+      // to match the input section alignment.
+      if (align < subalign || this->align_ == NULL)
+       {
+         align = subalign;
+         this->output_section_->set_addralign(align);
+       }
+    }
+
   address = align_address(address, align);
 
   uint64_t start_address = address;
@@ -2547,21 +2587,6 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
 
   this->evaluated_load_address_ = laddr;
 
-  uint64_t subalign;
-  if (this->subalign_ == NULL)
-    subalign = 0;
-  else
-    {
-      Output_section* subalign_section;
-      subalign = this->subalign_->eval_with_dot(symtab, layout, true,
-                                               *dot_value, NULL,
-                                               &subalign_section, NULL,
-                                               false);
-      if (subalign_section != NULL)
-       gold_warning(_("subalign of section %s is not absolute"),
-                    this->name_.c_str());
-    }
-
   std::string fill;
   if (this->fill_ != NULL)
     {
index 17f45d666668889fe1018c6a4bf46713d286cfb8..6a0b19d6bf383fe2bbe3719c88e08f1cff938125 100644 (file)
@@ -2009,6 +2009,33 @@ script_test_14: $(srcdir)/script_test_14.t script_test_14.o gcctestdir/ld
 script_test_14.stdout: script_test_14
        $(TEST_OBJDUMP) -s script_test_14 > $@
 
+# Test BSS section placement at end of segment.
+check_SCRIPTS += script_test_15a.sh
+check_DATA += script_test_15a.stdout
+MOSTLYCLEANFILES += script_test_15a
+script_test_15a: $(srcdir)/script_test_15a.t script_test_15.o gcctestdir/ld
+       gcctestdir/ld -o $@ script_test_15.o -T $(srcdir)/script_test_15a.t
+script_test_15a.stdout: script_test_15a
+       $(TEST_READELF) -lSW script_test_15a > $@
+
+# Test BSS section placement in middle of segment.
+check_SCRIPTS += script_test_15b.sh
+check_DATA += script_test_15b.stdout
+MOSTLYCLEANFILES += script_test_15b
+script_test_15b: $(srcdir)/script_test_15b.t script_test_15.o gcctestdir/ld
+       gcctestdir/ld -o $@ script_test_15.o -T $(srcdir)/script_test_15b.t
+script_test_15b.stdout: script_test_15b
+       $(TEST_READELF) -lSW script_test_15b > $@
+
+# Test orphan BSS section placement.
+check_SCRIPTS += script_test_15c.sh
+check_DATA += script_test_15c.stdout
+MOSTLYCLEANFILES += script_test_15c
+script_test_15c: $(srcdir)/script_test_15c.t script_test_15.o gcctestdir/ld
+       gcctestdir/ld -o $@ script_test_15.o -T $(srcdir)/script_test_15c.t
+script_test_15c.stdout: script_test_15c
+       $(TEST_READELF) -lSW script_test_15c > $@
+
 # Test --dynamic-list, --dynamic-list-data, --dynamic-list-cpp-new,
 # and --dynamic-list-cpp-typeinfo
 
index 5fef3cfed78f3759d11b67b27184ba27a5dab5df..a1d8b396ffd903553ef815184379ae4407f2d443 100644 (file)
@@ -365,9 +365,11 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_4 script_test_5 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_6 script_test_7 \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_8 script_test_9 \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_14 dynamic_list \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list.stdout libthin1.a \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ libthin3.a libthinall.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_14 script_test_15a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_15b script_test_15c \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list dynamic_list.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libthin1.a libthin3.a \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ libthinall.a \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/thin_archive_test_2.o \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/thin_archive_test_4.o \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/libthin2.a alt/libthin4.a
@@ -391,6 +393,12 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 
 # Test for SORT_BY_INIT_PRIORITY.
 
+# Test BSS section placement at end of segment.
+
+# Test BSS section placement in middle of segment.
+
+# Test orphan BSS section placement.
+
 # Test --dynamic-list, --dynamic-list-data, --dynamic-list-cpp-new,
 # and --dynamic-list-cpp-typeinfo
 @GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_42 =  \
@@ -410,6 +418,9 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_8.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_9.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_14.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_15a.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_15b.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_15c.sh \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list.sh
 
 # Create the data files that debug_msg.sh analyzes.
@@ -459,6 +470,9 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_8.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_9.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_14.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_15a.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_15b.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ script_test_15c.stdout \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ dynamic_list.stdout
 @GCC_FALSE@initpri1_DEPENDENCIES =
 @NATIVE_LINKER_FALSE@initpri1_DEPENDENCIES =
@@ -5101,6 +5115,12 @@ script_test_9.sh.log: script_test_9.sh
        @p='script_test_9.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 script_test_14.sh.log: script_test_14.sh
        @p='script_test_14.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_15a.sh.log: script_test_15a.sh
+       @p='script_test_15a.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_15b.sh.log: script_test_15b.sh
+       @p='script_test_15b.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+script_test_15c.sh.log: script_test_15c.sh
+       @p='script_test_15c.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 dynamic_list.sh.log: dynamic_list.sh
        @p='dynamic_list.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 plugin_test_1.sh.log: plugin_test_1.sh
@@ -6642,6 +6662,18 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ script_test_14.o -T $(srcdir)/script_test_14.t
 @GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_14.stdout: script_test_14
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_OBJDUMP) -s script_test_14 > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_15a: $(srcdir)/script_test_15a.t script_test_15.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ script_test_15.o -T $(srcdir)/script_test_15a.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_15a.stdout: script_test_15a
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -lSW script_test_15a > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_15b: $(srcdir)/script_test_15b.t script_test_15.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ script_test_15.o -T $(srcdir)/script_test_15b.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_15b.stdout: script_test_15b
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -lSW script_test_15b > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_15c: $(srcdir)/script_test_15c.t script_test_15.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ script_test_15.o -T $(srcdir)/script_test_15c.t
+@GCC_TRUE@@NATIVE_LINKER_TRUE@script_test_15c.stdout: script_test_15c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -lSW script_test_15c > $@
 @GCC_TRUE@@NATIVE_LINKER_TRUE@dynamic_list: basic_test.o gcctestdir/ld $(srcdir)/dynamic_list.t
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ basic_test.o \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@   -Wl,--dynamic-list $(srcdir)/dynamic_list.t \
diff --git a/gold/testsuite/script_test_15.c b/gold/testsuite/script_test_15.c
new file mode 100644 (file)
index 0000000..48cfde8
--- /dev/null
@@ -0,0 +1,10 @@
+int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+int extra[] __attribute__ ((section(".data.extra"))) = { 1, 2, 3, 4 };
+
+int zeroes[1024] = {0};
+
+int main(void)
+{
+  return 0;
+}
diff --git a/gold/testsuite/script_test_15a.sh b/gold/testsuite/script_test_15a.sh
new file mode 100755 (executable)
index 0000000..791350c
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# script_test_15a.sh -- test for .bss placement.
+
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@gmail.com>.
+
+# 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.
+
+# Check that the .bss section is not allocated in the file image.
+
+check()
+{
+    if ! grep -q "$2" "$1"
+    then
+       echo "Did not find expected section in $1:"
+       echo "   $2"
+       echo ""
+       echo "Actual output below:"
+       cat "$1"
+       exit 1
+    fi
+}
+
+check script_test_15a.stdout "LOAD.*0x0000.. 0x0010.. RW"
+check script_test_15a.stdout "01.*\\.data .*\\.data.extra .*\\.bss"
diff --git a/gold/testsuite/script_test_15a.t b/gold/testsuite/script_test_15a.t
new file mode 100644 (file)
index 0000000..5f14c8e
--- /dev/null
@@ -0,0 +1,40 @@
+/* script_test_15a.t -- linker script test 15a for gold
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Written by Cary Coutant <ccoutant@google.com>.
+
+   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.  */
+
+/* We won't try to run this program, just ensure that it links
+   as expected.  */
+
+SECTIONS
+{
+  /* With luck this will be enough to get the program working.  */
+  .interp : { *(.interp) }
+  .text : { *(.text .text.*) }
+  .rodata : { *(.rodata .rodata.*) }
+  /* Required by the ARM target. */
+  .ARM.extab : { *(.ARM.extab*) }
+  .ARM.exidx : { *(.ARM.exidx*) }
+  . = ALIGN(0x10000);
+  .dynamic : { *(.dynamic) }
+  .data : { *(.data) }
+  .got : { *(.got .toc) }
+  .bss : { *(.bss) }
+}
diff --git a/gold/testsuite/script_test_15b.sh b/gold/testsuite/script_test_15b.sh
new file mode 100755 (executable)
index 0000000..3179758
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# script_test_15b.sh -- test for .bss placement.
+
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@gmail.com>.
+
+# 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.
+
+# Check that a .bss section placed in the middle of a segment
+# is allocated in the file image.
+
+check()
+{
+    if ! grep -q "$2" "$1"
+    then
+       echo "Did not find expected section in $1:"
+       echo "   $2"
+       echo ""
+       echo "Actual output below:"
+       cat "$1"
+       exit 1
+    fi
+}
+
+check script_test_15b.stdout "LOAD.*0x0010.. 0x0010.. RW"
+check script_test_15b.stdout "01.*\\.bss .*\\.data .*\\.data.extra"
diff --git a/gold/testsuite/script_test_15b.t b/gold/testsuite/script_test_15b.t
new file mode 100644 (file)
index 0000000..2a17a7f
--- /dev/null
@@ -0,0 +1,49 @@
+/* script_test_15b.t -- linker script test 15b for gold
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Written by Cary Coutant <ccoutant@google.com>.
+
+   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.  */
+
+/* Test that a .bss section explicitly placed in the middle of a
+   segment has allocated file space.  */
+
+/* We won't try to run this program, just ensure that it links
+   as expected.  */
+
+PHDRS
+{
+  text    PT_LOAD FLAGS(5);
+  data    PT_LOAD FLAGS(6);
+}
+
+SECTIONS
+{
+  /* With luck this will be enough to get the program working.  */
+  .interp : { *(.interp) } :text
+  .text : { *(.text .text.*) }
+  .rodata : { *(.rodata .rodata.*) }
+  /* Required by the ARM target. */
+  .ARM.extab : { *(.ARM.extab*) }
+  .ARM.exidx : { *(.ARM.exidx*) }
+  . = ALIGN(0x10000);
+  .dynamic : { *(.dynamic) }
+  .bss : { *(.bss) } :data
+  .data : { *(.data) }
+  .got : { *(.got .toc) }
+}
diff --git a/gold/testsuite/script_test_15c.sh b/gold/testsuite/script_test_15c.sh
new file mode 100755 (executable)
index 0000000..27631fc
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# script_test_15c.sh -- test for .bss placement.
+
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@gmail.com>.
+
+# 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.
+
+# Check that an orphan .bss section is placed at the end of a segment
+# and is not allocated in the file image.
+
+check()
+{
+    if ! grep -q "$2" "$1"
+    then
+       echo "Did not find expected section in $1:"
+       echo "   $2"
+       echo ""
+       echo "Actual output below:"
+       cat "$1"
+       exit 1
+    fi
+}
+
+check script_test_15c.stdout "LOAD.*0x0000.. 0x0010.. RW"
+check script_test_15c.stdout "01.*\\.data .*\\.data.extra .*\\.bss"
diff --git a/gold/testsuite/script_test_15c.t b/gold/testsuite/script_test_15c.t
new file mode 100644 (file)
index 0000000..667d727
--- /dev/null
@@ -0,0 +1,41 @@
+/* script_test_15c.t -- linker script test 15c for gold
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Written by Cary Coutant <ccoutant@google.com>.
+
+   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.  */
+
+/* Test that an orphan .bss section is placed at the end of the segment.  */
+
+/* We won't try to run this program, just ensure that it links
+   as expected.  */
+
+SECTIONS
+{
+  /* With luck this will be enough to get the program working.  */
+  .interp : { *(.interp) }
+  .text : { *(.text .text.*) }
+  .rodata : { *(.rodata .rodata.*) }
+  /* Required by the ARM target. */
+  .ARM.extab : { *(.ARM.extab*) }
+  .ARM.exidx : { *(.ARM.exidx*) }
+  . = ALIGN(0x10000);
+  .dynamic : { *(.dynamic) }
+  .data : { *(.data) }
+  .got : { *(.got .toc) }
+}
index d1b7aa95c226bf471a2ccc5c80564b34809df887..eb45b32b32e2abafbaf21ac684bab79c8d6aae26 100644 (file)
@@ -42,21 +42,19 @@ int
 main(int, char**)
 {
   assert(reinterpret_cast<uintptr_t>(start_test_area) == 0x20000001);
-  assert(reinterpret_cast<uintptr_t>(start_test_area_1) == 0x20000010);
+  assert(reinterpret_cast<uintptr_t>(start_test_area_1) == 0x20000020);
 
-  // We should see the string from script_test_2b.o next.  The
-  // subalign should move it up to 0x20000020.
-  for (int i = 0; i < 16; ++i)
-    assert(start_test_area_1[i] == 0);
-  assert(strcmp(start_test_area_1 + 16, "test bb") == 0);
+  assert(strcmp(start_test_area_1, "test bb") == 0);
 
   // Next the string from script_test_2a.o, after the subalign.
-  for (int i = 16 + 7; i < 48; ++i)
+  for (int i = 7; i < 32; ++i)
     assert(start_test_area_1[i] == 0);
-  assert(strcmp(start_test_area_1 + 48, "test aa") == 0);
+  assert(strcmp(start_test_area_1 + 32, "test aa") == 0);
 
-  // Move four bytes forward to start_data.
-  assert(reinterpret_cast<uintptr_t>(start_test_area_1 + 48 + 8 + 4)
+  // Skip to start_data at relative offset 60.
+  for (int i = 32 + 7; i < 60; ++i)
+    assert(start_test_area_1[i] == 0);
+  assert(reinterpret_cast<uintptr_t>(start_test_area_1 + 60)
         == reinterpret_cast<uintptr_t>(start_data));
   assert(memcmp(start_data, "\1\2\0\4\0\0\0\010\0\0\0\0\0\0\0", 15) == 0
         || memcmp(start_data, "\1\0\2\0\0\0\4\0\0\0\0\0\0\0\010", 15) == 0);