[patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment.

Sriraman Tallam tmsriram@google.com
Sat Jul 21 00:28:00 GMT 2012


Hi,

  This patch allows plugins to specify that a subset of sections are
to be mapped to an unique segment.  This is useful, for instance, when
a set of functions that are determined to be hot can be placed in an
unique segment which can then be mapped to huge text pages. It has
been found for some Google applications that mapping functions to huge
pages, along with function layout, provides a significant performance
benefit and this feature can take this further by only mapping certain
functions to huge pages, which requires that they be placed in an
unique segment.

The plugin needs to specify a list of sections that have to mapped to
an unique segment.  The plugin can also specify any additional segment
flags to be set. The segment flag bits 3 to 19 seem to be available
and can be set to mark some segments which can later be mapped to huge
pages.  The flags which would be set by default, bits 0-2, cannot be
unset by the plugin.

Thoughts?

Patch attached.

Thanks,
-Sri.
-------------- next part --------------
This patch allows plugins to specify that a subset of sections are to be mapped to an unique segment.  This is useful, for instance, when a set of functions that are determined to be hot can be placed in an unique segment which can then be mapped to huge text pages. It has been found for some Google applications that mapping functions to huge pages, along with function layout, provides a significant performance benefit and this feature can take this further by only mapping certain functions to huge pages, which requires that they be placed in an unique segment.

The plugin needs to specify a list of sections that have to mapped to an unique segment.  The plugin can also specify any additional segment flags to be set. The segment flag bits 3 to 19 seem to be available and can be set to mark some segments which can later be mapped to huge pages.  The flags which would be set by default, bits 0-2, cannot be unset by the plugin.


	* plugin-api.h (ld_plugin_allow_unique_segment_for_sections):
	New interface.
	(ld_plugin_unique_segment_for_sections): New interface.
	(LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS): New enum val.
	(LDPT_UNIQUE_SEGMENT_FOR_SECTIONS): New enum val.
	(tv_allow_unique_segment_for_sections): New member.
	(tv_unique_segment_for_sections): New member.

	* gold.cc (queue_middle_tasks): Call layout again when unique
	segments for sections is desired.
	* layout.cc (Layout::Layout): Initialize new members.
	(choose_output_section): New parameter.
	Modify call to output_section_name.
	(output_section_name): New parameter.
	Check if input section needs to be mapped to a different output
	section.
	(Layout::layout): Modify call to choose_output_section.
	Mark output section for mapping to an unique segment.
	(Layout::layout_reloc): Modify call to choose_output_section.
	(Layout::make_eh_frame_section): Modify call to choose_output_section.
	(Layout::add_to_gdb_index): Modify call to choose_output_section.
	(Layout::add_output_section_data): Modify call to
	choose_output_section.
	(Layout::attach_allocated_section_to_segment): Set extra segment flags.
	Map to unique segment if necessary.
	(Layout::create_initial_dynamic_sections): Modify call to
	choose_output_section.
	(Layout::create_dynamic_symtab): Modify call to
	choose_output_section.
	(Layout::sized_create_version_sections): Modify call to
	choose_output_section.
	(Layout::create_interp): Modify call to
	choose_output_section. 
	* layout.h (Layout::get_section_segment_map): New function.
	(Layout::get_output_section_flags_map): New function.
	(Layout::is_unique_segment_for_sections_specified): New function.
	(Layout::set_unique_segment_for_sections_specified): New function.
	(Layout::output_section_name): Add parameter.
	(Layout::unique_segment_for_sections_specified_): New member.
	(Layout::section_segment_map_): New member.
	(Layout::output_section_flags_map_): New member.
	* object.cc (Sized_relobj_file<size, big_endian>::do_layout):
	Rename is_gc_pass_one to is_pass_one.
	Rename is_gc_pass_two to is_pass_two.
	Rename is_gc_or_icf to is_two_pass.
	Check for which pass based on whether symbols data is present.
	Make it two pass when unique segments for sections is desired.
	* output.cc (Output_section::Output_section): Initialize new
	member is_unique_segment.
	* output.h (Output_section::is_unique_segment): New function.
	(Output_section::set_is_unique_segment): New function.
	(Output_section::is_unique_segment): New member.
	* plugin.cc (allow_unique_segment_for_sections): New function.
	(unique_segment_for_sections): New function.
	(Plugin::load): Add new functions to transfer vector.
	* Makefile.am (plugin_final_layout.readelf.stdout): Add readelf output.
	* Makefile.in: Regenerate.
	* testsuite/plugin_final_layout.sh: Check if unique segment
	functionality works.
	* testsuite/plugin_section_order.c (onload): Check if new interfaces
	are available.
	(allow_unique_segment_for_sections): New global.
	(unique_segment_for_sections): New global.
	(claim_file_hook): Call allow_unique_segment_for_sections.
	(all_symbols_read_hook): Call unique_segment_for_sections.


Index: gold/gold.cc
===================================================================
RCS file: /cvs/src/src/gold/gold.cc,v
retrieving revision 1.100
diff -u -u -p -r1.100 gold.cc
--- gold/gold.cc	16 Jul 2012 19:00:18 -0000	1.100
+++ gold/gold.cc	20 Jul 2012 22:51:49 -0000
@@ -530,11 +530,13 @@ queue_middle_tasks(const General_options
 
   // Call Object::layout for the second time to determine the
   // output_sections for all referenced input sections.  When
-  // --gc-sections or --icf is turned on, Object::layout is
-  // called twice.  It is called the first time when the
-  // symbols are added.
+  // --gc-sections or --icf is turned on, or when certain input
+  // sections have to be mapped to unique segments, Object::layout
+  // is called twice.  It is called the first time when symbols
+  // are added.
   if (parameters->options().gc_sections()
-      || parameters->options().icf_enabled())
+      || parameters->options().icf_enabled()
+      || layout->is_unique_segment_for_sections_specified())
     {
       for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
 	   p != input_objects->relobj_end();
Index: gold/layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.231
diff -u -u -p -r1.231 layout.cc
--- gold/layout.cc	22 Jun 2012 18:02:24 -0000	1.231
+++ gold/layout.cc	20 Jul 2012 22:51:49 -0000
@@ -408,12 +408,15 @@ Layout::Layout(int number_of_input_files
     resized_signatures_(false),
     have_stabstr_section_(false),
     section_ordering_specified_(false),
+    unique_segment_for_sections_specified_(false),
     incremental_inputs_(NULL),
     record_output_section_data_from_script_(false),
     script_output_section_data_list_(),
     segment_states_(NULL),
     relaxation_debug_check_(NULL),
     section_order_map_(),
+    section_segment_map_(),
+    output_section_flags_map_(),
     input_section_position_(),
     input_section_glob_(),
     incremental_base_(NULL),
@@ -806,15 +809,17 @@ Layout::get_output_section(const char* n
 }
 
 // Pick the output section to use for section NAME, in input file
-// RELOBJ, with type TYPE and flags FLAGS.  RELOBJ may be NULL for a
-// linker created section.  IS_INPUT_SECTION is true if we are
-// choosing an output section for an input section found in a input
-// file.  ORDER is where this section should appear in the output
-// sections.  IS_RELRO is true for a relro section.  This will return
-// NULL if the input section should be discarded.
+// RELOBJ, with index SHNDX, with type TYPE and flags FLAGS.
+// RELOBJ may be NULL for a linker created section.
+// IS_INPUT_SECTION is true if we are choosing an output section
+// for an input section found in a input file.  ORDER is where this
+// section should appear in the output sections.  IS_RELRO is true
+// for a relro section.  This will return NULL if the input section
+// should be discarded.
 
 Output_section*
-Layout::choose_output_section(const Relobj* relobj, const char* name,
+Layout::choose_output_section(const Relobj* relobj, unsigned int shndx,
+			      const char* name,
 			      elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
 			      bool is_input_section, Output_section_order order,
 			      bool is_relro)
@@ -939,7 +944,8 @@ Layout::choose_output_section(const Relo
   if (is_input_section
       && !this->script_options_->saw_sections_clause()
       && !parameters->options().relocatable())
-    name = Layout::output_section_name(relobj, name, &len);
+    name = Layout::output_section_name(relobj, shndx, name, &len,
+				       &this->section_segment_map_);
 
   Stringpool::Key name_key;
   name = this->namepool_.add_with_length(name, len, true, &name_key);
@@ -1028,11 +1034,18 @@ Layout::layout(Sized_relobj_file<size, b
     }
   else
     {
-      os = this->choose_output_section(object, name, sh_type,
+      os = this->choose_output_section(object, shndx, name, sh_type,
 				       shdr.get_sh_flags(), true,
 				       ORDER_INVALID, false);
       if (os == NULL)
 	return NULL;
+
+      // Check if this output section needs to be mapped to an unique segment.
+      // This can happen when using plugins.
+      if (!os->is_unique_segment()
+	  && (this->section_segment_map_.find(Const_section_id(object, shndx))
+	      != this->section_segment_map_.end()))
+	os->set_is_unique_segment();
     }
 
   // By default the GNU linker sorts input sections whose names match
@@ -1119,7 +1132,7 @@ Layout::layout_reloc(Sized_relobj_file<s
   Output_section* os;
   if (!parameters->options().relocatable()
       || (data_section->flags() & elfcpp::SHF_GROUP) == 0)
-    os = this->choose_output_section(object, name.c_str(), sh_type,
+    os = this->choose_output_section(object, 0, name.c_str(), sh_type,
 				     shdr.get_sh_flags(), false,
 				     ORDER_INVALID, false);
   else
@@ -1291,7 +1304,7 @@ Layout::make_eh_frame_section(const Relo
 {
   // FIXME: On x86_64, this could use SHT_X86_64_UNWIND rather than
   // SHT_PROGBITS.
-  Output_section* os = this->choose_output_section(object, ".eh_frame",
+  Output_section* os = this->choose_output_section(object, 0, ".eh_frame",
 						   elfcpp::SHT_PROGBITS,
 						   elfcpp::SHF_ALLOC, false,
 						   ORDER_EHFRAME, false);
@@ -1308,7 +1321,7 @@ Layout::make_eh_frame_section(const Relo
       if (parameters->options().eh_frame_hdr() && !parameters->incremental())
 	{
 	  Output_section* hdr_os =
-	    this->choose_output_section(NULL, ".eh_frame_hdr",
+	    this->choose_output_section(NULL, 0, ".eh_frame_hdr",
 					elfcpp::SHT_PROGBITS,
 					elfcpp::SHF_ALLOC, false,
 					ORDER_EHFRAME, false);
@@ -1377,7 +1390,7 @@ Layout::add_to_gdb_index(bool is_type_un
 {
   if (this->gdb_index_data_ == NULL)
     {
-      Output_section* os = this->choose_output_section(NULL, ".gdb_index",
+      Output_section* os = this->choose_output_section(NULL, 0, ".gdb_index",
 						       elfcpp::SHT_PROGBITS, 0,
 						       false, ORDER_INVALID,
 						       false);
@@ -1403,7 +1416,7 @@ Layout::add_output_section_data(const ch
 				Output_section_data* posd,
 				Output_section_order order, bool is_relro)
 {
-  Output_section* os = this->choose_output_section(NULL, name, type, flags,
+  Output_section* os = this->choose_output_section(NULL, 0, name, type, flags,
 						   false, order, is_relro);
   if (os != NULL)
     os->add_output_section_data(posd);
@@ -1692,6 +1705,12 @@ Layout::attach_allocated_section_to_segm
 
   elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
 
+  // If this output section's segment has extra flags that need to be set,
+  // from a linker plugin, check that.
+  if (this->output_section_flags_map_.find(std::string(os->name()))
+      != this->output_section_flags_map_.end())
+    seg_flags |= this->output_section_flags_map_[std::string(os->name())];
+
   // Check for --section-start.
   uint64_t addr;
   bool is_address_set = parameters->options().section_start(os->name(), &addr);
@@ -1708,6 +1727,9 @@ Layout::attach_allocated_section_to_segm
        p != this->segment_list_.end();
        ++p)
     {
+      // No need to go through the loop if an unique segment is needed.
+      if (os->is_unique_segment())
+        break;
       if ((*p)->type() != elfcpp::PT_LOAD)
 	continue;
       if (!parameters->options().omagic()
@@ -1742,7 +1764,8 @@ Layout::attach_allocated_section_to_segm
       break;
     }
 
-  if (p == this->segment_list_.end())
+  if (p == this->segment_list_.end()
+      || os->is_unique_segment())
     {
       Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD,
 						       seg_flags);
@@ -1908,7 +1931,7 @@ Layout::create_initial_dynamic_sections(
   if (parameters->doing_static_link())
     return;
 
-  this->dynamic_section_ = this->choose_output_section(NULL, ".dynamic",
+  this->dynamic_section_ = this->choose_output_section(NULL, 0, ".dynamic",
 						       elfcpp::SHT_DYNAMIC,
 						       (elfcpp::SHF_ALLOC
 							| elfcpp::SHF_WRITE),
@@ -2664,7 +2687,7 @@ Layout::create_note(const char* name, in
       flags = elfcpp::SHF_ALLOC;
       order = ORDER_RO_NOTE;
     }
-  Output_section* os = this->choose_output_section(NULL, section_name,
+  Output_section* os = this->choose_output_section(NULL, 0, section_name,
 						   elfcpp::SHT_NOTE,
 						   flags, false, order, false);
   if (os == NULL)
@@ -3095,9 +3118,11 @@ Layout::segment_precedes(const Output_se
 
   // We shouldn't get here--we shouldn't create segments which we
   // can't distinguish.  Unless of course we are using a weird linker
-  // script or overlapping --section-start options.
+  // script or overlapping --section-start options.  We could also get
+  // here if plugins want unique segments for subsets of sections.
   gold_assert(this->script_options_->saw_phdrs_clause()
-	      || parameters->options().any_section_start());
+	      || parameters->options().any_section_start()
+	      || this->is_unique_segment_for_sections_specified());
   return false;
 }
 
@@ -3937,7 +3962,7 @@ Layout::create_dynamic_symtab(const Inpu
 
   // Create the dynamic symbol table section.
 
-  Output_section* dynsym = this->choose_output_section(NULL, ".dynsym",
+  Output_section* dynsym = this->choose_output_section(NULL, 0, ".dynsym",
 						       elfcpp::SHT_DYNSYM,
 						       elfcpp::SHF_ALLOC,
 						       false,
@@ -3976,7 +4001,7 @@ Layout::create_dynamic_symtab(const Inpu
   if (this->allocated_output_section_count() >= elfcpp::SHN_LORESERVE)
     {
       Output_section* dynsym_xindex =
-	this->choose_output_section(NULL, ".dynsym_shndx",
+	this->choose_output_section(NULL, 0, ".dynsym_shndx",
 				    elfcpp::SHT_SYMTAB_SHNDX,
 				    elfcpp::SHF_ALLOC,
 				    false, ORDER_DYNAMIC_LINKER, false);
@@ -4002,7 +4027,7 @@ Layout::create_dynamic_symtab(const Inpu
 
   // Create the dynamic string table section.
 
-  Output_section* dynstr = this->choose_output_section(NULL, ".dynstr",
+  Output_section* dynstr = this->choose_output_section(NULL, 0, ".dynstr",
 						       elfcpp::SHT_STRTAB,
 						       elfcpp::SHF_ALLOC,
 						       false,
@@ -4039,7 +4064,7 @@ Layout::create_dynamic_symtab(const Inpu
 				    &phash, &hashlen);
 
       Output_section* hashsec =
-	this->choose_output_section(NULL, ".hash", elfcpp::SHT_HASH,
+	this->choose_output_section(NULL, 0, ".hash", elfcpp::SHT_HASH,
 				    elfcpp::SHF_ALLOC, false,
 				    ORDER_DYNAMIC_LINKER, false);
 
@@ -4070,7 +4095,7 @@ Layout::create_dynamic_symtab(const Inpu
 				    &phash, &hashlen);
 
       Output_section* hashsec =
-	this->choose_output_section(NULL, ".gnu.hash", elfcpp::SHT_GNU_HASH,
+	this->choose_output_section(NULL, 0, ".gnu.hash", elfcpp::SHT_GNU_HASH,
 				    elfcpp::SHF_ALLOC, false,
 				    ORDER_DYNAMIC_LINKER, false);
 
@@ -4179,7 +4204,7 @@ Layout::sized_create_version_sections(
     const std::vector<Symbol*>& dynamic_symbols,
     const Output_section* dynstr)
 {
-  Output_section* vsec = this->choose_output_section(NULL, ".gnu.version",
+  Output_section* vsec = this->choose_output_section(NULL, 0, ".gnu.version",
 						     elfcpp::SHT_GNU_versym,
 						     elfcpp::SHF_ALLOC,
 						     false,
@@ -4212,7 +4237,7 @@ Layout::sized_create_version_sections(
   if (versions->any_defs())
     {
       Output_section* vdsec;
-      vdsec = this->choose_output_section(NULL, ".gnu.version_d",
+      vdsec = this->choose_output_section(NULL, 0, ".gnu.version_d",
 					  elfcpp::SHT_GNU_verdef,
 					  elfcpp::SHF_ALLOC,
 					  false, ORDER_DYNAMIC_LINKER, false);
@@ -4244,7 +4269,7 @@ Layout::sized_create_version_sections(
   if (versions->any_needs())
     {
       Output_section* vnsec;
-      vnsec = this->choose_output_section(NULL, ".gnu.version_r",
+      vnsec = this->choose_output_section(NULL, 0, ".gnu.version_r",
 					  elfcpp::SHT_GNU_verneed,
 					  elfcpp::SHF_ALLOC,
 					  false, ORDER_DYNAMIC_LINKER, false);
@@ -4292,7 +4317,7 @@ Layout::create_interp(const Target* targ
 
   Output_section_data* odata = new Output_data_const(interp, len, 1);
 
-  Output_section* osec = this->choose_output_section(NULL, ".interp",
+  Output_section* osec = this->choose_output_section(NULL, 0, ".interp",
 						     elfcpp::SHT_PROGBITS,
 						     elfcpp::SHF_ALLOC,
 						     false, ORDER_INTERP,
@@ -4693,8 +4718,10 @@ const int Layout::section_name_mapping_c
 // length of NAME.
 
 const char*
-Layout::output_section_name(const Relobj* relobj, const char* name,
-			    size_t* plen)
+Layout::output_section_name(const Relobj* relobj, unsigned int shndx,
+			    const char* name, size_t* plen,
+			    std::map<Const_section_id, const char*>*
+			      section_segment_map)
 {
   // gcc 4.3 generates the following sorts of section names when it
   // needs a section name specific to a function:
@@ -4731,6 +4758,17 @@ Layout::output_section_name(const Relobj
   // not found in the table, we simply use it as the output section
   // name.
 
+
+  // Check if this input section is explicitly asked to be mapped to a
+  // different output section by a linker plugin.
+  std::map<Const_section_id, const char*>::iterator it
+    = section_segment_map->find(Const_section_id(relobj, shndx));
+  if (it != section_segment_map->end())
+    {
+      *plen = strlen (it->second);
+      return it->second;
+    }
+
   const Section_name_mapping* psnm = section_name_mapping;
   for (int i = 0; i < section_name_mapping_count; ++i, ++psnm)
     {
Index: gold/layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.103
diff -u -u -p -r1.103 layout.h
--- gold/layout.h	2 May 2012 21:37:23 -0000	1.103
+++ gold/layout.h	20 Jul 2012 22:51:49 -0000
@@ -527,6 +527,14 @@ class Layout
   std::map<Section_id, unsigned int>*
   get_section_order_map()
   { return &this->section_order_map_; }
+  
+  std::map<Const_section_id, const char*>*
+  get_section_segment_map()
+  { return &this->section_segment_map_; }
+
+  std::map<std::string, uint64_t>*
+  get_output_section_flags_map()
+  { return &this->output_section_flags_map_; }
 
   bool
   is_section_ordering_specified()
@@ -536,6 +544,14 @@ class Layout
   set_section_ordering_specified()
   { this->section_ordering_specified_ = true; }
 
+  bool
+  is_unique_segment_for_sections_specified()
+  { return this->unique_segment_for_sections_specified_; }
+
+  void
+  set_unique_segment_for_sections_specified()
+  { this->unique_segment_for_sections_specified_ = true; }
+
   // For incremental updates, allocate a block of memory from the
   // free list.  Find a block starting at or after MINOFF.
   off_t
@@ -1053,7 +1069,8 @@ class Layout
   // name.  Set *PLEN to the length of the name.  *PLEN must be
   // initialized to the length of NAME.
   static const char*
-  output_section_name(const Relobj*, const char* name, size_t* plen);
+  output_section_name(const Relobj*, unsigned int shndx, const char* name,
+		      size_t* plen, std::map<Const_section_id, const char*>* ssmap);
 
   // Return the number of allocated output sections.
   size_t
@@ -1067,7 +1084,8 @@ class Layout
 
   // Choose the output section for NAME in RELOBJ.
   Output_section*
-  choose_output_section(const Relobj* relobj, const char* name,
+  choose_output_section(const Relobj* relobj, unsigned int shndx,
+			const char* name,
 			elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
 			bool is_input_section, Output_section_order order,
 			bool is_relro);
@@ -1331,6 +1349,9 @@ class Layout
   // True if the input sections in the output sections should be sorted
   // as specified in a section ordering file.
   bool section_ordering_specified_;
+  // True if some input sections need to be mapped to an unique segment,
+  // after being mapped to a unique Output_section.
+  bool unique_segment_for_sections_specified_;
   // In incremental build, holds information check the inputs and build the
   // .gnu_incremental_inputs section.
   Incremental_inputs* incremental_inputs_;
@@ -1345,6 +1366,15 @@ class Layout
   // Plugins specify section_ordering using this map.  This is set in
   // update_section_order in plugin.cc
   std::map<Section_id, unsigned int> section_order_map_;
+  // This maps an input section to a particular output section name. Such
+  // output sections are then mapped to unique segments.
+  std::map<Const_section_id, const char*> section_segment_map_;
+  // This maps an output section name to a flags value.  The bits set in the
+  // flags value should also be set in the output section with this name.
+  // This is used when plugins create unique segments (hence output sections)
+  // for a subset of sections and want to set extra segment bits to identify
+  // such segments later.
+  std::map<std::string, uint64_t> output_section_flags_map_;
   // Hash a pattern to its position in the section ordering file.
   Unordered_map<std::string, unsigned int> input_section_position_;
   // Vector of glob only patterns in the section_ordering file.
Index: gold/object.cc
===================================================================
RCS file: /cvs/src/src/gold/object.cc,v
retrieving revision 1.155
diff -u -u -p -r1.155 object.cc
--- gold/object.cc	2 May 2012 21:37:23 -0000	1.155
+++ gold/object.cc	20 Jul 2012 22:51:49 -0000
@@ -1164,15 +1164,19 @@ Sized_relobj_file<size, big_endian>::lay
 // whether they should be included in the link.  If they should, we
 // pass them to the Layout object, which will return an output section
 // and an offset.
-// During garbage collection (--gc-sections) and identical code folding
-// (--icf), this function is called twice.  When it is called the first
-// time, it is for setting up some sections as roots to a work-list for
-// --gc-sections and to do comdat processing.  Actual layout happens the
-// second time around after all the relevant sections have been determined.
-// The first time, is_worklist_ready or is_icf_ready is false. It is then
-// set to true after the garbage collection worklist or identical code
-// folding is processed and the relevant sections to be kept are
-// determined.  Then, this function is called again to layout the sections.
+// This function is called twice sometimes, two passes, when mapping
+// of input sections to output sections must be delayed.
+// This is true for the following :
+// * Garbage collection (--gc-sections): Some input sections will be
+// discarded and hence the assignment must wait until the second pass.
+// In the first pass,  it is for setting up some sections as roots to
+// a work-list for --gc-sections and to do comdat processing.
+// * Identical Code Folding (--icf=<safe,all>): Some input sections
+// will be folded and hence the assignment must wait.
+// * Using plugins to map some sections to unique segments: Mapping
+// some sections to unique segments requires mapping them to unique
+// output sections too.  This can be done via plugins now and the
+// output section information is not available in the first pass.
 
 template<int size, bool big_endian>
 void
@@ -1181,26 +1185,42 @@ Sized_relobj_file<size, big_endian>::do_
 					       Read_symbols_data* sd)
 {
   const unsigned int shnum = this->shnum();
-  bool is_gc_pass_one = ((parameters->options().gc_sections()
-			  && !symtab->gc()->is_worklist_ready())
-			 || (parameters->options().icf_enabled()
-			     && !symtab->icf()->is_icf_ready()));
-
-  bool is_gc_pass_two = ((parameters->options().gc_sections()
-			  && symtab->gc()->is_worklist_ready())
-			 || (parameters->options().icf_enabled()
-			     && symtab->icf()->is_icf_ready()));
 
-  bool is_gc_or_icf = (parameters->options().gc_sections()
-		       || parameters->options().icf_enabled());
-
-  // Both is_gc_pass_one and is_gc_pass_two should not be true.
-  gold_assert(!(is_gc_pass_one  && is_gc_pass_two));
+  /* Should this function be called twice?  */
+  bool is_two_pass = (parameters->options().gc_sections()
+		      || parameters->options().icf_enabled()
+		      || layout->is_unique_segment_for_sections_specified());
+
+  bool is_pass_one = false;
+  bool is_pass_two = false;
+
+  /* Check if do_layout needs to be two-pass.  If so, find out which pass
+     should happen.  In the first pass, the data in sd is saved to be used
+     later in the second pass.  */
+  if (is_two_pass)
+    {
+      if (!this->get_symbols_data())
+	{
+	  gold_assert (sd != NULL);
+	  is_pass_one = true;
+	}
+      else
+	{
+	  if (parameters->options().gc_sections())
+	    gold_assert(symtab->gc()->is_worklist_ready());
+	  if (parameters->options().icf_enabled())
+	    gold_assert(symtab->icf()->is_icf_ready()); 
+	  is_pass_two = true;
+	}
+    }
+    
+  // Both is_pass_one and is_pass_two should not be true.
+  gold_assert(!(is_pass_one  && is_pass_two));
 
   if (shnum == 0)
     return;
   Symbols_data* gc_sd = NULL;
-  if (is_gc_pass_one)
+  if (is_pass_one)
     {
       // During garbage collection save the symbols data to use it when
       // re-entering this function.
@@ -1208,7 +1228,7 @@ Sized_relobj_file<size, big_endian>::do_
       this->copy_symbols_data(gc_sd, sd, This::shdr_size * shnum);
       this->set_symbols_data(gc_sd);
     }
-  else if (is_gc_pass_two)
+  else if (is_pass_two)
     {
       gc_sd = this->get_symbols_data();
     }
@@ -1220,7 +1240,7 @@ Sized_relobj_file<size, big_endian>::do_
   const unsigned char* symbol_names_data = NULL;
   section_size_type symbol_names_size;
 
-  if (is_gc_or_icf)
+  if (is_two_pass)
     {
       section_headers_data = gc_sd->section_headers_data;
       section_names_size = gc_sd->section_names_size;
@@ -1246,7 +1266,7 @@ Sized_relobj_file<size, big_endian>::do_
   const unsigned char* pshdrs;
 
   // Get the section names.
-  const unsigned char* pnamesu = (is_gc_or_icf)
+  const unsigned char* pnamesu = (is_two_pass)
 				 ? gc_sd->section_names_data
 				 : sd->section_names->data();
 
@@ -1298,7 +1318,7 @@ Sized_relobj_file<size, big_endian>::do_
   Output_sections& out_sections(this->output_sections());
   std::vector<Address>& out_section_offsets(this->section_offsets());
 
-  if (!is_gc_pass_two)
+  if (!is_pass_two)
     {
       out_sections.resize(shnum);
       out_section_offsets.resize(shnum);
@@ -1308,7 +1328,7 @@ Sized_relobj_file<size, big_endian>::do_
   // do here.
   if (this->input_file()->just_symbols())
     {
-      if (!is_gc_pass_two)
+      if (!is_pass_two)
 	{
 	  delete sd->section_headers;
 	  sd->section_headers = NULL;
@@ -1360,7 +1380,7 @@ Sized_relobj_file<size, big_endian>::do_
 
       const char* name = pnames + shdr.get_sh_name();
 
-      if (!is_gc_pass_two)
+      if (!is_pass_two)
 	{
 	  if (this->handle_gnu_warning_section(name, i, symtab))
 	    {
@@ -1434,7 +1454,7 @@ Sized_relobj_file<size, big_endian>::do_
 	    }
 	}
 
-      if (is_gc_pass_one && parameters->options().gc_sections())
+      if (is_pass_one && parameters->options().gc_sections())
 	{
 	  if (this->is_section_name_included(name)
 	      || shdr.get_sh_type() == elfcpp::SHT_INIT_ARRAY
@@ -1479,7 +1499,7 @@ Sized_relobj_file<size, big_endian>::do_
 	  && strcmp(name, ".eh_frame") == 0
 	  && this->check_eh_frame_flags(&shdr))
 	{
-	  if (is_gc_pass_one)
+	  if (is_pass_one)
 	    {
 	      out_sections[i] = reinterpret_cast<Output_section*>(1);
 	      out_section_offsets[i] = invalid_address;
@@ -1494,7 +1514,7 @@ Sized_relobj_file<size, big_endian>::do_
 	  continue;
 	}
 
-      if (is_gc_pass_two && parameters->options().gc_sections())
+      if (is_pass_two && parameters->options().gc_sections())
 	{
 	  // This is executed during the second pass of garbage
 	  // collection. do_layout has been called before and some
@@ -1519,7 +1539,7 @@ Sized_relobj_file<size, big_endian>::do_
 	      }
 	}
 
-      if (is_gc_pass_two && parameters->options().icf_enabled())
+      if (is_pass_two && parameters->options().icf_enabled())
 	{
 	  if (out_sections[i] == NULL)
 	    {
@@ -1553,7 +1573,7 @@ Sized_relobj_file<size, big_endian>::do_
       // should_defer_layout should be false.
       if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
 	{
-	  gold_assert(!is_gc_pass_two);
+	  gold_assert(!is_pass_two);
 	  this->deferred_layout_.push_back(Deferred_layout(i, name,
 							   pshdrs,
 							   reloc_shndx[i],
@@ -1568,11 +1588,11 @@ Sized_relobj_file<size, big_endian>::do_
       // During gc_pass_two if a section that was previously deferred is
       // found, do not layout the section as layout_deferred_sections will
       // do it later from gold.cc.
-      if (is_gc_pass_two
+      if (is_pass_two
 	  && (out_sections[i] == reinterpret_cast<Output_section*>(2)))
 	continue;
 
-      if (is_gc_pass_one)
+      if (is_pass_one)
 	{
 	  // This is during garbage collection. The out_sections are
 	  // assigned in the second call to this function.
@@ -1603,7 +1623,7 @@ Sized_relobj_file<size, big_endian>::do_
 	}
     }
 
-  if (!is_gc_pass_two)
+  if (!is_pass_two)
     layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags, this);
 
   // When doing a relocatable link handle the reloc sections at the
@@ -1612,7 +1632,7 @@ Sized_relobj_file<size, big_endian>::do_
   if (emit_relocs)
     this->size_relocatable_relocs();
 
-  gold_assert(!(is_gc_or_icf) || reloc_sections.empty());
+  gold_assert(!(is_two_pass) || reloc_sections.empty());
 
   for (std::vector<unsigned int>::const_iterator p = reloc_sections.begin();
        p != reloc_sections.end();
@@ -1659,7 +1679,7 @@ Sized_relobj_file<size, big_endian>::do_
     }
 
   // Handle the .eh_frame sections at the end.
-  gold_assert(!is_gc_pass_one || eh_frame_sections.empty());
+  gold_assert(!is_pass_one || eh_frame_sections.empty());
   for (std::vector<unsigned int>::const_iterator p = eh_frame_sections.begin();
        p != eh_frame_sections.end();
        ++p)
@@ -1682,7 +1702,7 @@ Sized_relobj_file<size, big_endian>::do_
 
   // When building a .gdb_index section, scan the .debug_info and
   // .debug_types sections.
-  gold_assert(!is_gc_pass_one
+  gold_assert(!is_pass_one
 	      || (debug_info_sections.empty() && debug_types_sections.empty()));
   for (std::vector<unsigned int>::const_iterator p
 	   = debug_info_sections.begin();
@@ -1703,7 +1723,7 @@ Sized_relobj_file<size, big_endian>::do_
 			       i, reloc_shndx[i], reloc_type[i]);
     }
 
-  if (is_gc_pass_two)
+  if (is_pass_two)
     {
       delete[] gc_sd->section_headers_data;
       delete[] gc_sd->section_names_data;
Index: gold/output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.167
diff -u -u -p -r1.167 output.cc
--- gold/output.cc	6 Jun 2012 22:12:47 -0000	1.167
+++ gold/output.cc	20 Jul 2012 22:51:49 -0000
@@ -2245,6 +2245,7 @@ Output_section::Output_section(const cha
     always_keeps_input_sections_(false),
     has_fixed_layout_(false),
     is_patch_space_allowed_(false),
+    is_unique_segment_(false),
     tls_offset_(0),
     checkpoint_(NULL),
     lookup_maps_(new Output_section_lookup_maps),
Index: gold/output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.135
diff -u -u -p -r1.135 output.h
--- gold/output.h	10 Jul 2012 14:54:29 -0000	1.135
+++ gold/output.h	20 Jul 2012 22:51:49 -0000
@@ -3249,6 +3249,14 @@ class Output_section : public Output_dat
   requires_postprocessing() const
   { return this->requires_postprocessing_; }
 
+  bool
+  is_unique_segment() const
+  { return this->is_unique_segment_; }
+
+  void
+  set_is_unique_segment()
+  { this->is_unique_segment_ = true; }
+
   // If a section requires postprocessing, return the buffer to use.
   unsigned char*
   postprocessing_buffer() const
@@ -4200,6 +4208,8 @@ class Output_section : public Output_dat
   bool has_fixed_layout_ : 1;
   // True if we can add patch space to this section.
   bool is_patch_space_allowed_ : 1;
+  // True if this output section goes into an unique segment.
+  bool is_unique_segment_ : 1;
   // For SHT_TLS sections, the offset of this section relative to the base
   // of the TLS segment.
   uint64_t tls_offset_;
Index: gold/plugin.cc
===================================================================
RCS file: /cvs/src/src/gold/plugin.cc,v
retrieving revision 1.54
diff -u -u -p -r1.54 plugin.cc
--- gold/plugin.cc	12 Jun 2012 22:52:41 -0000	1.54
+++ gold/plugin.cc	20 Jul 2012 22:51:49 -0000
@@ -115,6 +115,13 @@ update_section_order(const struct ld_plu
 static enum ld_plugin_status
 allow_section_ordering();
 
+static enum ld_plugin_status
+allow_unique_segment_for_sections();
+
+static enum ld_plugin_status
+unique_segment_for_sections(const char* segment_name, uint64_t flags,
+			    const struct ld_plugin_section *section_list,
+			    unsigned int num_sections);
 };
 
 #endif // ENABLE_PLUGINS
@@ -159,7 +166,7 @@ Plugin::load()
   sscanf(ver, "%d.%d", &major, &minor);
 
   // Allocate and populate a transfer vector.
-  const int tv_fixed_size = 24;
+  const int tv_fixed_size = 26;
 
   int tv_size = this->args_.size() + tv_fixed_size;
   ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
@@ -273,6 +280,15 @@ Plugin::load()
   tv[i].tv_u.tv_allow_section_ordering = allow_section_ordering;
 
   ++i;
+  tv[i].tv_tag = LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS;
+  tv[i].tv_u.tv_allow_unique_segment_for_sections
+    = allow_unique_segment_for_sections;
+
+  ++i;
+  tv[i].tv_tag = LDPT_UNIQUE_SEGMENT_FOR_SECTIONS;
+  tv[i].tv_u.tv_unique_segment_for_sections = unique_segment_for_sections;
+
+  ++i;
   tv[i].tv_tag = LDPT_NULL;
   tv[i].tv_u.tv_val = 0;
 
@@ -1685,6 +1701,64 @@ allow_section_ordering()
   return LDPS_OK;
 }
 
+// Let the linker know that a subset of sections could be mapped
+// to a unique segment.
+
+static enum ld_plugin_status
+allow_unique_segment_for_sections()
+{
+  gold_assert(parameters->options().has_plugins());
+  Layout* layout = parameters->options().plugins()->layout();
+  layout->set_unique_segment_for_sections_specified();
+  return LDPS_OK;
+}
+
+// This function should map the list of sections specified in the
+// SECTION_LIST to an unique segment.  ELF segments do not have names
+// and the NAME is used to identify Output Section which should contain
+// the list of sections.  This Output Section will then be mapped to
+// an unique segment.  FLAGS is used to specify if any additional segment
+// flags need to be set.  For instance, a specific segment flag can be
+// set to identify this segment.  Unsetting segment flags is not possible.
+static enum ld_plugin_status
+unique_segment_for_sections(const char* segment_name,
+			    uint64_t flags,
+			    const struct ld_plugin_section* section_list,
+			    unsigned int num_sections)
+{
+  gold_assert(parameters->options().has_plugins());
+
+  if (num_sections == 0)
+    return LDPS_OK;
+
+  if (section_list == NULL)
+    return LDPS_ERR;
+
+  Layout* layout = parameters->options().plugins()->layout();
+  gold_assert (layout != NULL);
+
+  std::map<Const_section_id, const char*>* section_segment_map
+    = layout->get_section_segment_map();
+
+  for (unsigned int i = 0; i < num_sections; ++i)
+    {
+      Object* obj = parameters->options().plugins()->get_elf_object(
+          section_list[i].handle);
+      if (obj == NULL)
+	return LDPS_BAD_HANDLE;
+      unsigned int shndx = section_list[i].shndx;
+      Const_section_id secn_id(obj, shndx);
+      (*section_segment_map)[secn_id] = segment_name;
+    }
+  
+  std::map<std::string, uint64_t>* output_section_flags_map
+    = layout->get_output_section_flags_map();
+
+  (*output_section_flags_map)[std::string(segment_name)] = flags;
+
+  return LDPS_OK;
+}
+
 #endif // ENABLE_PLUGINS
 
 // Allocate a Pluginobj object of the appropriate size and endianness.
Index: gold/testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.194
diff -u -u -p -r1.194 Makefile.am
--- gold/testsuite/Makefile.am	19 Jul 2012 00:19:34 -0000	1.194
+++ gold/testsuite/Makefile.am	20 Jul 2012 22:51:50 -0000
@@ -1519,13 +1519,15 @@ unused.c:
 	@cp /dev/null $@
 
 check_SCRIPTS += plugin_final_layout.sh
-check_DATA += plugin_final_layout.stdout
+check_DATA += plugin_final_layout.stdout plugin_final_layout.readelf.stdout
 plugin_final_layout.o: plugin_final_layout.cc
 	$(CXXCOMPILE) -O0 -c -ffunction-sections  -fdata-sections -g -o $@ $<
 plugin_final_layout: plugin_final_layout.o plugin_section_order.so gcctestdir/ld
 	$(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_section_order.so" plugin_final_layout.o
 plugin_final_layout.stdout: plugin_final_layout
 	$(TEST_NM) -n plugin_final_layout > plugin_final_layout.stdout
+plugin_final_layout.readelf.stdout: plugin_final_layout
+	$(TEST_READELF) -l plugin_final_layout > plugin_final_layout.readelf.stdout
 
 plugin_section_order.so: plugin_section_order.o
 	$(LINK) -Bgcctestdir/ -shared plugin_section_order.o
Index: gold/testsuite/plugin_final_layout.sh
===================================================================
RCS file: /cvs/src/src/gold/testsuite/plugin_final_layout.sh,v
retrieving revision 1.1
diff -u -u -p -r1.1 plugin_final_layout.sh
--- gold/testsuite/plugin_final_layout.sh	29 Sep 2011 23:45:57 -0000	1.1
+++ gold/testsuite/plugin_final_layout.sh	20 Jul 2012 22:51:50 -0000
@@ -56,5 +56,35 @@ END {
     }" $1
 }
 
+# With readelf -l, an ELF Section to Segment mapping is printed as :
+##############################################
+#  Section to Segment mapping:
+#  Segment Sections...
+#  ...
+#     0x     .text.plugin_created_unique
+#  ...
+##############################################
+# Check of .text.plugin_created_unique is the only section in the segment.
+check_unique_segment()
+{
+    awk "
+BEGIN { saw_section = 0; saw_unique = 0; }
+/$2/ { saw_section = 1; }
+/[ ]*0[0-9][ ]*$2[ ]*\$/ { saw_unique = 1; }
+END {
+      if (!saw_section)
+	{
+	  printf \"Section $2 not seen in output\\n\";
+	  exit 1;
+	}
+      else if (!saw_unique)
+	{
+	  printf \"Unique segment not seen for: $2\\n\";
+	  exit 1;
+	}
+    }" $1
+}
+
 check plugin_final_layout.stdout "_Z3foov" "_Z3barv"
 check plugin_final_layout.stdout "_Z3barv" "_Z3bazv"
+check_unique_segment plugin_final_layout.readelf.stdout ".text.plugin_created_unique"
Index: gold/testsuite/plugin_section_order.c
===================================================================
RCS file: /cvs/src/src/gold/testsuite/plugin_section_order.c,v
retrieving revision 1.1
diff -u -u -p -r1.1 plugin_section_order.c
--- gold/testsuite/plugin_section_order.c	29 Sep 2011 23:45:57 -0000	1.1
+++ gold/testsuite/plugin_section_order.c	20 Jul 2012 22:51:50 -0000
@@ -36,6 +36,8 @@ static ld_plugin_get_input_section_name 
 static ld_plugin_get_input_section_contents get_input_section_contents = NULL;
 static ld_plugin_update_section_order update_section_order = NULL;
 static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
+static ld_plugin_allow_unique_segment_for_sections allow_unique_segment_for_sections = NULL;
+static ld_plugin_unique_segment_for_sections unique_segment_for_sections = NULL;
 
 enum ld_plugin_status onload(struct ld_plugin_tv *tv);
 enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
@@ -76,6 +78,11 @@ onload(struct ld_plugin_tv *tv)
 	case LDPT_ALLOW_SECTION_ORDERING:
 	  allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
 	  break;
+	case LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS:
+	  allow_unique_segment_for_sections = *entry->tv_u.tv_allow_unique_segment_for_sections;
+	case LDPT_UNIQUE_SEGMENT_FOR_SECTIONS:
+	  unique_segment_for_sections = *entry->tv_u.tv_unique_segment_for_sections;
+	  break;
         default:
           break;
         }
@@ -86,7 +93,9 @@ onload(struct ld_plugin_tv *tv)
       || get_input_section_name == NULL
       || get_input_section_contents == NULL
       || update_section_order == NULL
-      || allow_section_ordering == NULL)
+      || allow_section_ordering == NULL
+      || allow_unique_segment_for_sections == NULL
+      || unique_segment_for_sections == NULL)
     {
       fprintf(stderr, "Some interfaces are missing\n");
       return LDPS_ERR;
@@ -117,6 +126,9 @@ claim_file_hook(const struct ld_plugin_i
     {
       /* Inform the linker to prepare for section reordering.  */
       (*allow_section_ordering)();
+      /* Inform the linker to prepare to map some sections to unique
+	 segments.  */
+      (*allow_unique_segment_for_sections)(); 
       is_ordering_specified = 1;
     }
 
@@ -160,7 +172,11 @@ enum ld_plugin_status
 all_symbols_read_hook(void)
 {
   if (num_entries == 3)
-    update_section_order(section_list, num_entries);
+    { 
+      update_section_order(section_list, num_entries);
+      unique_segment_for_sections (".text.plugin_created_unique", 0,
+				   section_list, num_entries);
+    }
 
   return LDPS_OK;
 }
Index: include/plugin-api.h
===================================================================
RCS file: /cvs/src/src/include/plugin-api.h,v
retrieving revision 1.19
diff -u -u -p -r1.19 plugin-api.h
--- include/plugin-api.h	12 Jun 2012 22:50:44 -0000	1.19
+++ include/plugin-api.h	20 Jul 2012 22:51:50 -0000
@@ -318,6 +318,29 @@ typedef
 enum ld_plugin_status
 (*ld_plugin_allow_section_ordering) (void);
 
+/* The linker's interface for specifying that a subset of sections is
+   to be mapped to a unique segment.  This should be invoked before
+   unique_segment_for_sections, preferably in the claim_file handler.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_allow_unique_segment_for_sections) (void);
+
+/* The linker's interface for specifying that a specific set of sections
+   must be mapped to an unique segment.  ELF segments do not have names
+   and the NAME is used as an identifier only.   FLAGS is used to specify
+   if any additional segment flags need to be set.  For instance, a
+   specific segment flag can be set to identify this segment.  Unsetting
+   segment flags that would be set by default is not possible. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_unique_segment_for_sections) (const char* segment_name,
+					  uint64_t segment_flags,
+					  const struct ld_plugin_section *
+					    section_list,
+					  unsigned int num_sections);
+
 enum ld_plugin_level
 {
   LDPL_INFO,
@@ -355,7 +378,9 @@ enum ld_plugin_tag
   LDPT_GET_INPUT_SECTION_CONTENTS,
   LDPT_UPDATE_SECTION_ORDER,
   LDPT_ALLOW_SECTION_ORDERING,
-  LDPT_GET_SYMBOLS_V2
+  LDPT_GET_SYMBOLS_V2,
+  LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS,
+  LDPT_UNIQUE_SEGMENT_FOR_SECTIONS
 };
 
 /* The plugin transfer vector.  */
@@ -385,6 +410,8 @@ struct ld_plugin_tv
     ld_plugin_get_input_section_contents tv_get_input_section_contents;
     ld_plugin_update_section_order tv_update_section_order;
     ld_plugin_allow_section_ordering tv_allow_section_ordering;
+    ld_plugin_allow_unique_segment_for_sections tv_allow_unique_segment_for_sections; 
+    ld_plugin_unique_segment_for_sections tv_unique_segment_for_sections;
   } tv_u;
 };
 


More information about the Binutils mailing list