]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Make sure the start and size of the TLS segment are aligned.
authorIan Lance Taylor <iant@google.com>
Wed, 19 Mar 2008 21:41:38 +0000 (21:41 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 19 Mar 2008 21:41:38 +0000 (21:41 +0000)
gold/layout.cc
gold/output.cc
gold/output.h
gold/testsuite/tls_test.cc

index 978828f16aad07d39d2d6f2667b84f79aee64c45..9758597af5829aad5571e209ff35a443f1b06d56 100644 (file)
@@ -1535,8 +1535,8 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
            }
 
          unsigned int shndx_hold = *pshndx;
-         uint64_t new_addr = (*p)->set_section_addresses(false, addr, &off,
-                                                         pshndx);
+         uint64_t new_addr = (*p)->set_section_addresses(this, false, addr,
+                                                          &off, pshndx);
 
          // Now that we know the size of this segment, we may be able
          // to save a page in memory, at the cost of wasting some
@@ -1561,8 +1561,8 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
                  addr = align_address(aligned_addr, common_pagesize);
                  addr = align_address(addr, (*p)->maximum_alignment());
                  off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
-                 new_addr = (*p)->set_section_addresses(true, addr, &off,
-                                                        pshndx);
+                 new_addr = (*p)->set_section_addresses(this, true, addr,
+                                                         &off, pshndx);
                }
            }
 
index ba4f6c8421fa3ddd8fd2f077d02be2a78d66f0ac..85cc2b257be06181fb9fe2bdbf0ea8a6a8012beb 100644 (file)
@@ -2483,7 +2483,8 @@ Output_segment::dynamic_reloc_count_list(const Output_data_list* pdl) const
 // *POFF and *PSHNDX.
 
 uint64_t
