* options.cc: Include "demangle.h".
[deliverable/binutils-gdb.git] / gold / output.cc
index 622e98378621ef0b7ae1d1e444c765aa0722b22d..85cc2b257be06181fb9fe2bdbf0ea8a6a8012beb 100644 (file)
@@ -1,6 +1,6 @@
 // output.cc -- manage the output file for gold
 
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -800,7 +800,7 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
   const unsigned int lsi = this->local_sym_index_;
   section_offset_type offset;
   Output_section* os = this->u1_.relobj->output_section(lsi, &offset);
-  gold_assert(os != NULL);
+  gold_assert(os != NULL && offset != -1);
   return offset;
 }
 
@@ -851,18 +851,21 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write(
 
 template<bool dynamic, int size, bool big_endian>
 typename elfcpp::Elf_types<size>::Elf_Addr
-Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::symbol_value() const
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::symbol_value(
+    Address addend) const
 {
   if (this->local_sym_index_ == GSYM_CODE)
     {
       const Sized_symbol<size>* sym;
       sym = static_cast<const Sized_symbol<size>*>(this->u1_.gsym);
-      return sym->value();
+      return sym->value() + addend;
     }
   gold_assert(this->local_sym_index_ != SECTION_CODE
-              && this->local_sym_index_ != INVALID_CODE);
-  const Sized_relobj<size, big_endian>* relobj = this->u1_.relobj;
-  return relobj->local_symbol_value(this->local_sym_index_);
+              && this->local_sym_index_ != INVALID_CODE
+              && !this->is_section_symbol_);
+  const unsigned int lsi = this->local_sym_index_;
+  const Symbol_value<size>* symval = this->u1_.relobj->local_symbol(lsi);
+  return symval->value(this->u1_.relobj, addend);
 }
 
 // Write out a Rela relocation.
@@ -876,8 +879,8 @@ Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write(
   this->rel_.write_rel(&orel);
   Addend addend = this->addend_;
   if (this->rel_.is_relative())
-    addend += this->rel_.symbol_value();
-  if (this->rel_.is_local_section_symbol())
+    addend = this->rel_.symbol_value(addend);
+  else if (this->rel_.is_local_section_symbol())
     addend += this->rel_.local_section_offset();
   orel.put_r_addend(addend);
 }
@@ -1037,7 +1040,11 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
       break;
 
     default:
-      val = this->u_.object->local_symbol_value(this->local_sym_index_);
+      {
+        const unsigned int lsi = this->local_sym_index_;
+        const Symbol_value<size>* symval = this->u_.object->local_symbol(lsi);
+        val = symval->value(this->u_.object, 0);
+      }
       break;
     }
 
@@ -2376,6 +2383,27 @@ Output_segment::add_output_section(Output_section* os,
     pdl->push_back(os);
 }
 
+// Remove an Output_section from this segment.  It is an error if it
+// is not present.
+
+void
+Output_segment::remove_output_section(Output_section* os)
+{
+  // We only need this for SHT_PROGBITS.
+  gold_assert(os->type() == elfcpp::SHT_PROGBITS);
+  for (Output_data_list::iterator p = this->output_data_.begin();
+       p != this->output_data_.end();
+       ++p)
+   {
+     if (*p == os)
+       {
+         this->output_data_.erase(p);
+         return;
+       }
+   }
+  gold_unreachable();
+}
+
 // Add an Output_data (which is not an Output_section) to the start of
 // a segment.
 
@@ -2455,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);
@@ -2472,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
@@ -2496,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;
 
@@ -2514,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
@@ -2527,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();
 
@@ -2598,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.
This page took 0.025489 seconds and 4 git commands to generate.