[GOLD][PATCH] Add Arm_output_section class and downcasting hooks.

Doug Kwan (關振德) dougkwan@google.com
Fri Oct 23 21:27:00 GMT 2009


Sorry, wrong patch.  Here is the correct one.

-Doug

2009/10/22 Doug Kwan (關振德) <dougkwan@google.com>:
> Hi,
>
>    This patch adds a new class Arm_output_section, which is a
> sub-class of Output_section.  The class is defined mainly because we
> want to group input sections into stub-groups.  In addition, this
> patch also adds down-casting hooks for Relobj,
> Output_relaxed_input_section and Output_section to their ARM
> sub-classes.
>
> -Doug
>
> 2009-10-22  Doug Kwan  <dougkwan@google.com>
>
>        * arm.cc (Arm_output_section, Arm_relobj): Forward class declarations.
>        (Arm_input_section::do_arm_input_section): New method.
>        (Arm_output_section): New class definition.
>        (Arm_output_section::create_stub_group,
>        Arm_output_section::group_sections): New method definitions.
>        * object.h (Arm_relobj): Forward class declaration.
>        (Relobj::arm_relobj): New function template definition.
>        (Relobj::do_arm_relobj): New overloaded method definitions.
>        * output.h (Arm_input_section, Arm_output_section): Forward class
>        declarations.
>        (Output_relaxed_input_section::arm_input_section): New function
>        template definition.
>        (Output_relaxed_input_section::do_arm_input_section): New
>        overloaded method definitions.
>        (Output_section::arm_output_section): New function template
>        definition.
>        (Output_section::do_arm_output_section): New overloaded method
>        definitions.
>
-------------- next part --------------
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.19
diff -u -p -r1.19 arm.cc
--- gold/arm.cc	22 Oct 2009 18:58:02 -0000	1.19
+++ gold/arm.cc	22 Oct 2009 23:47:50 -0000
@@ -62,6 +62,12 @@ template<bool big_endian>
 class Arm_input_section;
 
 template<bool big_endian>
+class Arm_output_section;
+
+template<bool big_endian>
+class Arm_relobj;
+
+template<bool big_endian>
 class Target_arm;
 
 // For convenience.
@@ -821,6 +827,10 @@ class Arm_input_section : public Output_
       return false;
   }
 
+  void
+  do_arm_input_section(Arm_input_section<big_endian>** presult)
+  { *presult = this; }
+
  private:
   // Copying is not allowed.
   Arm_input_section(const Arm_input_section&);
@@ -834,6 +844,43 @@ class Arm_input_section : public Output_
   Stub_table<big_endian>* stub_table_;
 };
 
+// Arm output section class.  This is defined mainly to add a number of
+// stub generation methods.
+
+template<bool big_endian>
+class Arm_output_section : public Output_section
+{
+ public:
+  Arm_output_section(const char* name, elfcpp::Elf_Word type,
+		     elfcpp::Elf_Xword flags)
+    : Output_section(name, type, flags)
+  { }
+
+  ~Arm_output_section()
+  { }
+  
+  // Group input sections for stub generation.
+  void
+  group_sections(section_size_type, bool, Target_arm<big_endian>*);
+
+ protected:
+  void
+  do_arm_output_section(Arm_output_section<big_endian>** presult)
+  { *presult = this; }
+
+ private:
+  // For convenience.
+  typedef Output_section::Input_section Input_section;
+  typedef Output_section::Input_section_list Input_section_list;
+
+  // Create a stub group.
+  void create_stub_group(Input_section_list::const_iterator,
+			 Input_section_list::const_iterator,
+			 Input_section_list::const_iterator,
+			 Target_arm<big_endian>*,
+			 std::vector<Output_relaxed_input_section*>*);
+};
+
 // Utilities for manipulating integers of up to 32-bits
 
 namespace utils
@@ -2649,6 +2696,205 @@ Arm_input_section<big_endian>::do_reset_
   this->set_current_data_size(off);
 }
 
