2009-10-09 Doug Kwan <dougkwan@google.com>
authorDoug Kwan <dougkwan@google.com>
Fri, 9 Oct 2009 23:18:19 +0000 (23:18 +0000)
committerDoug Kwan <dougkwan@google.com>
Fri, 9 Oct 2009 23:18:19 +0000 (23:18 +0000)
* layout.cc (Layout::make_output_section): Call target hook to make
ordinary output section.
(Layout::finalize): Adjust parameter list of call the
Target::may_relax().
* layout.h (class Layout::section_list): New method.
* merge.h (Output_merge_base::entsize): Change visibility to public.
(Output_merge_base::is_string, Output_merge_base::do_is_string):
New methods.
(Output_merge_string::do_is_string): New method.
* object.cc (Sized_relobj::do_setup): renamed from
Sized_relobj::set_up.
* object.h (Sized_relobj::adjust_shndx,
Sized_relobj::initializ_input_to_output_maps,
Sized_relobj::free_input_to_output_maps): Change visibilities to
protected.
(Sized_relobj::setup): Virtualize.
(Sized_relobj::do_setup): New method declaration.
(Sized_relobj::invalidate_section_offset,
Sized_relobj::do_invalidate_section_offset): New method decfinitions.
(Sized_relobj::elf_file, Sized_relobj::local_values): New methods.
* options.cc (parse_int): New function.
* options.h (parse_int): New declaration.
(DEFINE_int): New macro.
(stub_group_size): New option.
* output.cc (Output_section::Output_section): Initialize memebers
merge_section_map_, merge_section_by_properties_map_,
relaxed_input_section_map_, is_relaxed_input_section_map_valid_.
(Output_section::add_input_section): Handled deferred code-fill
generation and remove an old comment.
(Output_section::add_relaxed_input_section): New method definition.
(Output_section::add_merge_input_section): Use merge section by
properties map to speed to search.  Update merge section maps
as appropriate.
(Output_section::build_relaxation_map): New method definition.
(Output_section::convert_input_sections_in_list_to_relaxed_sections):
Same.
(Output_section::relax_input_section): Renamed to
Output_section::convert_input_sections_to_relaxed_sections and change
interface to take a vector of pointers to relaxed sections.
(Output_section::find_merge_section,
Output_section::find_relaxed_input_section): New method definitions.
(Output_section::is_input_address_mapped,
Output_section::output_offset, Output_section::output_address):
Use output section data maps to speed up searching.
(Output_section::find_starting_output_address): Add comments.
(Output_section::do_write,
Output_section::write_to_postprocessing_buffer): Do code-fill
generation as appropriate.
(Output_section::get_input_sections): Invalidate relaxed input section
map.
(Output_section::restore_states): Adjust type of checkpoint .
Invalidate relaxed input section map.
* output.h (Output_merge_base): New class declaration.
(Input_section_specifier): New class defintion.
(class Output_relaxed_input_section) Change base class to
Output_section_data_build.
(Output_relaxed_input_section::Output_relaxed_input_section): Adjust
base class initializer.
(Output_section::add_relaxed_input_section): New method declaration.
(Output_section::Input_section): Change visibility to protected.
      (Output_section::Input_section::relobj,
Output_section::Input_section::shndx): Handle relaxed input sections.
Output_section::input_sections) Change visibility to protected.  Also
define overload to return a non-const pointer.
(Output_section::Merge_section_properties): New class defintion.
(Output_section::Merge_section_by_properties_map,
Output_section::Output_section_data_by_input_section_map,
Output_section::Relaxation_map): New types.
(Output_section::relax_input_section): Rename method to
Output_section::convert_input_sections_to_relaxed_sections and change
interface to take a vector of relaxed section pointers.
(Output_section::find_merge_section,
Output_section::find_relaxed_input_section,
Output_section::build_relaxation_map,
Output_section::convert_input_sections_in_list_to_relaxed_sections):
New method declarations.
(Output_section::merge_section_map_
Output_section::merge_section_by_properties_map_,
Output_section::relaxed_input_section_map_,
Output_section::is_relaxed_input_section_map_valid_,
Output_section::generate_code_fills_at_write_): New data members.
* script-sections.cc
(Output_section_element_input::set_section_addresses): Call
current_data_size and addralign methods of relaxed input sections.
(Orphan_output_section::set_section_addresses): Call current_data_size
and addralign methods of relaxed input sections.
* symtab.cc (Symbol_table::compute_final_value): Extract template
from the body of Symbol_table::sized_finalize_symbol.
(Symbol_table::sized_finalized_symbol): Call
Symbol_table::compute_final_value.
* symtab.h (Symbol_table::Compute_final_value_status): New enum type.
(Symbol_table::compute_final_value): New templated method declaration.
* target.cc (Target::do_make_output_section): New method defintion.
* target.h (Target::make_output_section): New method declaration.
(Target::relax): Add more parameters for input objects, symbol table
and layout.  Adjust call to do_relax.
(Target::do_make_output_section): New method declaration.
(Target::do_relax): Add parameters for input objects, symbol table
and layout.

15 files changed:
gold/ChangeLog
gold/layout.cc
gold/layout.h
gold/merge.h
gold/object.cc
gold/object.h
gold/options.cc
gold/options.h
gold/output.cc
gold/output.h
gold/script-sections.cc
gold/symtab.cc
gold/symtab.h
gold/target.cc
gold/target.h