-Output_segment::set_section_addresses(bool reset, uint64_t addr, off_t* poff,
+Output_segment::set_section_addresses(const Layout* layout, bool reset,
+                                      uint64_t addr, off_t* poff,
                                      unsigned int* pshndx)
 {
   gold_assert(this->type_ == elfcpp::PT_LOAD);
@@ -2500,17 +2501,31 @@ Output_segment::set_section_addresses(bool reset, uint64_t addr, off_t* poff,
       this->are_addresses_set_ = true;
     }
 
+  bool in_tls = false;
+
   off_t orig_off = *poff;
   this->offset_ = orig_off;
 
-  addr = this->set_section_list_addresses(reset, &this->output_data_,
-                                         addr, poff, pshndx);
+  addr = this->set_section_list_addresses(layout, reset, &this->output_data_,
+                                         addr, poff, pshndx, &in_tls);
   this->filesz_ = *poff - orig_off;
 
   off_t off = *poff;
 
-  uint64_t ret = this->set_section_list_addresses(reset, &this->output_bss_,
-                                                 addr, poff, pshndx);
+  uint64_t ret = this->set_section_list_addresses(layout, reset,
+                                                  &this->output_bss_,
+                                                 addr, poff, pshndx,
+                                                  &in_tls);
+
+  // 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
+  // segment is aligned.
+  if (in_tls)
+    {
+      uint64_t segment_align = layout->tls_segment()->maximum_alignment();
+      *poff = align_address(*poff, segment_align);
+    }
+
   this->memsz_ = *poff - orig_off;
 
   // Ignore the file offset adjustments made by the BSS Output_data
@@ -2524,9 +2539,11 @@ Output_segment::set_section_addresses(bool reset, uint64_t addr, off_t* poff,
 // structures.
 
 uint64_t
-Output_segment::set_section_list_addresses(bool reset, Output_data_list* pdl,
+Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
+                                           Output_data_list* pdl,
                                           uint64_t addr, off_t* poff,
-                                          unsigned int* pshndx)
+                                          unsigned int* pshndx,
+                                           bool* in_tls)
 {
   off_t startoff = *poff;
 
@@ -2542,7 +2559,42 @@ Output_segment::set_section_list_addresses(bool reset, Output_data_list* pdl,
       // already have an address.
       if (!(*p)->is_address_valid())
        {
-         off = align_address(off, (*p)->addralign());
+          uint64_t align = (*p)->addralign();
+
+          if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+            {
+              // Give the first TLS section the alignment of the
+              // entire TLS segment.  Otherwise the TLS segment as a
+              // whole may be misaligned.
+              if (!*in_tls)
+                {
+                  Output_segment* tls_segment = layout->tls_segment();
+                  gold_assert(tls_segment != NULL);
+                  uint64_t segment_align = tls_segment->maximum_alignment();
+                  gold_assert(segment_align >= align);
+                  align = segment_align;
+
+                  *in_tls = true;
+                }
+            }
+          else
+            {
+              // If this is the first section after the TLS segment,
+              // align it to at least the alignment of the TLS
+              // segment, so that the size of the overall TLS segment
+              // is aligned.
+              if (*in_tls)
+                {
+                  uint64_t segment_align =
+                      layout->tls_segment()->maximum_alignment();
+                  if (segment_align > align)
+                    align = segment_align;
+
+                  *in_tls = false;
+                }
+            }
+
+         off = align_address(off, align);
          (*p)->set_address_and_file_offset(addr + (off - startoff), off);
        }
       else
@@ -2555,11 +2607,10 @@ Output_segment::set_section_list_addresses(bool reset, Output_data_list* pdl,
          (*p)->finalize_data_size();
        }
 
-      // Unless this is a PT_TLS segment, 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 (this->type_ == elfcpp::PT_TLS
-         || !(*p)->is_section_flag_set(elfcpp::SHF_TLS)
+      // We want to ignore the size of a SHF_TLS or 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))
        off += (*p)->data_size();
 
@@ -2626,6 +2677,16 @@ Output_segment::set_offset()
   this->memsz_ = (last->address()
                  + last->data_size()
                  - this->vaddr_);
+
+  // If this is a TLS segment, align the memory size.  The code in
+  // set_section_list ensures that the section after the TLS segment
+  // is aligned to give us room.
+  if (this->type_ == elfcpp::PT_TLS)
+    {
+      uint64_t segment_align = this->maximum_alignment();
+      gold_assert(this->vaddr_ == align_address(this->vaddr_, segment_align));
+      this->memsz_ = align_address(this->memsz_, segment_align);
+    }
 }
 
 // Set the TLS offsets of the sections in the PT_TLS segment.
index ac812a0ab19d560c0dcbdd89e42585db59ebe359..e3945381c29943b14a637597b49013c78778b4ab 100644 (file)
@@ -2582,7 +2582,7 @@ class Output_segment
   // address of the immediately following segment.  Update *POFF and
   // *PSHNDX.  This should only be called for a PT_LOAD segment.
   uint64_t
-  set_section_addresses(bool reset, uint64_t addr, off_t* poff,
+  set_section_addresses(const Layout*, bool reset, uint64_t addr, off_t* poff,
                        unsigned int* pshndx);
 
   // Set the minimum alignment of this segment.  This may be adjusted
@@ -2638,8 +2638,9 @@ class Output_segment
 
   // Set the section addresses in an Output_data_list.
   uint64_t
-  set_section_list_addresses(bool reset, Output_data_list*, uint64_t addr,
-                            off_t* poff, unsigned int* pshndx);
+  set_section_list_addresses(const Layout*, bool reset, Output_data_list*,
+                             uint64_t addr, off_t* poff, unsigned int* pshndx,
+                             bool* in_tls);
 
   // Return the number of Output_sections in an Output_data_list.
   unsigned int
index 4a701da405bd0a116e2fe346339e85b3fb941230..418d0ea256fef191e211e78652c11e6b8abb29b3 100644 (file)
 
 __thread int v1;
 static __thread int v2;
+
+// We don't use these pointers, but putting them in tests alignment on
+// a 64-bit target.
+__thread char* p1;
+char dummy;
+__thread char* p2 = &dummy;
+
 __thread int v3 = 3;
 static __thread int v4 = 4;
 __thread int v5;