+// Arm_output_section methods.
+
+// Create a stub group for input sections from BEGIN to END.  OWNER
+// points to the input section to be the owner of a new stub table.
+
+template<bool big_endian>
+void
+Arm_output_section<big_endian>::create_stub_group(
+  Input_section_list::const_iterator begin,
+  Input_section_list::const_iterator end,
+  Input_section_list::const_iterator owner,
+  Target_arm<big_endian>* target,
+  std::vector<Output_relaxed_input_section*>* new_relaxed_sections)
+{
+  // Currently we convert ordinary input sections into relaxed sections only
+  // at this point but we may want to support creating relaxed input section
+  // very early.  So we check here to see if owner is already a relaxed
+  // section.
+  
+  Arm_input_section<big_endian>* arm_input_section;
+  if (owner->is_relaxed_input_section())
+    {
+      arm_input_section =
+	owner->relaxed_input_section()->arm_input_section<big_endian>();
+      gold_assert(arm_input_section != NULL);
+    }
+  else
+    {
+      gold_assert(owner->is_input_section());
+      // Create a new relaxed input section.
+      arm_input_section =
+	target->new_arm_input_section(owner->relobj(), owner->shndx());
+      new_relaxed_sections->push_back(arm_input_section);
+    }
+
+  // Create a stub table.
+  Stub_table<big_endian>* stub_table =
+    target->new_stub_table(arm_input_section);
+
+  arm_input_section->set_stub_table(stub_table);
+  
+  Input_section_list::const_iterator after_end = end + 1;
+  for (Input_section_list::const_iterator p = begin; p != after_end; ++p)
+    if (p->is_input_section() || p->is_relaxed_input_section())
+      {
+	// Stub table information for input sections lives
+	// in their objects.
+	Arm_relobj<big_endian>* arm_relobj =
+	  p->relobj()->arm_relobj<big_endian>();
+	gold_assert(arm_relobj != NULL);
+	arm_relobj->set_stub_table(p->shndx(), stub_table);
+      }
+}
+
+// Group input sections for stub generation.  GROUP_SIZE is roughly the limit
+// of a stub group.  We grow a stub group by adding input sections until the
+// size is just below GROUP_SIZE.  The last input section will be converted
+// into an Arm_input_section holding the stub table.  If
+// STUB_ALWAYS_AFTER_BRANCH is false, we also add input sections after the stub
+// table, effectively double the group size.
+//
+// This is similar to the group_sections() function in elf32-arm.c but is
+// implemented differently.
+
+template<bool big_endian>
+void
+Arm_output_section<big_endian>::group_sections(
+    section_size_type group_size,
+    bool stubs_always_after_branch,
+    Target_arm<big_endian>* target)
+{
+  // We only care about sections containing code.
+  if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0)
+    return;
+
+  // States for grouping.
+  typedef enum
+  {
+    // No group is being built.
+    NO_GROUP,
+    // A group is being built but the stub section is not found yet.
+    // We keep building a stub group until the size is just under GROUP_SIZE.
+    // The last input section in the group will be used as the stub section.
+    FINDING_STUB_SECTION,
+    // A group is being built and we have already found a stub section.
+    // We enter this state to grow a stub group by adding input sections
+    // after the stub section.  This effectively doubles the group size.
+    HAS_STUB_SECTION
+  } State;
+
+  // Any newly created relaxed sections are stored here.
+  std::vector<Output_relaxed_input_section*> new_relaxed_sections;
+
+  State state = NO_GROUP;
+  section_size_type off = 0;
+  section_size_type group_begin_offset = 0;
+  section_size_type group_end_offset = 0;
+  section_size_type stub_table_end_offset = 0;
+  Input_section_list::const_iterator group_begin =
+    this->input_sections().end();
+  Input_section_list::const_iterator stub_table =
+    this->input_sections().end();
+  Input_section_list::const_iterator group_end = this->input_sections().end();
+  for (Input_section_list::const_iterator p = this->input_sections().begin();
+       p != this->input_sections().end();
+       ++p)
+    {
+      section_size_type section_begin_offset =
+	align_address(off, p->addralign());
+      section_size_type section_end_offset =
+	section_begin_offset + p->data_size(); 
+      
+      // Check to see if we should group the previously seen sections.
+      switch(state)
+	{
+	case NO_GROUP:
+	  break;
+
+	case FINDING_STUB_SECTION:
+	  // Adding this section makes the group larger than GROUP_SIZE.
+	  if (section_end_offset - group_begin_offset >= group_size)
+	    {
+	      if (stubs_always_after_branch)
+		{	
+		  this->create_stub_group(group_begin, group_end, group_end,
+					  target, &new_relaxed_sections);
+		  state = NO_GROUP;
+		}
+	      else
+		{
+		  // But wait, there's more!  Input sections up to
+		  // stub_group_size bytes after the stub table can be
+		  // handled by it too.
+		  state = HAS_STUB_SECTION;
+		  stub_table = group_end;
+		  stub_table_end_offset = group_end_offset;
+		}
+	    }
+	    break;
+
+	case HAS_STUB_SECTION:
+	  // Adding this section makes the post stub-section group larger
+	  // than GROUP_SIZE.
+	  if (section_end_offset - stub_table_end_offset >= group_size)
+	   {
+	     this->create_stub_group(group_begin, group_end, stub_table,
+				     target, &new_relaxed_sections);
+	     state = NO_GROUP;
+	   }
+	   break;
+
+	  default:
+	    gold_unreachable();
+	}	
+
+      // If we see an input section and currently there is no group, start
+      // a new one.  Skip any empty sections.
+      if ((p->is_input_section() || p->is_relaxed_input_section())
+	  && (p->relobj()->section_size(p->shndx()) != 0))
+	{
+	  if (state == NO_GROUP)
+	    {
+	      state = FINDING_STUB_SECTION;
+	      group_begin = p;
+	      group_begin_offset = section_begin_offset;
+	    }
+
+	  // Keep track of the last input section seen.
+	  group_end = p;
+	  group_end_offset = section_end_offset;
+	}
+
+      off = section_end_offset;
+    }
+
+  // Create a stub group for any ungrouped sections.
+  if (state == FINDING_STUB_SECTION || state == HAS_STUB_SECTION)
+    this->create_stub_group(group_begin, group_end,
+			    (state == FINDING_STUB_SECTION
+			     ? group_end
+			     : stub_table),
+			    target, &new_relaxed_sections);
+
+  // Convert input sections into Arm_input_sections in a batch.
+  if (!new_relaxed_sections.empty())
+    this->convert_input_sections_to_relaxed_sections(new_relaxed_sections);
+
+  // Update the section offsets
+  for (size_t i = 0; i < new_relaxed_sections.size(); ++i)
+    {
+      Arm_relobj<big_endian>* arm_relobj =
+	 new_relaxed_sections[i]->relobj()->arm_relobj<big_endian>();
+      gold_assert(arm_relobj != NULL);
+      unsigned int shndx = new_relaxed_sections[i]->shndx();
+      // Tell Arm_relobj that this input section is converted.
+      arm_relobj->convert_input_section_to_relaxed_section(shndx);
+    }
+}
+
 // A class to handle the PLT data.
 
 template<bool big_endian>