index eb37d39dc632c00904d625328f2d0daa8b5c7806..2b31fa68334816277fded54ef85a4bd633f3f539 100644 (file)
@@ -1,3 +1,105 @@
+2009-10-09  Doug Kwan  <dougkwan@google.com>
+
+       * layout.cc (Layout::make_output_section): Call target hook to make
+       ordinary output section.
+       (Layout::finalize): Adjust parameter list of call the
+       Target::may_relax().
+       * layout.h (class Layout::section_list): New method.
+       * merge.h (Output_merge_base::entsize): Change visibility to public.
+       (Output_merge_base::is_string, Output_merge_base::do_is_string):
+       New methods.
+       (Output_merge_string::do_is_string): New method.
+       * object.cc (Sized_relobj::do_setup): renamed from
+       Sized_relobj::set_up.
+       * object.h (Sized_relobj::adjust_shndx,
+       Sized_relobj::initializ_input_to_output_maps,
+       Sized_relobj::free_input_to_output_maps): Change visibilities to
+       protected.
+       (Sized_relobj::setup): Virtualize.
+       (Sized_relobj::do_setup): New method declaration.
+       (Sized_relobj::invalidate_section_offset,
+       Sized_relobj::do_invalidate_section_offset): New method decfinitions.
+       (Sized_relobj::elf_file, Sized_relobj::local_values): New methods.
+       * options.cc (parse_int): New function.
+       * options.h (parse_int): New declaration.
+       (DEFINE_int): New macro.
+       (stub_group_size): New option.
+       * output.cc (Output_section::Output_section): Initialize memebers
+       merge_section_map_, merge_section_by_properties_map_,
+       relaxed_input_section_map_, is_relaxed_input_section_map_valid_.
+       (Output_section::add_input_section): Handled deferred code-fill
+       generation and remove an old comment.
+       (Output_section::add_relaxed_input_section): New method definition.
+       (Output_section::add_merge_input_section): Use merge section by
+       properties map to speed to search.  Update merge section maps
+       as appropriate.
+       (Output_section::build_relaxation_map): New method definition.
+       (Output_section::convert_input_sections_in_list_to_relaxed_sections):
+       Same.
+       (Output_section::relax_input_section): Renamed to
+       Output_section::convert_input_sections_to_relaxed_sections and change
+       interface to take a vector of pointers to relaxed sections.
+       (Output_section::find_merge_section,
+       Output_section::find_relaxed_input_section): New method definitions.
+       (Output_section::is_input_address_mapped,
+       Output_section::output_offset, Output_section::output_address):
+       Use output section data maps to speed up searching.
+       (Output_section::find_starting_output_address): Add comments.
+       (Output_section::do_write,
+       Output_section::write_to_postprocessing_buffer): Do code-fill
+       generation as appropriate.
+       (Output_section::get_input_sections): Invalidate relaxed input section
+       map.
+       (Output_section::restore_states): Adjust type of checkpoint .
+       Invalidate relaxed input section map.
+       * output.h (Output_merge_base): New class declaration.
+       (Input_section_specifier): New class defintion.
+       (class Output_relaxed_input_section) Change base class to
+       Output_section_data_build.
+       (Output_relaxed_input_section::Output_relaxed_input_section): Adjust
+       base class initializer.
+       (Output_section::add_relaxed_input_section): New method declaration.
+       (Output_section::Input_section): Change visibility to protected.
+       (Output_section::Input_section::relobj,
+       Output_section::Input_section::shndx): Handle relaxed input sections.
+       Output_section::input_sections) Change visibility to protected.  Also
+       define overload to return a non-const pointer.
+       (Output_section::Merge_section_properties): New class defintion.
+       (Output_section::Merge_section_by_properties_map,
+       Output_section::Output_section_data_by_input_section_map,
+       Output_section::Relaxation_map): New types.
+       (Output_section::relax_input_section): Rename method to
+       Output_section::convert_input_sections_to_relaxed_sections and change
+       interface to take a vector of relaxed section pointers.
+       (Output_section::find_merge_section,
+       Output_section::find_relaxed_input_section,
+       Output_section::build_relaxation_map,
+       Output_section::convert_input_sections_in_list_to_relaxed_sections):
+       New method declarations.
+       (Output_section::merge_section_map_
+       Output_section::merge_section_by_properties_map_,
+       Output_section::relaxed_input_section_map_,
+       Output_section::is_relaxed_input_section_map_valid_,
+       Output_section::generate_code_fills_at_write_): New data members.
+       * script-sections.cc
+       (Output_section_element_input::set_section_addresses): Call
+       current_data_size and addralign methods of relaxed input sections.
+       (Orphan_output_section::set_section_addresses): Call current_data_size
+       and addralign methods of relaxed input sections.
+       * symtab.cc (Symbol_table::compute_final_value): Extract template
+       from the body of Symbol_table::sized_finalize_symbol.
+       (Symbol_table::sized_finalized_symbol): Call
+       Symbol_table::compute_final_value.
+       * symtab.h (Symbol_table::Compute_final_value_status): New enum type.
+       (Symbol_table::compute_final_value): New templated method declaration.
+       * target.cc (Target::do_make_output_section): New method defintion.
+       * target.h (Target::make_output_section): New method declaration.
+       (Target::relax): Add more parameters for input objects, symbol table
+       and layout.  Adjust call to do_relax.
+       (Target::do_make_output_section): New method declaration.
+       (Target::do_relax): Add parameters for input objects, symbol table
+       and layout.
+
 2009-10-09  Andrew Pinski  <andrew_pinski@playstation.sony.com>
 
        * pread.c: Include stdio.h.
index e7d63777f896c7f5c22d55d65acee82466a39d7b..0e26116bcc84279730ce94ee34101d3399b0e945 100644 (file)
@@ -870,7 +870,11 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
         this->debug_info_->set_abbreviations(this->debug_abbrev_);
     }
  else
-    os = new Output_section(name, type, flags);
+    {
+      // FIXME: const_cast is ugly.
+      Target* target = const_cast<Target*>(&parameters->target());
+      os = target->make_output_section(name, type, flags);
+    }
 
   parameters->target().new_output_section(os);
 
@@ -1592,7 +1596,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
                                       &shndx);
       pass++;
     }
-  while (target->may_relax() && target->relax(pass));
+  while (target->may_relax()
+        && target->relax(pass, input_objects, symtab, this));
 
   // Set the file offsets of all the non-data sections we've seen so
   // far which don't have to wait for the input sections.  We need
index 88561258c03535ecb33dcf1e082f88ecbfda6042..675c65813b8bd0b4aa9b91ddaf9f2ba3acc7c2b6 100644 (file)
@@ -602,6 +602,11 @@ class Layout
       this->script_output_section_data_list_.push_back(posd);
   }
 
+  // Return section list.
+  const Section_list&
+  section_list() const
+  { return this->section_list_; }
+
  private:
   Layout(const Layout&);
   Layout& operator=(const Layout&);
index fb6721d2925da70c63a5f5e2f1c785af8fec1cb6..345b1154ebe17e6b95e847867222675b6ee46e0f 100644 (file)
@@ -219,6 +219,17 @@ class Output_merge_base : public Output_section_data
     : Output_section_data(addralign), merge_map_(), entsize_(entsize)
   { }
 
+  // Return the entry size.
+  uint64_t
+  entsize() const
+  { return this->entsize_; }
+
+  // Whether this is a merge string section.  This is only true of
+  // Output_merge_string.
+  bool
+  is_string()
+  { return this->do_is_string(); }
+
  protected:
   // Return the output offset for an input offset.
   bool
@@ -230,11 +241,6 @@ class Output_merge_base : public Output_section_data
   bool
   do_is_merge_section_for(const Relobj*, unsigned int shndx) const;
 
-  // Return the entry size.
-  uint64_t
-  entsize() const
-  { return this->entsize_; }
-
   // Add a mapping from an OFFSET in input section SHNDX in object
   // OBJECT to an OUTPUT_OFFSET in the output section.  OUTPUT_OFFSET
   // is the offset from the start of the merged data in the output
@@ -246,6 +252,11 @@ class Output_merge_base : public Output_section_data
     this->merge_map_.add_mapping(object, shndx, offset, length, output_offset);
   }
 
+  // This may be overriden by the child class.
+  virtual bool
+  do_is_string()
+  { return false; }
+
  private:
   // A mapping from input object/section/offset to offset in output
   // section.
@@ -424,6 +435,11 @@ class Output_merge_string : public Output_merge_base
   clear_stringpool()
   { this->stringpool_.clear(); }
 
+  // Whether this is a merge string section.
+  virtual bool
+  do_is_string()
+  { return true; }
+
  private:
   // The name of the string type, for stats.
   const char*
index b8d9eb84f82612414fc589c32a41c028dfd5dd3d..e09a71fca244034a34075e915e99adeb430183e9 100644 (file)
@@ -359,7 +359,7 @@ Sized_relobj<size, big_endian>::~Sized_relobj()
 
 template<int size, bool big_endian>
 void
-Sized_relobj<size, big_endian>::setup()
+Sized_relobj<size, big_endian>::do_setup()
 {
   const unsigned int shnum = this->elf_file_.shnum();
   this->set_shnum(shnum);
index bbc1a106e46fd2efe63d7104870f2c03be586509..66f5dbbd6c4b21b89c4f8380bd25c3af4cbb5522 100644 (file)
@@ -1324,7 +1324,8 @@ class Sized_relobj : public Relobj
 
   // Set up the object file based on TARGET.
   void
-  setup();
+  setup()
+  { this->do_setup(); }
 
   // Return the number of symbols.  This is only valid after
   // Object::add_symbols has been called.
@@ -1462,7 +1463,16 @@ class Sized_relobj : public Relobj
   Address
   map_to_kept_section(unsigned int shndx, bool* found) const;
 
+  // Make section offset invalid.  This is needed for relaxation.
+  void
+  invalidate_section_offset(unsigned int shndx)
+  { this->do_invalidate_section_offset(shndx); }
+
  protected:
+  // Set up.
+  virtual void
+  do_setup();
+
   // Read the symbols.
   void
   do_read_symbols(Read_symbols_data*);
@@ -1596,6 +1606,48 @@ class Sized_relobj : public Relobj
     this->section_offsets_[shndx] = convert_types<Address, uint64_t>(off);
   }
 
+  // Set the offset of a section to invalid_address.
+  virtual void
+  do_invalidate_section_offset(unsigned int shndx)
+  {
+    gold_assert(shndx < this->section_offsets_.size());
+    this->section_offsets_[shndx] = invalid_address;
+  }
+
+  // Adjust a section index if necessary.
+  unsigned int
+  adjust_shndx(unsigned int shndx)
+  {
+    if (shndx >= elfcpp::SHN_LORESERVE)
+      shndx += this->elf_file_.large_shndx_offset();
+    return shndx;
+  }
+
+  // Initialize input to output maps for section symbols in merged
+  // sections.
+  void
+  initialize_input_to_output_maps();
+
+  // Free the input to output maps for section symbols in merged
+  // sections.
+  void
+  free_input_to_output_maps();
+
+  // Return symbol table section index.
+  unsigned int
+  symtab_shndx() const
+  { return this->symtab_shndx_; }
+
+  // Allow a child class to access the ELF file.
+  elfcpp::Elf_file<size, big_endian, Object>*
+  elf_file()
+  { return &this->elf_file_; }
+  
+  // Allow a child class to access the local values.
+  Local_values*
+  local_values()
+  { return &this->local_values_; }
+
  private:
   // For convenience.
   typedef Sized_relobj<size, big_endian> This;
@@ -1618,15 +1670,6 @@ class Sized_relobj : public Relobj
   typedef std::map<unsigned int, Kept_comdat_section>
       Kept_comdat_section_table;
 
-  // Adjust a section index if necessary.
-  unsigned int
-  adjust_shndx(unsigned int shndx)
-  {
-    if (shndx >= elfcpp::SHN_LORESERVE)
-      shndx += this->elf_file_.large_shndx_offset();
-    return shndx;
-  }
-
   // Find the SHT_SYMTAB section, given the section headers.
   void
   find_symtab(const unsigned char* pshdrs);
@@ -1742,16 +1785,6 @@ class Sized_relobj : public Relobj
   find_functions(const unsigned char* pshdrs, unsigned int shndx,
                 Function_offsets*);
 
-  // Initialize input to output maps for section symbols in merged
-  // sections.
-  void
-  initialize_input_to_output_maps();
-
-  // Free the input to output maps for section symbols in merged
-  // sections.
-  void
-  free_input_to_output_maps();
-
   // Write out the local symbols.
   void
   write_local_symbols(Output_file*,
index bf3eb55574bfbd19ef061f70268481f73ea423c7..1c0383a8d689c4ced256449d8b0aa262a051615d 100644 (file)
@@ -194,6 +194,16 @@ parse_uint(const char* option_name, const char* arg, int* retval)
                option_name, arg);
 }
 
+void
+parse_int(const char* option_name, const char* arg, int* retval)
+{
+  char* endptr;
+  *retval = strtol(arg, &endptr, 0);
+  if (*endptr != '\0')
+    gold_fatal(_("%s: invalid option value (expected an integer): %s"),
+               option_name, arg);
+}
+
 void
 parse_uint64(const char* option_name, const char* arg, uint64_t *retval)
 {
index f590630731333e2a72a65990fd6e1b56a0e603cf..7266a96cf46fbba54418379042b8a438a57a73cf 100644 (file)
@@ -82,6 +82,9 @@ typedef Unordered_set<std::string> String_set;
 extern void
 parse_bool(const char* option_name, const char* arg, bool* retval);
 
+extern void
+parse_int(const char* option_name, const char* arg, int* retval);
+
 extern void
 parse_uint(const char* option_name, const char* arg, int* retval);
 
@@ -333,6 +336,12 @@ struct Struct_special : public Struct_var
   };                                                                     \
   Struct_disable_##varname__ disable_##varname__##_initializer_
 