Index: gold/object.h
===================================================================
RCS file: /cvs/src/src/gold/object.h,v
retrieving revision 1.82
diff -u -p -r1.82 object.h
--- gold/object.h	15 Oct 2009 00:33:18 -0000	1.82
+++ gold/object.h	22 Oct 2009 23:47:50 -0000
@@ -51,6 +51,9 @@ class Symbols_data;
 template<typename Stringpool_char>
 class Stringpool_template;
 
+template<bool big_endian>
+class Arm_relobj;
+
 // Data to pass from read_symbols() to add_symbols().
 
 struct Read_symbols_data
@@ -778,6 +781,16 @@ class Relobj : public Object
   layout_deferred_sections(Layout* layout)
   { this->do_layout_deferred_sections(layout); }
 
+  // Return a pointer to self if this is an Arm_relobj or NULL otherwise.
+  template<bool big_endian>
+  Arm_relobj<big_endian>*
+  arm_relobj()
+  {
+    Arm_relobj<big_endian>* as_arm_relobj;
+    this->do_arm_relobj(&as_arm_relobj);
+    return as_arm_relobj;
+  }
+
  protected:
   // The output section to be used for each input section, indexed by
   // the input section number.  The output section is NULL if the
@@ -863,6 +876,19 @@ class Relobj : public Object
   set_relocs_must_follow_section_writes()
   { this->relocs_must_follow_section_writes_ = true; }
 