+#define DEFINE_int(varname__, dashes__, shortname__, default_value__,   \
+                   helpstring__, helparg__)                             \
+  DEFINE_var(varname__, dashes__, shortname__, default_value__,         \
+             #default_value__, helpstring__, helparg__, false,         \
+             int, int, options::parse_int)
+
 #define DEFINE_uint(varname__, dashes__, shortname__, default_value__,  \
                    helpstring__, helparg__)                             \
   DEFINE_var(varname__, dashes__, shortname__, default_value__,         \
@@ -802,6 +811,12 @@ class General_options
   DEFINE_bool(strip_lto_sections, options::TWO_DASHES, '\0', true,
               N_("Strip LTO intermediate code sections"), NULL);
 
+  DEFINE_int(stub_group_size, options::TWO_DASHES , '\0', 1,
+             N_("(ARM only) The maximum distance from instructions in a group "
+               "of sections to their stubs.  Negative values mean stubs "
+               "are always after the group. 1 means using default size.\n"),
+            N_("SIZE"));
+
   DEFINE_bool(no_keep_memory, options::TWO_DASHES, '\0', false,
               N_("Use less memory and more disk I/O "
                  "(included only for compatibility with GNU ld)"), NULL);
index e3b11714e8fb64ddfe87ca4a50201042e9cdbed0..7d869b3326e0d6a0359b1cf978fe91d8a1bfc989 100644 (file)
@@ -1801,7 +1801,12 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     is_small_section_(false),
     is_large_section_(false),
     tls_offset_(0),
-    checkpoint_(NULL)
+    checkpoint_(NULL),
+    merge_section_map_(),
+    merge_section_by_properties_map_(),
+    relaxed_input_section_map_(),
+    is_relaxed_input_section_map_valid_(true),
+    generate_code_fills_at_write_(false)
 {
   // An unallocated section has no address.  Forcing this means that
   // we don't need special treatment for symbols defined in debug
@@ -1892,7 +1897,21 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
   off_t aligned_offset_in_section = align_address(offset_in_section,
                                                   addralign);
 
+  // Determine if we want to delay code-fill generation until the output
+  // section is written.  When the target is relaxing, we want to delay fill
+  // generating to avoid adjusting them during relaxation.
+  if (!this->generate_code_fills_at_write_
+      && !have_sections_script
+      && (sh_flags & elfcpp::SHF_EXECINSTR) != 0
+      && parameters->target().has_code_fill()
+      && parameters->target().may_relax())
+    {
+      gold_assert(this->fills_.empty());
+      this->generate_code_fills_at_write_ = true;
+    }
+
   if (aligned_offset_in_section > offset_in_section
+      && !this->generate_code_fills_at_write_
       && !have_sections_script
       && (sh_flags & elfcpp::SHF_EXECINSTR) != 0
       && parameters->target().has_code_fill())
@@ -1905,8 +1924,6 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
         this->fills_.push_back(Fill(offset_in_section, fill_len));
       else
         {
-          // FIXME: When relaxing, the size needs to adjust to
-          // maintain a constant alignment.
           std::string fill_data(parameters->target().code_fill(fill_len));
           Output_data_const* odc = new Output_data_const(fill_data, 1);
           this->input_sections_.push_back(Input_section(odc));
@@ -1951,6 +1968,31 @@ Output_section::add_output_section_data(Output_section_data* posd)
     }
 }
 
+// Add a relaxed input section.
+
+void
+Output_section::add_relaxed_input_section(Output_relaxed_input_section* poris)
+{
+  Input_section inp(poris);
+  this->add_output_section_data(&inp);
+  if (this->is_relaxed_input_section_map_valid_)
+    {
+      Input_section_specifier iss(poris->relobj(), poris->shndx());
+      this->relaxed_input_section_map_[iss] = poris;
+    }
+
+  // For a relaxed section, we use the current data size.  Linker scripts
+  // get all the input sections, including relaxed one from an output
+  // section and add them back to them same output section to compute the
+  // output section size.  If we do not account for sizes of relaxed input
+  // sections,  an output section would be incorrectly sized.
+  off_t offset_in_section = this->current_data_size_for_child();
+  off_t aligned_offset_in_section = align_address(offset_in_section,
+                                                 poris->addralign());
+  this->set_current_data_size_for_child(aligned_offset_in_section
+                                       + poris->current_data_size());
+}
+
 // Add arbitrary data to an output section by Input_section.
 
 void
@@ -1995,73 +2037,151 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
   // We cannot restore merged input section states.
   gold_assert(this->checkpoint_ == NULL);
 
-  Input_section_list::iterator p;
-  for (p = this->input_sections_.begin();
-       p != this->input_sections_.end();
-       ++p)
-    if (p->is_merge_section(is_string, entsize, addralign))
-      {
-        p->add_input_section(object, shndx);
-        return true;
-      }
+  // Look up merge sections by required properties.
+  Merge_section_properties msp(is_string, entsize, addralign);
+  Merge_section_by_properties_map::const_iterator p =
+    this->merge_section_by_properties_map_.find(msp);
+  if (p != this->merge_section_by_properties_map_.end())
+    {
+      Output_merge_base* merge_section = p->second;
+      merge_section->add_input_section(object, shndx);
+      gold_assert(merge_section->is_string() == is_string
+                 && merge_section->entsize() == entsize
+                 && merge_section->addralign() == addralign);
+
+      // Link input section to found merge section.
+      Input_section_specifier iss(object, shndx);
+      this->merge_section_map_[iss] = merge_section;
+      return true;
+    }
 
   // We handle the actual constant merging in Output_merge_data or
   // Output_merge_string_data.
-  Output_section_data* posd;
+  Output_merge_base* pomb;
   if (!is_string)
-    posd = new Output_merge_data(entsize, addralign);
+    pomb = new Output_merge_data(entsize, addralign);
   else
     {
       switch (entsize)
        {
         case 1:
-         posd = new Output_merge_string<char>(addralign);
+         pomb = new Output_merge_string<char>(addralign);
          break;
         case 2:
-         posd = new Output_merge_string<uint16_t>(addralign);
+         pomb = new Output_merge_string<uint16_t>(addralign);
          break;
         case 4:
-         posd = new Output_merge_string<uint32_t>(addralign);
+         pomb = new Output_merge_string<uint32_t>(addralign);
          break;
         default:
          return false;
        }
     }
 
-  this->add_output_merge_section(posd, is_string, entsize);
-  posd->add_input_section(object, shndx);
+  // Add new merge section to this output section and link merge section
+  // properties to new merge section in map.
+  this->add_output_merge_section(pomb, is_string, entsize);
+  this->merge_section_by_properties_map_[msp] = pomb;
+
+  // Add input section to new merge section and link input section to new
+  // merge section in map.
+  pomb->add_input_section(object, shndx);
+  Input_section_specifier iss(object, shndx);
+  this->merge_section_map_[iss] = pomb;
 
   return true;
 }
 
-// Relax an existing input section.
+// Build a relaxation map to speed up relaxation of existing input sections.
+// Look up to the first LIMIT elements in INPUT_SECTIONS.
+
 void
-Output_section::relax_input_section(Output_relaxed_input_section *psection)
+Output_section::build_relaxation_map(
+  const Input_section_list& input_sections,
+  size_t limit,
+  Relaxation_map* relaxation_map) const
 {
-  Relobj* relobj = psection->relobj();
-  unsigned int shndx = psection->shndx();
+  for (size_t i = 0; i < limit; ++i)
+    {
+      const Input_section& is(input_sections[i]);
+      if (is.is_input_section() || is.is_relaxed_input_section())
+       {
+         Input_section_specifier iss(is.relobj(), is.shndx());
+         (*relaxation_map)[iss] = i;
+       }
+    }
+}
+
+// Convert regular input sections in INPUT_SECTIONS into relaxed input
+// sections in RELAXED_SECTIONS.  MAP is a prebuilt map from input section
+// specifier to indices of INPUT_SECTIONS.
+
+void
+Output_section::convert_input_sections_in_list_to_relaxed_sections(
+  const std::vector<Output_relaxed_input_section*>& relaxed_sections,
+  const Relaxation_map& map,
+  Input_section_list* input_sections)
+{
+  for (size_t i = 0; i < relaxed_sections.size(); ++i)
+    {
+      Output_relaxed_input_section* poris = relaxed_sections[i];
+      Input_section_specifier iss(poris->relobj(), poris->shndx());
+      Relaxation_map::const_iterator p = map.find(iss);
+      gold_assert(p != map.end());
+      gold_assert((*input_sections)[p->second].is_input_section());
+      (*input_sections)[p->second] = Input_section(poris);
+    }
+}
+  
+// Convert regular input sections into relaxed input sections. RELAXED_SECTIONS
+// is a vector of pointers to Output_relaxed_input_section or its derived
+// classes.  The relaxed sections must correspond to existing input sections.
 
+void
+Output_section::convert_input_sections_to_relaxed_sections(
+  const std::vector<Output_relaxed_input_section*>& relaxed_sections)
+{
   gold_assert(parameters->target().may_relax());
 
-  // This is not very efficient if we a going to relax a number of sections
-  // in an Output_section with lot of Input_sections.
-  for (Input_section_list::iterator p = this->input_sections_.begin();
-       p != this->input_sections_.end();
-       ++p)
+  // We want to make sure that restore_states does not undo the effect of
+  // this.  If there is no checkpoint active, just search the current
+  // input section list and replace the sections there.  If there is
+  // a checkpoint, also replace the sections there.
+  
+  // By default, we look at the whole list.
+  size_t limit = this->input_sections_.size();
+
+  if (this->checkpoint_ != NULL)
     {
-      if (p->is_input_section())
+      // Replace input sections with relaxed input section in the saved
+      // copy of the input section list.
+      if (this->checkpoint_->input_sections_saved())
        {
-         if (p->relobj() == relobj && p->shndx() == shndx)
-           {
-             gold_assert(p->addralign() == psection->addralign());
-             *p = Input_section(psection);
-             return;
-           }
+         Relaxation_map map;
+         this->build_relaxation_map(
+                   *(this->checkpoint_->input_sections()),
+                   this->checkpoint_->input_sections()->size(),
+                   &map);
+         this->convert_input_sections_in_list_to_relaxed_sections(
+                   relaxed_sections,
+                   map,
+                   this->checkpoint_->input_sections());
+       }
+      else
+       {
+         // We have not copied the input section list yet.  Instead, just
+         // look at the portion that would be saved.
+         limit = this->checkpoint_->input_sections_size();
        }
-      else if (p->is_relaxed_input_section())
-       gold_assert(p->relobj() != relobj || p->shndx() != shndx);
-
     }
+
+  // Convert input sections in input_section_list.
+  Relaxation_map map;
+  this->build_relaxation_map(this->input_sections_, limit, &map);
+  this->convert_input_sections_in_list_to_relaxed_sections(
+           relaxed_sections,
+           map,
+           &this->input_sections_);
 }
 
 // Update the output section flags based on input section flags.
@@ -2082,6 +2202,60 @@ Output_section::update_flags_for_input_section(elfcpp::Elf_Xword flags)
                      | elfcpp::SHF_EXECINSTR));
 }
 
+// Find the merge section into which an input section with index SHNDX in
+// OBJECT has been added.  Return NULL if none found.
+
+Output_section_data*
+Output_section::find_merge_section(const Relobj* object,
+                                  unsigned int shndx) const
+{
+  Input_section_specifier iss(object, shndx);
+  Output_section_data_by_input_section_map::const_iterator p =
+    this->merge_section_map_.find(iss);
+  if (p != this->merge_section_map_.end())
+    {
+      Output_section_data* posd = p->second;
+      gold_assert(posd->is_merge_section_for(object, shndx));
+      return posd;
+    }
+  else
+    return NULL;
+}
+
+// Find an relaxed input section corresponding to an input section
+// in OBJECT with index SHNDX.
+
+const Output_section_data*
+Output_section::find_relaxed_input_section(const Relobj* object,
+                                          unsigned int shndx) const
+{
+  // Be careful that the map may not be valid due to input section export
+  // to scripts or a check-point restore.
+  if (!this->is_relaxed_input_section_map_valid_)
+    {
+      // Rebuild the map as needed.
+      this->relaxed_input_section_map_.clear();
+      for (Input_section_list::const_iterator p = this->input_sections_.begin();
+          p != this->input_sections_.end();
+          ++p)
+       if (p->is_relaxed_input_section())
+         {
+           Input_section_specifier iss(p->relobj(), p->shndx());
+           this->relaxed_input_section_map_[iss] =
+             p->relaxed_input_section();
+         }
+      this->is_relaxed_input_section_map_valid_ = true;
+    }
+
+  Input_section_specifier iss(object, shndx);
+  Output_section_data_by_input_section_map::const_iterator p =
+    this->relaxed_input_section_map_.find(iss);
+  if (p != this->relaxed_input_section_map_.end())
+    return p->second;
+  else
+    return NULL;
+}
+
 // Given an address OFFSET relative to the start of input section
 // SHNDX in OBJECT, return whether this address is being included in
 // the final link.  This should only be called if SHNDX in OBJECT has