+  // Return pointer to self if this is Arm_relobj or NULL otherwise.
+  // Instead of returning a pointer, we use a pointer to pointer for the
+  // result.  This is intentional.  The parameter type helps us selecting
+  // the correct overload.  We cannot resolve overloads using the return type.
+  // These may be overriden by a child class.
+  virtual void
+  do_arm_relobj(Arm_relobj<false>** presult)
+  { *presult = NULL; }
+
+  virtual void
+  do_arm_relobj(Arm_relobj<true>** presult)
+  { *presult = NULL; }
+
  private:
   // Mapping from input sections to output section.
   Output_sections output_sections_;
Index: gold/output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.86
diff -u -p -r1.86 output.h
--- gold/output.h	21 Oct 2009 08:08:41 -0000	1.86
+++ gold/output.h	22 Oct 2009 23:47:50 -0000
@@ -47,6 +47,11 @@ class Sized_target;
 template<int size, bool big_endian>
 class Sized_relobj;
 
+template<bool big_endian>
+class Arm_input_section;
+template<bool big_endian>
+class Arm_output_section;
+
 // This class specifies an input section.  It is used as a key type
 // for maps.
 
@@ -2065,6 +2070,30 @@ class Output_relaxed_input_section : pub
   shndx() const
   { return this->shndx_; }
 
+  // Return self if this is an Arm_input_section or NULL otherwise.
+  template<bool big_endian>
+  Arm_input_section<big_endian>*
+  arm_input_section()
+  {
+    Arm_input_section<big_endian>* as_arm_input_section;
+    this->do_arm_input_section(&as_arm_input_section);
+    return as_arm_input_section;
+  }
+
+ protected:
+  // Return pointer to self if this is Arm_input_section or NULL otherwise.
+  // Instead of returning a pointer, we use a pointer to pointer for the
+  // result.  This is intentional.  The parameter type helps us selecting
+  // the correct overload.  We cannot resolve overloads using the return type.
+  // These may be overriden by a child class.
+  virtual void
+  do_arm_input_section(Arm_input_section<false>** presult)
+  { *presult = NULL; }
+
+  virtual void
+  do_arm_input_section(Arm_input_section<true>** presult)
+  { *presult = NULL; }
+    
  private:
   Relobj* relobj_;
   unsigned int shndx_;
@@ -2581,6 +2610,17 @@ class Output_section : public Output_dat
   const Output_section_data*
   find_relaxed_input_section(const Relobj* object, unsigned int shndx) const;
   
+  // Return pointer to self if this is an Arm_output_section, otherwise
+  // return NULL.
+  template<bool big_endian>
+  Arm_output_section<big_endian>*
+  arm_output_section()
+  {
+    Arm_output_section<big_endian>* as_arm_output_section;
+    this->do_arm_output_section(&as_arm_output_section);
+    return as_arm_output_section;
+  }
+
   // Print merge statistics to stderr.
   void
   print_merge_stats();
@@ -2974,6 +3014,19 @@ class Output_section : public Output_dat
   input_sections() const
   { return this->input_sections_; }
 
+  // Return pointer to self if this is Arm_output_section or NULL otherwise.
+  // Instead of returning a pointer, we use a pointer to pointer for the
+  // result.  This is intentional.  The parameter type helps us selecting
+  // the correct overload.  We cannot resolve overloads using the return type.
+  // These may be overriden by a child class.
+  virtual void
+  do_arm_output_section(Arm_output_section<false>** presult)
+  { *presult = NULL; }
+
+  virtual void
+  do_arm_output_section(Arm_output_section<true>** presult)
+  { *presult = NULL; }
+
  private:
   // We only save enough information to undo the effects of section layout.
   class Checkpoint_output_section


More information about the Binutils mailing list