@@ -2092,6 +2266,20 @@ Output_section::is_input_address_mapped(const Relobj* object,
                                        unsigned int shndx,
                                        off_t offset) const
 {
+  // Look at the Output_section_data_maps first.
+  const Output_section_data* posd = this->find_merge_section(object, shndx);
+  if (posd == NULL)
+    posd = this->find_relaxed_input_section(object, shndx);
+
+  if (posd != NULL)
+    {
+      section_offset_type output_offset;
+      bool found = posd->output_offset(object, shndx, offset, &output_offset);
+      gold_assert(found);   
+      return output_offset != -1;
+    }
+
+  // Fall back to the slow look-up.
   for (Input_section_list::const_iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
@@ -2116,9 +2304,23 @@ section_offset_type
 Output_section::output_offset(const Relobj* object, unsigned int shndx,
                              section_offset_type offset) const
 {
-  // This can only be called meaningfully when layout is complete.
-  gold_assert(Output_data::is_layout_complete());
+  // This can only be called meaningfully when we know the data size
+  // of this.
+  gold_assert(this->is_data_size_valid());
 
+  // Look at the Output_section_data_maps first.
+  const Output_section_data* posd = this->find_merge_section(object, shndx);
+  if (posd == NULL) 
+    posd = this->find_relaxed_input_section(object, shndx);
+  if (posd != NULL)
+    {
+      section_offset_type output_offset;
+      bool found = posd->output_offset(object, shndx, offset, &output_offset);
+      gold_assert(found);   
+      return output_offset;
+    }
+
+  // Fall back to the slow look-up.
   for (Input_section_list::const_iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
@@ -2138,6 +2340,20 @@ Output_section::output_address(const Relobj* object, unsigned int shndx,
                               off_t offset) const
 {
   uint64_t addr = this->address() + this->first_input_offset_;
+
+  // Look at the Output_section_data_maps first.
+  const Output_section_data* posd = this->find_merge_section(object, shndx);
+  if (posd == NULL) 
+    posd = this->find_relaxed_input_section(object, shndx);
+  if (posd != NULL && posd->is_address_valid())
+    {
+      section_offset_type output_offset;
+      bool found = posd->output_offset(object, shndx, offset, &output_offset);
+      gold_assert(found);
+      return posd->address() + output_offset;
+    }
+
+  // Fall back to the slow look-up.
   for (Input_section_list::const_iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
@@ -2169,6 +2385,9 @@ Output_section::find_starting_output_address(const Relobj* object,
                                             unsigned int shndx,
                                             uint64_t* paddr) const
 {
+  // FIXME: This becomes a bottle-neck if we have many relaxed sections.
+  // Looking up the merge section map does not always work as we sometimes
+  // find a merge section without its address set.
   uint64_t addr = this->address() + this->first_input_offset_;
   for (Input_section_list::const_iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
@@ -2532,6 +2751,9 @@ Output_section::do_write(Output_file* of)
 {
   gold_assert(!this->requires_postprocessing());
 
+  // If the target performs relaxation, we delay filler generation until now.
+  gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty());
+
   off_t output_section_file_offset = this->offset();
   for (Fill_list::iterator p = this->fills_.begin();
        p != this->fills_.end();
@@ -2542,10 +2764,22 @@ Output_section::do_write(Output_file* of)
                fill_data.data(), fill_data.size());
     }
 
+  off_t off = this->offset() + this->first_input_offset_;
   for (Input_section_list::iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
-    p->write(of);
+    {
+      off_t aligned_off = align_address(off, p->addralign());
+      if (this->generate_code_fills_at_write_ && (off != aligned_off))
+       {
+         size_t fill_len = aligned_off - off;
+         std::string fill_data(parameters->target().code_fill(fill_len));
+         of->write(off, fill_data.data(), fill_data.size());
+       }
+
+      p->write(of);
+      off = aligned_off + p->data_size();
+    }
 }
 
 // If a section requires postprocessing, create the buffer to use.
@@ -2586,6 +2820,9 @@ Output_section::write_to_postprocessing_buffer()
 {
   gold_assert(this->requires_postprocessing());
 
+  // If the target performs relaxation, we delay filler generation until now.
+  gold_assert(!this->generate_code_fills_at_write_ || this->fills_.empty());
+
   unsigned char* buffer = this->postprocessing_buffer();
   for (Fill_list::iterator p = this->fills_.begin();
        p != this->fills_.end();
@@ -2601,9 +2838,16 @@ Output_section::write_to_postprocessing_buffer()
        p != this->input_sections_.end();
        ++p)
     {
-      off = align_address(off, p->addralign());
-      p->write_to_buffer(buffer + off);
-      off += p->data_size();
+      off_t aligned_off = align_address(off, p->addralign());
+      if (this->generate_code_fills_at_write_ && (off != aligned_off))
+       {
+         size_t fill_len = aligned_off - off;
+         std::string fill_data(parameters->target().code_fill(fill_len));
+         memcpy(buffer + off, fill_data.data(), fill_data.size());
+       }
+
+      p->write_to_buffer(buffer + aligned_off);
+      off = aligned_off + p->data_size();
     }
 }
 
@@ -2627,6 +2871,9 @@ Output_section::get_input_sections(
       && !this->checkpoint_->input_sections_saved())
     this->checkpoint_->save_input_sections();
 
+  // Invalidate the relaxed input section map.
+  this->is_relaxed_input_section_map_valid_ = false;
+
   uint64_t orig_address = address;
 
   address = align_address(address, this->addralign());
@@ -2738,11 +2985,15 @@ Output_section::restore_states()
       // extremely large output with hundreads of thousands of input
       // objects.  We may need to re-think how we should pass sections
       // to scripts.
-      this->input_sections_ = checkpoint->input_sections();
+      this->input_sections_ = *checkpoint->input_sections();
     }
 
   this->attached_input_sections_are_sorted_ =
     checkpoint->attached_input_sections_are_sorted();
+
+  // Simply invalidate the relaxed input section map since we do not keep
+  // track of it.
+  this->is_relaxed_input_section_map_valid_ = false;
 }
 
 // Print to the map file.
index 377864cddfd2428f459ef5046e22d859587ae073..bc109509cf82e3bd13ed9ff45a01ce644e2c61ae 100644 (file)
@@ -38,6 +38,7 @@ class General_options;
 class Object;
 class Symbol;
 class Output_file;
+class Output_merge_base;
 class Output_section;
 class Relocatable_relocs;
 class Target;
@@ -46,6 +47,71 @@ class Sized_target;
 template<int size, bool big_endian>
 class Sized_relobj;
 
+// This class specifies an input section.  It is used as a key type
+// for maps.
+
+class Input_section_specifier
+{
+ public:
+  Input_section_specifier(const Relobj* relobj, unsigned int shndx)
+    : relobj_(relobj), shndx_(shndx)
+  { }
+   
+  // Return Relobj of this.
+  const Relobj*
+  relobj() const
+  { return this->relobj_; }
+
+  // Return section index of this.
+  unsigned int
+  shndx() const
+  { return this->shndx_; }
+
+  // Whether this equals to another specifier ISS.
+  bool
+  eq(const Input_section_specifier& iss) const
+  { return this->relobj_ == iss.relobj_ && this->shndx_ == iss.shndx_; }
+
+  // Compute a hash value of this.
+  size_t
+  hash_value() const
+  { return this->string_hash(this->relobj_->name().c_str()) ^ this->shndx_; }
+
+  // Functors for containers.
+  struct equal_to
+  {
+    bool
+    operator()(const Input_section_specifier& iss1,
+              const Input_section_specifier& iss2) const
+    { return iss1.eq(iss2); }
+  };
+  struct hash
+  {
+    size_t
+    operator()(const Input_section_specifier& iss) const
+    { return iss.hash_value(); }
+  };
+
+ private:
+  // For portability, we use our own string hash function instead of assuming
+  // __gnu_cxx::hash or std::tr1::hash is available.  This is the same hash
+  // function used in Stringpool_template::string_hash.
+  static size_t
+  string_hash(const char* s)
+  {
+    size_t h = 5381;
+    while (*s != '\0')
+      h = h * 33 + *s++;
+    return h;
+  }
+
+  // An object.
+  const Relobj* relobj_;
+  // A section index. 
+  unsigned int shndx_;
+};
+
 // An abtract class for data which has to go into the output file.
 
 class Output_data
@@ -1987,7 +2053,7 @@ class Output_symtab_xindex : public Output_section_data
 };
 
 // A relaxed input section.
-class Output_relaxed_input_section : public Output_section_data
+class Output_relaxed_input_section : public Output_section_data_build
 {
  public:
   // We would like to call relobj->section_addralign(shndx) to get the
@@ -1995,7 +2061,7 @@ class Output_relaxed_input_section : public Output_section_data
   // are repsonsible for ensuring that.
   Output_relaxed_input_section(Relobj* relobj, unsigned int shndx,
                               uint64_t addralign)
-    : Output_section_data(addralign), relobj_(relobj), shndx_(shndx)
+    : Output_section_data_build(addralign), relobj_(relobj), shndx_(shndx)
   { }
  
   // Return the Relobj of this relaxed input section.
@@ -2041,6 +2107,10 @@ class Output_section : public Output_data
   void
   add_output_section_data(Output_section_data* posd);
 
+  // Add a relaxed input section PORIS to this output section.
+  void
+  add_relaxed_input_section(Output_relaxed_input_section* poris);
+
   // Return the section name.
   const char*
   name() const
@@ -2510,6 +2580,11 @@ class Output_section : public Output_data
   void
   restore_states();
 
+  // Convert existing input sections to relaxed input sections.
+  void
+  convert_input_sections_to_relaxed_sections(
+      const std::vector<Output_relaxed_input_section*>& sections);
+
   // Print merge statistics to stderr.
   void
   print_merge_stats();
@@ -2625,7 +2700,6 @@ class Output_section : public Output_data
   void
   write_to_postprocessing_buffer();
 
- private:
   // In some cases we need to keep a list of the input sections
   // associated with this output section.  We only need the list if we
   // might have to change the offsets of the input section within the
@@ -2741,16 +2815,24 @@ class Output_section : public Output_data
     Relobj*
     relobj() const
     {
-      gold_assert(this->is_input_section());
-      return this->u2_.object;
+      if (this->is_input_section())
+        return this->u2_.object;
+      else if (this->is_relaxed_input_section())
+       return this->u2_.poris->relobj();
+      else
+       gold_unreachable();
     }
 
     // Return the input section index for an input section.
     unsigned int
     shndx() const
     {
-      gold_assert(this->is_input_section());
-      return this->shndx_;
+      if (this->is_input_section())
+        return this->shndx_;
+      else if (this->is_relaxed_input_section())
+       return this->u2_.poris->shndx();
+      else
+       gold_unreachable();
     }
 
     // For non-input-sections, return the associated Output_section_data
@@ -2891,6 +2973,12 @@ class Output_section : public Output_data
 
   typedef std::vector<Input_section> Input_section_list;
 
+  // Allow a child class to access the input sections.
+  const Input_section_list&
+  input_sections() const
+  { return this->input_sections_; }
+
+ private:
   // We only save enough information to undo the effects of section layout.
   class Checkpoint_output_section
   {
@@ -2921,9 +3009,9 @@ class Output_section : public Output_data
     { return this->flags_; }
 
     // Return a reference to the input section list copy.
-    const Input_section_list&
-    input_sections() const
-    { return this->input_sections_copy_; }
+    Input_section_list*
+    input_sections()
+    { return &this->input_sections_copy_; }
 
     // Return the size of input_sections at the time when checkpoint is
     // taken.
@@ -2974,7 +3062,6 @@ class Output_section : public Output_data
     bool attached_input_sections_are_sorted_;
   };
 
- private:
   // This class is used to sort the input sections.
   class Input_section_sort_entry;
 
@@ -3018,6 +3105,82 @@ class Output_section : public Output_data
 
   typedef std::vector<Fill> Fill_list;
 
+  // This class describes properties of merge data sections.  It is used
+  // as a key type for maps.
+  class Merge_section_properties
+  {
+   public:
+    Merge_section_properties(bool is_string, uint64_t entsize,
+                            uint64_t addralign)
+      : is_string_(is_string), entsize_(entsize), addralign_(addralign)
+    { }
+
+    // Whether this equals to another Merge_section_properties MSP.
+    bool
+    eq(const Merge_section_properties& msp) const
+    {
+      return ((this->is_string_ == msp.is_string_)
+             && (this->entsize_ == msp.entsize_)
+             && (this->addralign_ == msp.addralign_));
+    }
+
+    // Compute a hash value for this using 64-bit FNV-1a hash.
+    size_t
+    hash_value() const
+    {
+      uint64_t h = 14695981039346656037ULL;    // FNV offset basis.
+      uint64_t prime = 1099511628211ULL;
+      h = (h ^ static_cast<uint64_t>(this->is_string_)) * prime;
+      h = (h ^ static_cast<uint64_t>(this->entsize_)) * prime;
+      h = (h ^ static_cast<uint64_t>(this->addralign_)) * prime;
+      return h;
+    }
+    
+    // Functors for associative containers.
+    struct equal_to
+    {
+      bool
+      operator()(const Merge_section_properties& msp1,
+                const Merge_section_properties& msp2) const
+      { return msp1.eq(msp2); }
+    };
+
+    struct hash
+    {
+      size_t
+      operator()(const Merge_section_properties& msp) const
+      { return msp.hash_value(); }
+    };
+
+   private:
+    // Whether this merge data section is for strings.
+    bool is_string_;
+    // Entsize of this merge data section.
+    uint64_t entsize_;
+    // Address alignment.
+    uint64_t addralign_;
+  };
+
+  // Map that link Merge_section_properties to Output_merge_base.
+  typedef Unordered_map<Merge_section_properties, Output_merge_base*,
+                       Merge_section_properties::hash,
+                       Merge_section_properties::equal_to>
+    Merge_section_by_properties_map;
+
+  // Map that link Input_section_specifier to Output_section_data.
+  typedef Unordered_map<Input_section_specifier, Output_section_data*,
+                       Input_section_specifier::hash,
+                       Input_section_specifier::equal_to>
+    Output_section_data_by_input_section_map;
+
+  // Map used during relaxation of existing sections.  This map
+  // an input section specifier to an input section list index.
+  // We assume that Input_section_list is a vector.
+  typedef Unordered_map<Input_section_specifier, size_t,
+                       Input_section_specifier::hash,
+                       Input_section_specifier::equal_to>
+    Relaxation_map;
+
   // Add a new output section by Input_section.
   void
   add_output_section_data(Input_section*);
@@ -3036,14 +3199,34 @@ class Output_section : public Output_data
   add_output_merge_section(Output_section_data* posd, bool is_string,
                           uint64_t entsize);
 
-  // Relax an existing input section.
-  void
-  relax_input_section(Output_relaxed_input_section*);
-
   // Sort the attached input sections.
   void
   sort_attached_input_sections();
 
+  // Find the merge section into which an input section with index SHNDX in
+  // OBJECT has been added.  Return NULL if none found.
+  Output_section_data*
+  find_merge_section(const Relobj* object, unsigned int shndx) const;
+
+  // Find a relaxed input section to an input section in OBJECT
+  // with index SHNDX.  Return NULL if none is found.
+  const Output_section_data*
+  find_relaxed_input_section(const Relobj* object, unsigned int shndx) const;
+  
+  // Build a relaxation map.
+  void
+  build_relaxation_map(
+      const Input_section_list& input_sections,
+      size_t limit,
+      Relaxation_map* map) const;
+
+  // Convert input sections in an input section list into relaxed sections.
+  void
+  convert_input_sections_in_list_to_relaxed_sections(
+      const std::vector<Output_relaxed_input_section*>& relaxed_sections,
+      const Relaxation_map& map,
+      Input_section_list* input_sections);
+
   // Most of these fields are only valid after layout.
 
   // The name of the section.  This will point into a Stringpool.
@@ -3149,6 +3332,18 @@ class Output_section : public Output_data
   uint64_t tls_offset_;
   // Saved checkpoint.
   Checkpoint_output_section* checkpoint_;
+  // Map from input sections to merge sections.
+  Output_section_data_by_input_section_map merge_section_map_;
+  // Map from merge section properties to merge_sections;
+  Merge_section_by_properties_map merge_section_by_properties_map_;
+  // Map from input sections to relaxed input sections.  This is mutable
+  // beacause it is udpated lazily.  We may need to update it in a
+  // const qualified method.
+  mutable Output_section_data_by_input_section_map relaxed_input_section_map_;
+  // Whether relaxed_input_section_map_ is valid.
+  mutable bool is_relaxed_input_section_map_valid_;
+  // Whether code-fills are generated at write.
+  bool generate_code_fills_at_write_;
 };
 
 // An output segment.  PT_LOAD segments are built from collections of
index d6e2b7279e80d6954882db7d00c863274cef116f..15d22d68774f520a6ab83ddb016321de87935506 100644 (file)
@@ -1325,10 +1325,17 @@ Output_section_element_input::set_section_addresses(
 
        isi.set_section_name(relobj->section_name(shndx));
        if (p->is_relaxed_input_section())
-         isi.set_size(p->relaxed_input_section()->data_size());
+         {
+           // We use current data size because relxed section sizes may not
+           // have finalized yet.
+           isi.set_size(p->relaxed_input_section()->current_data_size());
+           isi.set_addralign(p->relaxed_input_section()->addralign());
+         }
        else
-         isi.set_size(relobj->section_size(shndx));
-       isi.set_addralign(relobj->section_addralign(shndx));
+         {
+           isi.set_size(relobj->section_size(shndx));
+           isi.set_addralign(relobj->section_addralign(shndx));
+         }
       }
 
       if (!this->match_file_name(relobj->name().c_str()))
@@ -2292,7 +2299,9 @@ Orphan_output_section::set_section_addresses(Symbol_table*, Layout*,
        Task_lock_obj<Object> tl(task, p->relobj());
        addralign = p->relobj()->section_addralign(p->shndx());
        if (p->is_relaxed_input_section())
-         size = p->relaxed_input_section()->data_size();
+         // We use current data size because relxed section sizes may not
+         // have finalized yet.
+         size = p->relaxed_input_section()->current_data_size();
        else
          size = p->relobj()->section_size(p->shndx());
       }
index 562e1fc43adfe41a881ec45124a03cf3c39ae599..8a9e6f103ae4392dc670b27ae119e46bbf141909 100644 (file)
@@ -2355,30 +2355,17 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool,
   return off;
 }
 
-// Finalize the symbol SYM.  This returns true if the symbol should be
-// added to the symbol table, false otherwise.
+// Compute the final value of SYM and store status in location PSTATUS.
+// During relaxation, this may be called multiple times for a symbol to
+// compute its would-be final value in each relaxation pass.
 
 template<int size>
-bool
-Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
+typename Sized_symbol<size>::Value_type
+Symbol_table::compute_final_value(
+    const Sized_symbol<size>* sym,
+    Compute_final_value_status* pstatus) const
 {
   typedef typename Sized_symbol<size>::Value_type Value_type;
-
-  Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
-
-  // The default version of a symbol may appear twice in the symbol
-  // table.  We only need to finalize it once.
-  if (sym->has_symtab_index())
-    return false;
-
-  if (!sym->in_reg())
-    {
-      gold_assert(!sym->has_symtab_index());
-      sym->set_symtab_index(-1U);
-      gold_assert(sym->dynsym_index() == -1U);
-      return false;
-    }
-
   Value_type value;
 
   switch (sym->source())
@@ -2392,9 +2379,8 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
            && shndx != elfcpp::SHN_ABS
            && !Symbol::is_common_shndx(shndx))
          {
-           gold_error(_("%s: unsupported symbol section 0x%x"),
-                      sym->demangled_name().c_str(), shndx);
-           shndx = elfcpp::SHN_UNDEF;
+           *pstatus = CFVS_UNSUPPORTED_SYMBOL_SECTION;
+           return 0;
          }
 
        Object* symobj = sym->object();
@@ -2435,12 +2421,12 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
 
            if (os == NULL)
              {
-               sym->set_symtab_index(-1U);
                 bool static_or_reloc = (parameters->doing_static_link() ||
                                         parameters->options().relocatable());
                 gold_assert(static_or_reloc || sym->dynsym_index() == -1U);
 
-               return false;
+               *pstatus = CFVS_NO_OUTPUT_SECTION;
+               return 0;
              }
 
             if (secoff64 == -1ULL)
@@ -2513,6 +2499,57 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
       gold_unreachable();
     }
 
+  *pstatus = CFVS_OK;
+  return value;
+}
+
+// Finalize the symbol SYM.  This returns true if the symbol should be
+// added to the symbol table, false otherwise.
+
+template<int size>
+bool
+Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
+{
+  typedef typename Sized_symbol<size>::Value_type Value_type;
+
+  Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(unsized_sym);
+
+  // The default version of a symbol may appear twice in the symbol
+  // table.  We only need to finalize it once.
+  if (sym->has_symtab_index())
+    return false;
+
+  if (!sym->in_reg())
+    {
+      gold_assert(!sym->has_symtab_index());
+      sym->set_symtab_index(-1U);
+      gold_assert(sym->dynsym_index() == -1U);
+      return false;
+    }
+
+  // Compute final symbol value.
+  Compute_final_value_status status;
+  Value_type value = this->compute_final_value(sym, &status);
+
+  switch (status)
+    {
+    case CFVS_OK:
+      break;
+    case CFVS_UNSUPPORTED_SYMBOL_SECTION:
+      {
+       bool is_ordinary;
+       unsigned int shndx = sym->shndx(&is_ordinary);
+       gold_error(_("%s: unsupported symbol section 0x%x"),
+                  sym->demangled_name().c_str(), shndx);
+      }
+      break;
+    case CFVS_NO_OUTPUT_SECTION:
+      sym->set_symtab_index(-1U);
+      return false;
+    default:
+      gold_unreachable();
+    }
+
   sym->set_value(value);
 
   if (parameters->options().strip_all()
index 8dd7a7228016cfc1755fe980e755b54c2fa1fe57..148634ed8c0ff9679ffcb7a42f0e1bbda333b81f 100644 (file)
@@ -1377,6 +1377,26 @@ class Symbol_table
   finalize(off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount,
           Stringpool* pool, unsigned int *plocal_symcount);
 
+  // Status code of Symbol_table::compute_final_value.
+  enum Compute_final_value_status
+  {
+    // No error.
+    CFVS_OK,
+    // Unspported symbol section.
+    CFVS_UNSUPPORTED_SYMBOL_SECTION,
+    // No output section.
+    CFVS_NO_OUTPUT_SECTION
+  };
+
+  // Compute the final value of SYM and store status in location PSTATUS.
+  // During relaxation, this may be called multiple times for a symbol to 
+  // compute its would-be final value in each relaxation pass.
+
+  template<int size>
+  typename Sized_symbol<size>::Value_type
+  compute_final_value(const Sized_symbol<size>* sym,
+                     Compute_final_value_status* pstatus) const;
+
   // Write out the global symbols.
   void
   write_globals(const Stringpool*, const Stringpool*,
index b129b59fac6278f0ccdeaa21dc184c208fb5efb5..0ddc13d68ed91b0a67afa6d8f60d187e705cd733 100644 (file)
@@ -23,6 +23,7 @@
 #include "gold.h"
 #include "target.h"
 #include "dynobj.h"
+#include "output.h"
 #include "elfcpp.h"
 
 namespace gold
@@ -136,6 +137,13 @@ Target::do_make_elf_object(const std::string& name, Input_file* input_file,
 }
 #endif
 
+Output_section*
+Target::do_make_output_section(const char* name, elfcpp::Elf_Word type,
+                              elfcpp::Elf_Xword flags)
+{
+  return new Output_section(name, type, flags);
+}
+
 // Default conversion for -fsplit-stack is to give an error.
 
 void
index 68d89dc5ed814e8646b43fd9687d91caf5505919..67397c31502ea4fb17b81d939bfba775acd874b3 100644 (file)
@@ -242,6 +242,12 @@ class Target
                  off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
   { return this->do_make_elf_object(name, input_file, offset, ehdr); }
 
+  // Make an output section.
+  Output_section*
+  make_output_section(const char* name, elfcpp::Elf_Word type,
+                     elfcpp::Elf_Xword flags)
+  { return this->do_make_output_section(name, type, flags); }
+
   // Return true if target wants to perform relaxation.
   bool
   may_relax() const
@@ -255,14 +261,15 @@ class Target
 
   // Perform a relaxation pass.  Return true if layout may be changed.
   bool
-  relax(int pass)
+  relax(int pass, const Input_objects* input_objects, Symbol_table* symtab,
+       Layout* layout)
   {
     // Run the dummy relaxation pass twice if relaxation debugging is enabled.
     if (is_debugging_enabled(DEBUG_RELAXATION))
       return pass < 2;
 
-    return this->do_relax(pass);
-  }
+    return this->do_relax(pass, input_objects, symtab, layout);
+  } 
 
  protected:
   // This struct holds the constant information for a child class.  We
@@ -386,6 +393,11 @@ class Target
                     off_t offset, const elfcpp::Ehdr<64, true>& ehdr);
 #endif
 
+  // Virtual functions which may be overriden by the child class.
+  virtual Output_section*
+  do_make_output_section(const char* name, elfcpp::Elf_Word type,
+                        elfcpp::Elf_Xword flags);
+
   // Virtual function which may be overriden by the child class.
   virtual bool
   do_may_relax() const
@@ -393,7 +405,7 @@ class Target
 
   // Virtual function which may be overriden by the child class.
   virtual bool
-  do_relax(int)
+  do_relax(int, const Input_objects*, Symbol_table*, Layout*)
   { return false; }
 
   // A function for targets to call.  Return whether BYTES/LEN matches