public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment.
@ 2012-07-21  0:28 Sriraman Tallam
  2012-07-31 17:21 ` Sriraman Tallam
  0 siblings, 1 reply; 9+ messages in thread
From: Sriraman Tallam @ 2012-07-21  0:28 UTC (permalink / raw)
  To: binutils, Ian Lance Taylor, Cary Coutant

[-- Attachment #1: Type: text/plain, Size: 989 bytes --]

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.

[-- Attachment #2: segment_patch.txt --]
[-- Type: text/plain, Size: 43290 bytes --]

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;
 };
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment.
  2012-07-21  0:28 [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment Sriraman Tallam
@ 2012-07-31 17:21 ` Sriraman Tallam
  2012-08-03  6:44   ` Cary Coutant
  0 siblings, 1 reply; 9+ messages in thread
From: Sriraman Tallam @ 2012-07-31 17:21 UTC (permalink / raw)
  To: binutils, Ian Lance Taylor, Cary Coutant

Ping.

Thanks,
-Sri.

On Fri, Jul 20, 2012 at 5:28 PM, Sriraman Tallam <tmsriram@google.com> wrote:
> 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.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment.
  2012-07-31 17:21 ` Sriraman Tallam
@ 2012-08-03  6:44   ` Cary Coutant
  2012-08-10  0:56     ` Sriraman Tallam
  0 siblings, 1 reply; 9+ messages in thread
From: Cary Coutant @ 2012-08-03  6:44 UTC (permalink / raw)
  To: Sriraman Tallam; +Cc: binutils, Ian Lance Taylor

	* 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.

Please include the class name with the method name
(Layout::choose_output_section, Layout::output_section_name).

s/New parameter/Add parameter./

	(Layout::layout): Modify call to choose_output_section.
	Mark output section for mapping to an unique segment.

s/an unique/a unique/ (throughout)


@@ -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_);

This seems to be pushing the check for a remapped section too deep --
you're essentially turning a class method into an instance method
by passing it a pointer to instance data that it could have accessed
directly if it weren't static.

I think the lookup in section_segment_map should be made in
Layout::layout, just before it would call choose_output_section;
then you can call choose_output_section with the remapped name.

That would avoid the large number of places where you have to
pass '0' for shndx.


+      // 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();

This looks like a redundant test.  If you move the remap into
Layout::layout, you can just set a bool flag, and call
set_is_unique_segment right after choose_output_section returns.


+  /* 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())

Write this as "if (this->get_symbols_data() == NULL)".

Also, since you call get_symbols_data() again just a bit lower,
you may as well simply write:

       gc_sd = this->get_symbols_data();
       if (gc_sd == NULL)

+	{
+	  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));

I think the assert is unnecessary. It's pretty obvious from the code
immediately above that they're mutually exclusive.

What you could explain here (or, better, where the two bools are declared)
is that both will be false when it's *not* a two-pass layout.


+// 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.

Please add a blank line after this comment block.

+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)

Given the discussion upstream, I think you'll want to add the ability
for the plugin to select a specific segment alignment here as well.

+{
+  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();

Indent by four spaces here.

I think it would clear up the code if you made this a reference instead
of a pointer. It would also help to have a typedef for the 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;

Rather than have a second map keyed on the section name, I suggest
you store the flags (and alignment) as part of the section_segment_map.

Also, I think "section" flags is the wrong name -- it should be
"segment" flags.

It's also a bit confusing that you're creating a segment (which doesn't
have a name) by creating a new section (which does), and setting the
is_unique_segment flag on that section later when it actually gets
created. There's not much to do about that but clarify it in the
comments and documentation.


--- 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;

There are a few lines > 80 chars here.


+/* 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. */

NAME is still subject to some constraints, I think. You're going to create
an output section with that name, so I think it will need to be unique
in the namespace of section names.

+
+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);

Rewrite this parameter list with the first parameter on a new line,
indented by four spaces.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment.
  2012-08-03  6:44   ` Cary Coutant
@ 2012-08-10  0:56     ` Sriraman Tallam
  2012-08-22 21:41       ` Ian Lance Taylor
  0 siblings, 1 reply; 9+ messages in thread
From: Sriraman Tallam @ 2012-08-10  0:56 UTC (permalink / raw)
  To: Cary Coutant; +Cc: binutils, Ian Lance Taylor

[-- Attachment #1: Type: text/plain, Size: 11586 bytes --]

Hi Cary,

   I have attached the revised patch with all the mentioned changes done.

Thanks,
-Sri.

	* gold.cc (queue_middle_tasks): Call layout again when unique
	segments for sections is desired.
	* layout.cc (Layout::Layout): Initialize new members.
	(Layout::layout): Make output section for mapping to a unique segment.
	(Layout::attach_allocated_section_to_segment): Make unique segment for
	output sections marked so.
	(Layout::segment_precedes): Check for unique segments when sorting.
	* layout.h (Layout::Unique_segment_info): New struct.
	(Layout::Section_segment_map): New typedef.
	(Layout::get_section_segment_map): New function.
	(Layout::is_unique_segment_for_sections_specified): New function.
	(Layout::set_unique_segment_for_sections_specified): New function.
	(Layout::unique_segment_for_sections_specified_): New member.
	(Layout::section_segment_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
	members.
	* output.h (Output_section::is_unique_segment): New function.
	(Output_section::set_is_unique_segment): New function.
	(Output_section::is_unique_segment_): New member.
	(Output_section::extra_segment_flags): New function.
	(Output_section::set_extra_segment_flags): New function.
	(Output_section::extra_segment_flags_): New member.
	(Output_section::segment_alignment): New function.
	(Output_section::set_segment_alignment): New function.
	(Output_section::segment_alignment_): New member.
	(Output_segment::Output_segment): Initialize is_unique_segment_.
	(Output_segment::is_unique_segment): New function.
	(Output_segment::set_is_unique_segment): New function.
	(Output_segment::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.


	* 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.


On Thu, Aug 2, 2012 at 6:02 PM, Cary Coutant <ccoutant@google.com> wrote:
>         * 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.
>
> Please include the class name with the method name
> (Layout::choose_output_section, Layout::output_section_name).
>
> s/New parameter/Add parameter./
>
>         (Layout::layout): Modify call to choose_output_section.
>         Mark output section for mapping to an unique segment.
>
> s/an unique/a unique/ (throughout)
>
>
> @@ -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_);
>
> This seems to be pushing the check for a remapped section too deep --
> you're essentially turning a class method into an instance method
> by passing it a pointer to instance data that it could have accessed
> directly if it weren't static.
>
> I think the lookup in section_segment_map should be made in
> Layout::layout, just before it would call choose_output_section;
> then you can call choose_output_section with the remapped name.
>
> That would avoid the large number of places where you have to
> pass '0' for shndx.
>
>
> +      // 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();
>
> This looks like a redundant test.  If you move the remap into
> Layout::layout, you can just set a bool flag, and call
> set_is_unique_segment right after choose_output_section returns.
>
>
> +  /* 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())
>
> Write this as "if (this->get_symbols_data() == NULL)".
>
> Also, since you call get_symbols_data() again just a bit lower,
> you may as well simply write:
>
>        gc_sd = this->get_symbols_data();
>        if (gc_sd == NULL)
>
> +       {
> +         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));
>
> I think the assert is unnecessary. It's pretty obvious from the code
> immediately above that they're mutually exclusive.
>
> What you could explain here (or, better, where the two bools are declared)
> is that both will be false when it's *not* a two-pass layout.
>
>
> +// 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.
>
> Please add a blank line after this comment block.
>
> +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)
>
> Given the discussion upstream, I think you'll want to add the ability
> for the plugin to select a specific segment alignment here as well.
>
> +{
> +  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();
>
> Indent by four spaces here.
>
> I think it would clear up the code if you made this a reference instead
> of a pointer. It would also help to have a typedef for the 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;
>
> Rather than have a second map keyed on the section name, I suggest
> you store the flags (and alignment) as part of the section_segment_map.
>
> Also, I think "section" flags is the wrong name -- it should be
> "segment" flags.
>
> It's also a bit confusing that you're creating a segment (which doesn't
> have a name) by creating a new section (which does), and setting the
> is_unique_segment flag on that section later when it actually gets
> created. There's not much to do about that but clarify it in the
> comments and documentation.
>
>
> --- 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;
>
> There are a few lines > 80 chars here.
>
>
> +/* 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. */
>
> NAME is still subject to some constraints, I think. You're going to create
> an output section with that name, so I think it will need to be unique
> in the namespace of section names.
>
> +
> +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);
>
> Rewrite this parameter list with the first parameter on a new line,
> indented by four spaces.

[-- Attachment #2: segment_patch.txt --]
[-- Type: text/plain, Size: 37005 bytes --]

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	9 Aug 2012 21:28:02 -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.232
diff -u -u -p -r1.232 layout.cc
--- gold/layout.cc	7 Aug 2012 13:24:47 -0000	1.232
+++ gold/layout.cc	9 Aug 2012 21:28:02 -0000
@@ -408,12 +408,14 @@ 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_(),
     input_section_position_(),
     input_section_glob_(),
     incremental_base_(NULL),
@@ -1028,9 +1030,48 @@ Layout::layout(Sized_relobj_file<size, b
     }
   else
     {
-      os = this->choose_output_section(object, name, sh_type,
-				       shdr.get_sh_flags(), true,
-				       ORDER_INVALID, false);
+      // Plugins can choose to place one or more subsets of sections in
+      // unique segments and this is done by mapping these section subsets
+      // to unique output sections.  Check if this section needs to be
+      // remapped to a unique output section.
+      Section_segment_map::iterator it
+	  = this->section_segment_map_.find(Const_section_id(object, shndx));
+      if (it != this->section_segment_map_.end())
+	{
+	  // We know the name of the output section, directly call
+	  // get_output_section here by-passing choose_output_section.
+	  elfcpp::Elf_Xword flags = shdr.get_sh_flags();
+	  // Some flags in the input section should not be automatically
+	  // copied to the output section.
+	  flags &= ~ (elfcpp::SHF_INFO_LINK
+		      | elfcpp::SHF_GROUP
+		      | elfcpp::SHF_MERGE
+		      | elfcpp::SHF_STRINGS);
+
+	  // We only clear the SHF_LINK_ORDER flag in for
+	  // a non-relocatable link.
+	  if (!parameters->options().relocatable())
+	    flags &= ~elfcpp::SHF_LINK_ORDER;
+	  
+	  const char* os_name = it->second->name;
+	  Stringpool::Key name_key;
+	  os_name = this->namepool_.add_with_length(os_name, strlen(os_name),
+						    true, &name_key);
+	  os = this->get_output_section(os_name, name_key, sh_type, flags,
+					ORDER_INVALID, false);
+	  if (!os->is_unique_segment())
+	    {
+	      os->set_is_unique_segment();
+	      os->set_extra_segment_flags(it->second->flags);
+	      os->set_segment_alignment(it->second->align);
+	    }
+	}
+      else
+	{
+          os = this->choose_output_section(object, name, sh_type,
+					   shdr.get_sh_flags(), true,
+					   ORDER_INVALID, false);
+	}
       if (os == NULL)
 	return NULL;
     }
@@ -1692,6 +1733,10 @@ 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,
+  // coming from a linker plugin, do that.
+  seg_flags |= os->extra_segment_flags();
+
   // Check for --section-start.
   uint64_t addr;
   bool is_address_set = parameters->options().section_start(os->name(), &addr);
@@ -1708,8 +1753,14 @@ Layout::attach_allocated_section_to_segm
        p != this->segment_list_.end();
        ++p)
     {
+      // No need to go through the loop if a unique segment is needed.
+      if (os->is_unique_segment())
+        break;
       if ((*p)->type() != elfcpp::PT_LOAD)
 	continue;
+      // If this segment is marked unique, skip.
+      if ((*p)->is_unique_segment())
+	continue;
       if (!parameters->options().omagic()
 	  && ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W))
 	continue;
@@ -1742,7 +1793,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);
@@ -1751,6 +1803,14 @@ Layout::attach_allocated_section_to_segm
       oseg->add_output_section_to_load(this, os, seg_flags);
       if (is_address_set)
 	oseg->set_addresses(addr, addr);
+      // Check if segment should be marked unique.  For segments marked
+      // unique by linker plugins, set the new alignment if specified.
+      if (os->is_unique_segment())
+	{
+	  oseg->set_is_unique_segment();
+	  if (os->segment_alignment())
+	    oseg->set_minimum_p_align(os->segment_alignment());
+	}
     }
 
   // If we see a loadable SHT_NOTE section, we create a PT_NOTE
@@ -3095,9 +3155,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;
 }
 
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	9 Aug 2012 21:28:02 -0000
@@ -528,6 +528,29 @@ class Layout
   get_section_order_map()
   { return &this->section_order_map_; }
 
+  // Struct to store segment info when mapping some input sections to
+  // unique segments using linker plugins.  Mapping an input section to
+  // a unique segment is done by first placing such input sections in
+  // unique output sections and then mapping the output section to a
+  // unique segment.  NAME is the name of the output section.  FLAGS
+  // and ALIGN are the extra flags and alignment of the segment.
+  typedef struct
+  {
+    // Identifier for the Segment.  ELF Segments dont have names.
+    const char* name;
+    // Segment flags.
+    uint64_t flags;
+    uint64_t align;
+  } Unique_segment_info; 
+
+  // Mapping from input section to segment.
+  typedef std::map<Const_section_id, Unique_segment_info*>
+  Section_segment_map;
+
+  Section_segment_map&
+  get_section_segment_map()
+  { return this->section_segment_map_; }
+  
   bool
   is_section_ordering_specified()
   { return this->section_ordering_specified_; }
@@ -536,6 +559,14 @@ class Layout
   set_section_ordering_specified()
   { this->section_ordering_specified_ = true; }
 
+  bool
+  is_unique_segment_for_sections_specified() const
+  { 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
@@ -1331,6 +1362,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 a 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 +1379,11 @@ 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 unique segment. This is done by first
+  // placing such input sections in unique output sections and then mapping
+  // the output section to a unique segment.  Unique_segment_info stores
+  // any additional flags and alignment of the new segment.
+  Section_segment_map section_segment_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	9 Aug 2012 21:28:03 -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 this
+// information is not available in the first pass.
 
 template<int size, bool big_endian>
 void
@@ -1181,26 +1185,44 @@ 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());
+  /* 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());
+
+  /* Only one of is_pass_one and is_pass_two is true.  Both are false when
+     a two-pass approach is not needed.  */
+  bool is_pass_one = false;
+  bool is_pass_two = false;
 
-  // Both is_gc_pass_one and is_gc_pass_two should not be true.
-  gold_assert(!(is_gc_pass_one  && is_gc_pass_two));
+  Symbols_data* gc_sd = NULL;
 
+  /* 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)
+    {
+      gc_sd = this->get_symbols_data();
+      if (gc_sd == NULL)
+	{
+	  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;
+	}
+    }
+    
   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,10 +1230,6 @@ 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)
-    {
-      gc_sd = this->get_symbols_data();
-    }
 
   const unsigned char* section_headers_data = NULL;
   section_size_type section_names_size;
@@ -1220,7 +1238,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 +1264,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 +1316,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 +1326,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 +1378,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 +1452,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 +1497,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 +1512,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 +1537,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 +1571,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 +1586,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 +1621,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 +1630,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 +1677,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 +1700,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 +1721,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	9 Aug 2012 21:28:03 -0000
@@ -2245,7 +2245,10 @@ 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),
+    extra_segment_flags_(0),
+    segment_alignment_(0),
     checkpoint_(NULL),
     lookup_maps_(new Output_section_lookup_maps),
     free_list_(),
@@ -3979,7 +3982,8 @@ Output_segment::Output_segment(elfcpp::E
     flags_(flags),
     is_max_align_known_(false),
     are_addresses_set_(false),
-    is_large_data_segment_(false)
+    is_large_data_segment_(false),
+    is_unique_segment_(false)
 {
   // The ELF ABI specifies that a PT_TLS segment always has PF_R as
   // the flags.
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	9 Aug 2012 21:28:03 -0000
@@ -3249,6 +3249,29 @@ 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; }
+
+  uint64_t extra_segment_flags() const
+  { return extra_segment_flags_; }
+
+  void
+  set_extra_segment_flags(uint64_t flags)
+  { extra_segment_flags_ = flags; }
+
+  uint64_t segment_alignment() const
+  { return segment_alignment_; }
+
+  void
+  set_segment_alignment(uint64_t align)
+  { segment_alignment_ = align; }
+  
+
   // If a section requires postprocessing, return the buffer to use.
   unsigned char*
   postprocessing_buffer() const
@@ -4200,9 +4223,17 @@ 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 a 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_;
+  // Additional segment flags, specified via linker plugin, when mapping some
+  // input sections to unique segments.
+  uint64_t extra_segment_flags_; 
+  // Segment alignment specified via linker plugin, when mapping some
+  // input sections to unique segments.
+  uint64_t segment_alignment_;
   // Saved checkpoint.
   Checkpoint_output_section* checkpoint_;
   // Fast lookup maps for merged and relaxed input sections.
@@ -4278,6 +4309,16 @@ class Output_segment
   set_is_large_data_segment()
   { this->is_large_data_segment_ = true; }
 
+  bool
+  is_unique_segment() const
+  { return is_unique_segment_; }
+
+  // Mark segment as unique, happens when linker plugins request that
+  // certain input sections be mapped to unique segments.
+  void
+  set_is_unique_segment()
+  { this->is_unique_segment_ = true; }
+
   // Return the maximum alignment of the Output_data.
   uint64_t
   maximum_alignment();
@@ -4488,6 +4529,8 @@ class Output_segment
   bool are_addresses_set_ : 1;
   // Whether this segment holds large data sections.
   bool is_large_data_segment_ : 1;
+  // Whether this was marked as a unique segment via a linker plugin.
+  bool is_unique_segment_ : 1;
 };
 
 // This class represents the output file.
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	9 Aug 2012 21:28:03 -0000
@@ -115,6 +115,15 @@ 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,
+			    uint64_t align,
+			    const struct ld_plugin_section *section_list,
+			    unsigned int num_sections);
 };
 
 #endif // ENABLE_PLUGINS
@@ -159,7 +168,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 +282,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 +1703,68 @@ 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 a 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
+// a 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.
+// ALIGN specifies the alignment of the segment.
+
+static enum ld_plugin_status
+unique_segment_for_sections(const char* segment_name,
+			    uint64_t flags,
+			    uint64_t align,
+			    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);
+
+  Layout::Section_segment_map& section_segment_map
+      = layout->get_section_segment_map();
+
+  Layout::Unique_segment_info* s = static_cast<Layout::Unique_segment_info*>
+      (malloc(sizeof(Layout::Unique_segment_info)));
+  s->name = segment_name;
+  s->flags = flags;
+  s->align = align;
+
+  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] = s;
+    }
+
+  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	9 Aug 2012 21:28:03 -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/Makefile.in
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.in,v
retrieving revision 1.204
diff -u -u -p -r1.204 Makefile.in
--- gold/testsuite/Makefile.in	19 Jul 2012 00:19:35 -0000	1.204
+++ gold/testsuite/Makefile.in	9 Aug 2012 21:28:04 -0000
@@ -329,7 +329,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__E
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_7.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_7.syms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_9.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_final_layout.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_final_layout.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_final_layout.readelf.stdout
 # Make a copy of two_file_test_1.o, which does not define the symbol _Z4t16av.
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_36 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_1.err \
@@ -4867,6 +4868,8 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_section_order.so" plugin_final_layout.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.stdout: plugin_final_layout
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(TEST_NM) -n plugin_final_layout > plugin_final_layout.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.readelf.stdout: plugin_final_layout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(TEST_READELF) -l plugin_final_layout > plugin_final_layout.readelf.stdout
 
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_section_order.so: plugin_section_order.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(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	9 Aug 2012 21:28:04 -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	9 Aug 2012 21:28:04 -0000
@@ -36,6 +36,9 @@ 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,
@@ -52,11 +55,13 @@ onload(struct ld_plugin_tv *tv)
       switch (entry->tv_tag)
         {
         case LDPT_REGISTER_CLAIM_FILE_HOOK:
-          assert((*entry->tv_u.tv_register_claim_file) (claim_file_hook) == LDPS_OK);
+          assert((*entry->tv_u.tv_register_claim_file) (claim_file_hook)
+		 == LDPS_OK);
           break;
 	case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
-          assert((*entry->tv_u.tv_register_all_symbols_read) (all_symbols_read_hook)
-		  == LDPS_OK);
+          assert((*entry->tv_u.tv_register_all_symbols_read)
+		     (all_symbols_read_hook)
+		 == LDPS_OK);
           break;
         case LDPT_GET_INPUT_SECTION_COUNT:
           get_input_section_count = *entry->tv_u.tv_get_input_section_count;
@@ -68,7 +73,8 @@ onload(struct ld_plugin_tv *tv)
           get_input_section_name = *entry->tv_u.tv_get_input_section_name;
           break;
         case LDPT_GET_INPUT_SECTION_CONTENTS:
-          get_input_section_contents = *entry->tv_u.tv_get_input_section_contents;
+          get_input_section_contents
+	      = *entry->tv_u.tv_get_input_section_contents;
           break;
 	case LDPT_UPDATE_SECTION_ORDER:
 	  update_section_order = *entry->tv_u.tv_update_section_order;
@@ -76,6 +82,13 @@ 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 +99,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 +132,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,8 +178,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, 0x1000,
+				   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	9 Aug 2012 21:28:04 -0000
@@ -318,6 +318,31 @@ 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 a 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.  The
+   parameter SEGMENT_ALIGNMENT when non-zero will override the default.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_unique_segment_for_sections) (
+    const char* segment_name,
+    uint64_t segment_flags,
+    uint64_t segment_alignment,
+    const struct ld_plugin_section * section_list,
+    unsigned int num_sections);
+
 enum ld_plugin_level
 {
   LDPL_INFO,
@@ -355,7 +380,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 +412,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;
 };
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment.
  2012-08-10  0:56     ` Sriraman Tallam
@ 2012-08-22 21:41       ` Ian Lance Taylor
  2012-08-23  4:14         ` Sriraman Tallam
  0 siblings, 1 reply; 9+ messages in thread
From: Ian Lance Taylor @ 2012-08-22 21:41 UTC (permalink / raw)
  To: Sriraman Tallam; +Cc: Cary Coutant, binutils

On Thu, Aug 9, 2012 at 2:32 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>
>         * gold.cc (queue_middle_tasks): Call layout again when unique
>         segments for sections is desired.
>         * layout.cc (Layout::Layout): Initialize new members.
>         (Layout::layout): Make output section for mapping to a unique segment.
>         (Layout::attach_allocated_section_to_segment): Make unique segment for
>         output sections marked so.
>         (Layout::segment_precedes): Check for unique segments when sorting.
>         * layout.h (Layout::Unique_segment_info): New struct.
>         (Layout::Section_segment_map): New typedef.
>         (Layout::get_section_segment_map): New function.
>         (Layout::is_unique_segment_for_sections_specified): New function.
>         (Layout::set_unique_segment_for_sections_specified): New function.
>         (Layout::unique_segment_for_sections_specified_): New member.
>         (Layout::section_segment_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
>         members.
>         * output.h (Output_section::is_unique_segment): New function.
>         (Output_section::set_is_unique_segment): New function.
>         (Output_section::is_unique_segment_): New member.
>         (Output_section::extra_segment_flags): New function.
>         (Output_section::set_extra_segment_flags): New function.
>         (Output_section::extra_segment_flags_): New member.
>         (Output_section::segment_alignment): New function.
>         (Output_section::set_segment_alignment): New function.
>         (Output_section::segment_alignment_): New member.
>         (Output_segment::Output_segment): Initialize is_unique_segment_.
>         (Output_segment::is_unique_segment): New function.
>         (Output_segment::set_is_unique_segment): New function.
>         (Output_segment::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.
>
>
>         * 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.

> +      if (it != this->section_segment_map_.end())
> +	{
> +	  // We know the name of the output section, directly call
> +	  // get_output_section here by-passing choose_output_section.
> +	  elfcpp::Elf_Xword flags = shdr.get_sh_flags();

Please invert this conditional, so the common and shorter case appears.  That is
  if (it == this->section_segment_map_.end())
    os = this->choose_output_section(...);
  else
    {
      ...
    }

> +	  // We know the name of the output section, directly call
> +	  // get_output_section here by-passing choose_output_section.
> +	  elfcpp::Elf_Xword flags = shdr.get_sh_flags();
> +	  // Some flags in the input section should not be automatically
> +	  // copied to the output section.
> +	  flags &= ~ (elfcpp::SHF_INFO_LINK
> +		      | elfcpp::SHF_GROUP
> +		      | elfcpp::SHF_MERGE
> +		      | elfcpp::SHF_STRINGS);
> +
> +	  // We only clear the SHF_LINK_ORDER flag in for
> +	  // a non-relocatable link.
> +	  if (!parameters->options().relocatable())
> +	    flags &= ~elfcpp::SHF_LINK_ORDER;

This code is too finicky to have two copies.  Please refactor into a
common function one way or another.

> +	  os_name = this->namepool_.add_with_length(os_name, strlen(os_name),
> +						    true, &name_key);

Don't call add_with_length(x, strlen(x), ...).  Just call add().

> +      // If this segment is marked unique, skip.

This comment adds nothing to the code.

> +	  if (os->segment_alignment())

os->segment_alignment is not a bool: write os->segment_alignment() != 0.

> +  typedef struct
> +  {
> +    // Identifier for the Segment.  ELF Segments dont have names.
> +    const char* name;
> +    // Segment flags.
> +    uint64_t flags;
> +    uint64_t align;
> +  } Unique_segment_info;

This is C++, not C.  Don't write typedef struct { } S.  Just write struct S { }.

The align field should have a comment.  The flags field comment should
say something like "Additional segment flags."

> +  Section_segment_map&
> +  get_section_segment_map()
> +  { return this->section_segment_map_; }

gold doesn't use non-const references as function parameter or return
types.  This should be a pointer.

> +	  gold_assert (sd != NULL);

Remove space before left parenthesis.

Thanks for the cleanups here.

> +  const unsigned char* pnamesu = (is_two_pass)
>  				 ? gc_sd->section_names_data
>  				 : sd->section_names->data();

It's not new in this patch, but the parenthesization here is wrong.
It should be
   ... = (is_two_pass
           ? ...
           : ...);

The ? and : should be lined up under the start of the condition (i.e.,
under the 'i').

L +  gold_assert(!(is_two_pass) || reloc_sections.empty());

No need to parenthesize is_two_pass.

> +  uint64_t extra_segment_flags() const
> +  { return extra_segment_flags_; }
> +
> +  void
> +  set_extra_segment_flags(uint64_t flags)
> +  { extra_segment_flags_ = flags; }
> +
> +  uint64_t segment_alignment() const
> +  { return segment_alignment_; }
> +
> +  void
> +  set_segment_alignment(uint64_t align)
> +  { segment_alignment_ = align; }

This functions are all missing "this->".

> +  bool
> +  is_unique_segment() const
> +  { return is_unique_segment_; }
> +
> +  // Mark segment as unique, happens when linker plugins request that
> +  // certain input sections be mapped to unique segments.
> +  void
> +  set_is_unique_segment()
> +  { this->is_unique_segment_ = true; }

Missing this-> here too.

> +  Layout* layout = parameters->options().plugins()->layout();
> +  gold_assert (layout != NULL);

Somewhere here you should ensure that the plugin called the
LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS entry point.

> +  Layout::Unique_segment_info* s = static_cast<Layout::Unique_segment_info*>
> +      (malloc(sizeof(Layout::Unique_segment_info)));

This is C++.  You mean
  Layout::Unique_segment_info* s = new Unique_segment_info;

> +      section_segment_map[secn_id] = s;

Rather than have Layout return a pointer to its private data member, I
would prefer to see a Layout method that saves this value.  And that
Layout method should assert unique_segment_for_sections_specified_.

> +check_DATA += plugin_final_layout.stdout plugin_final_layout.readelf.stdout

Stick to a single '.' per fliename.
plugin_final_layout_readelf.stdout is fine here.

> With readelf -l, an ELF Section to Segment mapping is printed as :

readelf can be a bit unpredictable: I recommend using the -W option as well.

> +/* 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.  */

This is a "must", not a "should".  How about something along the lines
of "If the plugin wants to call unique_segment_for_sections, it must
call this function from a claim_file handler or when it is first
loaded."

Sorry for the slow review.

Ian

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment.
  2012-08-22 21:41       ` Ian Lance Taylor
@ 2012-08-23  4:14         ` Sriraman Tallam
  2012-08-24 17:41           ` Ian Lance Taylor
  2012-08-24 17:44           ` Cary Coutant
  0 siblings, 2 replies; 9+ messages in thread
From: Sriraman Tallam @ 2012-08-23  4:14 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Cary Coutant, binutils

[-- Attachment #1: Type: text/plain, Size: 8972 bytes --]

Hi Ian,

    I have made all the changes and attached the patch.

Thanks,
-Sri.

On Wed, Aug 22, 2012 at 10:59 AM, Ian Lance Taylor <iant@google.com> wrote:
> On Thu, Aug 9, 2012 at 2:32 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>>
>>         * gold.cc (queue_middle_tasks): Call layout again when unique
>>         segments for sections is desired.
>>         * layout.cc (Layout::Layout): Initialize new members.
>>         (Layout::layout): Make output section for mapping to a unique segment.
>>         (Layout::attach_allocated_section_to_segment): Make unique segment for
>>         output sections marked so.
>>         (Layout::segment_precedes): Check for unique segments when sorting.
>>         * layout.h (Layout::Unique_segment_info): New struct.
>>         (Layout::Section_segment_map): New typedef.
>>         (Layout::get_section_segment_map): New function.
>>         (Layout::is_unique_segment_for_sections_specified): New function.
>>         (Layout::set_unique_segment_for_sections_specified): New function.
>>         (Layout::unique_segment_for_sections_specified_): New member.
>>         (Layout::section_segment_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
>>         members.
>>         * output.h (Output_section::is_unique_segment): New function.
>>         (Output_section::set_is_unique_segment): New function.
>>         (Output_section::is_unique_segment_): New member.
>>         (Output_section::extra_segment_flags): New function.
>>         (Output_section::set_extra_segment_flags): New function.
>>         (Output_section::extra_segment_flags_): New member.
>>         (Output_section::segment_alignment): New function.
>>         (Output_section::set_segment_alignment): New function.
>>         (Output_section::segment_alignment_): New member.
>>         (Output_segment::Output_segment): Initialize is_unique_segment_.
>>         (Output_segment::is_unique_segment): New function.
>>         (Output_segment::set_is_unique_segment): New function.
>>         (Output_segment::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.
>>
>>
>>         * 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.
>
>> +      if (it != this->section_segment_map_.end())
>> +     {
>> +       // We know the name of the output section, directly call
>> +       // get_output_section here by-passing choose_output_section.
>> +       elfcpp::Elf_Xword flags = shdr.get_sh_flags();
>
> Please invert this conditional, so the common and shorter case appears.  That is
>   if (it == this->section_segment_map_.end())
>     os = this->choose_output_section(...);
>   else
>     {
>       ...
>     }
>
>> +       // We know the name of the output section, directly call
>> +       // get_output_section here by-passing choose_output_section.
>> +       elfcpp::Elf_Xword flags = shdr.get_sh_flags();
>> +       // Some flags in the input section should not be automatically
>> +       // copied to the output section.
>> +       flags &= ~ (elfcpp::SHF_INFO_LINK
>> +                   | elfcpp::SHF_GROUP
>> +                   | elfcpp::SHF_MERGE
>> +                   | elfcpp::SHF_STRINGS);
>> +
>> +       // We only clear the SHF_LINK_ORDER flag in for
>> +       // a non-relocatable link.
>> +       if (!parameters->options().relocatable())
>> +         flags &= ~elfcpp::SHF_LINK_ORDER;
>
> This code is too finicky to have two copies.  Please refactor into a
> common function one way or another.
>
>> +       os_name = this->namepool_.add_with_length(os_name, strlen(os_name),
>> +                                                 true, &name_key);
>
> Don't call add_with_length(x, strlen(x), ...).  Just call add().
>
>> +      // If this segment is marked unique, skip.
>
> This comment adds nothing to the code.
>
>> +       if (os->segment_alignment())
>
> os->segment_alignment is not a bool: write os->segment_alignment() != 0.
>
>> +  typedef struct
>> +  {
>> +    // Identifier for the Segment.  ELF Segments dont have names.
>> +    const char* name;
>> +    // Segment flags.
>> +    uint64_t flags;
>> +    uint64_t align;
>> +  } Unique_segment_info;
>
> This is C++, not C.  Don't write typedef struct { } S.  Just write struct S { }.
>
> The align field should have a comment.  The flags field comment should
> say something like "Additional segment flags."
>
>> +  Section_segment_map&
>> +  get_section_segment_map()
>> +  { return this->section_segment_map_; }
>
> gold doesn't use non-const references as function parameter or return
> types.  This should be a pointer.
>
>> +       gold_assert (sd != NULL);
>
> Remove space before left parenthesis.
>
> Thanks for the cleanups here.
>
>> +  const unsigned char* pnamesu = (is_two_pass)
>>                                ? gc_sd->section_names_data
>>                                : sd->section_names->data();
>
> It's not new in this patch, but the parenthesization here is wrong.
> It should be
>    ... = (is_two_pass
>            ? ...
>            : ...);
>
> The ? and : should be lined up under the start of the condition (i.e.,
> under the 'i').
>
> L +  gold_assert(!(is_two_pass) || reloc_sections.empty());
>
> No need to parenthesize is_two_pass.
>
>> +  uint64_t extra_segment_flags() const
>> +  { return extra_segment_flags_; }
>> +
>> +  void
>> +  set_extra_segment_flags(uint64_t flags)
>> +  { extra_segment_flags_ = flags; }
>> +
>> +  uint64_t segment_alignment() const
>> +  { return segment_alignment_; }
>> +
>> +  void
>> +  set_segment_alignment(uint64_t align)
>> +  { segment_alignment_ = align; }
>
> This functions are all missing "this->".
>
>> +  bool
>> +  is_unique_segment() const
>> +  { return is_unique_segment_; }
>> +
>> +  // Mark segment as unique, happens when linker plugins request that
>> +  // certain input sections be mapped to unique segments.
>> +  void
>> +  set_is_unique_segment()
>> +  { this->is_unique_segment_ = true; }
>
> Missing this-> here too.
>
>> +  Layout* layout = parameters->options().plugins()->layout();
>> +  gold_assert (layout != NULL);
>
> Somewhere here you should ensure that the plugin called the
> LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS entry point.
>
>> +  Layout::Unique_segment_info* s = static_cast<Layout::Unique_segment_info*>
>> +      (malloc(sizeof(Layout::Unique_segment_info)));
>
> This is C++.  You mean
>   Layout::Unique_segment_info* s = new Unique_segment_info;
>
>> +      section_segment_map[secn_id] = s;
>
> Rather than have Layout return a pointer to its private data member, I
> would prefer to see a Layout method that saves this value.  And that
> Layout method should assert unique_segment_for_sections_specified_.
>
>> +check_DATA += plugin_final_layout.stdout plugin_final_layout.readelf.stdout
>
> Stick to a single '.' per fliename.
> plugin_final_layout_readelf.stdout is fine here.
>
>> With readelf -l, an ELF Section to Segment mapping is printed as :
>
> readelf can be a bit unpredictable: I recommend using the -W option as well.
>
>> +/* 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.  */
>
> This is a "must", not a "should".  How about something along the lines
> of "If the plugin wants to call unique_segment_for_sections, it must
> call this function from a claim_file handler or when it is first
> loaded."
>
> Sorry for the slow review.
>
> Ian

[-- Attachment #2: segment_patch.txt --]
[-- Type: text/plain, Size: 42294 bytes --]




	* gold.cc (queue_middle_tasks): Call layout again when unique
	segments for sections is desired.
	* layout.cc (Layout::Layout): Initialize new members.
	(Layout::get_output_section_flags): New function.
	(Layout::choose_output_section): Call get_output_section_flags.
	(Layout::layout): Make output section for mapping to a unique segment.
	(Layout::insert_section_segment_map): New function.
	(Layout::attach_allocated_section_to_segment): Make unique segment for
	output sections marked so. 
	(Layout::segment_precedes): Check for unique segments when sorting.
	* layout.h (Layout::Unique_segment_info): New struct.
	(Layout::Section_segment_map): New typedef.
	(Layout::insert_section_segment_map): New function.
	(Layout::get_output_section_flags): New function.
	(Layout::is_unique_segment_for_sections_specified): New function.
	(Layout::set_unique_segment_for_sections_specified): New function.
	(Layout::unique_segment_for_sections_specified_): New member.
	(Layout::section_segment_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
	members.
	* output.h (Output_section::is_unique_segment): New function.
	(Output_section::set_is_unique_segment): New function.
	(Output_section::is_unique_segment_): New member.
	(Output_section::extra_segment_flags): New function.
	(Output_section::set_extra_segment_flags): New function.
	(Output_section::extra_segment_flags_): New member.
	(Output_section::segment_alignment): New function.
	(Output_section::set_segment_alignment): New function.
	(Output_section::segment_alignment_): New member.
	(Output_segment::Output_segment): Initialize is_unique_segment_.
	(Output_segment::is_unique_segment): New function.
	(Output_segment::set_is_unique_segment): New function.
	(Output_segment::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.

	* 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.

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	23 Aug 2012 02:32:29 -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.235
diff -u -u -p -r1.235 layout.cc
--- gold/layout.cc	22 Aug 2012 18:26:32 -0000	1.235
+++ gold/layout.cc	23 Aug 2012 02:32:29 -0000
@@ -408,12 +408,14 @@ 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_(),
     input_section_position_(),
     input_section_glob_(),
     incremental_base_(NULL),
@@ -824,6 +826,27 @@ Layout::keep_input_section(const Relobj*
   return name != NULL && keep;
 }
 
+// Clear the input section flags that should not be copied to the
+// output section.
+
+elfcpp::Elf_Xword
+Layout::get_output_section_flags(elfcpp::Elf_Xword input_section_flags)
+{
+  // Some flags in the input section should not be automatically
+  // copied to the output section.
+  input_section_flags &= ~ (elfcpp::SHF_INFO_LINK
+			    | elfcpp::SHF_GROUP
+			    | elfcpp::SHF_MERGE
+			    | elfcpp::SHF_STRINGS);
+
+  // We only clear the SHF_LINK_ORDER flag in for
+  // a non-relocatable link.
+  if (!parameters->options().relocatable())
+    input_section_flags &= ~elfcpp::SHF_LINK_ORDER;
+
+  return input_section_flags;
+}
+
 // 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
@@ -842,17 +865,7 @@ Layout::choose_output_section(const Relo
   // sections to segments.
   gold_assert(!is_input_section || !this->sections_are_attached_);
 
-  // Some flags in the input section should not be automatically
-  // copied to the output section.
-  flags &= ~ (elfcpp::SHF_INFO_LINK
-	      | elfcpp::SHF_GROUP
-	      | elfcpp::SHF_MERGE
-	      | elfcpp::SHF_STRINGS);
-
-  // We only clear the SHF_LINK_ORDER flag in for
-  // a non-relocatable link.
-  if (!parameters->options().relocatable())
-    flags &= ~elfcpp::SHF_LINK_ORDER;
+  flags = this->get_output_section_flags (flags);
 
   if (this->script_options_->saw_sections_clause())
     {
@@ -1054,9 +1067,37 @@ Layout::layout(Sized_relobj_file<size, b
     }
   else
     {
-      os = this->choose_output_section(object, name, sh_type,
-				       shdr.get_sh_flags(), true,
-				       ORDER_INVALID, false);
+      // Plugins can choose to place one or more subsets of sections in
+      // unique segments and this is done by mapping these section subsets
+      // to unique output sections.  Check if this section needs to be
+      // remapped to a unique output section.
+      Section_segment_map::iterator it
+	  = this->section_segment_map_.find(Const_section_id(object, shndx));
+      if (it == this->section_segment_map_.end())
+	{
+          os = this->choose_output_section(object, name, sh_type,
+					   shdr.get_sh_flags(), true,
+					   ORDER_INVALID, false);
+	}
+      else
+	{
+	  // We know the name of the output section, directly call
+	  // get_output_section here by-passing choose_output_section.
+	  elfcpp::Elf_Xword flags
+	    = this->get_output_section_flags(shdr.get_sh_flags());
+
+	  const char* os_name = it->second->name;
+	  Stringpool::Key name_key;
+	  os_name = this->namepool_.add(os_name, true, &name_key);
+	  os = this->get_output_section(os_name, name_key, sh_type, flags,
+					ORDER_INVALID, false);
+	  if (!os->is_unique_segment())
+	    {
+	      os->set_is_unique_segment();
+	      os->set_extra_segment_flags(it->second->flags);
+	      os->set_segment_alignment(it->second->align);
+	    }
+	}
       if (os == NULL)
 	return NULL;
     }
@@ -1116,6 +1157,15 @@ Layout::layout(Sized_relobj_file<size, b
   return os;
 }
 
+// Maps section SECN to SEGMENT s.
+void
+Layout::insert_section_segment_map(Const_section_id secn,
+				   Unique_segment_info *s)
+{
+  gold_assert(this->unique_segment_for_sections_specified_); 
+  this->section_segment_map_[secn] = s;
+}
+
 // Handle a relocation section when doing a relocatable link.
 
 template<int size, bool big_endian>
@@ -1718,6 +1768,10 @@ 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,
+  // coming from a linker plugin, do that.
+  seg_flags |= os->extra_segment_flags();
+
   // Check for --section-start.
   uint64_t addr;
   bool is_address_set = parameters->options().section_start(os->name(), &addr);
@@ -1734,8 +1788,13 @@ Layout::attach_allocated_section_to_segm
        p != this->segment_list_.end();
        ++p)
     {
+      // No need to go through the loop if a unique segment is needed.
+      if (os->is_unique_segment())
+        break;
       if ((*p)->type() != elfcpp::PT_LOAD)
 	continue;
+      if ((*p)->is_unique_segment())
+	continue;
       if (!parameters->options().omagic()
 	  && ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W))
 	continue;
@@ -1768,7 +1827,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);
@@ -1777,6 +1837,14 @@ Layout::attach_allocated_section_to_segm
       oseg->add_output_section_to_load(this, os, seg_flags);
       if (is_address_set)
 	oseg->set_addresses(addr, addr);
+      // Check if segment should be marked unique.  For segments marked
+      // unique by linker plugins, set the new alignment if specified.
+      if (os->is_unique_segment())
+	{
+	  oseg->set_is_unique_segment();
+	  if (os->segment_alignment() != 0)
+	    oseg->set_minimum_p_align(os->segment_alignment());
+	}
     }
 
   // If we see a loadable SHT_NOTE section, we create a PT_NOTE
@@ -3121,9 +3189,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;
 }
 
Index: gold/layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.104
diff -u -u -p -r1.104 layout.h
--- gold/layout.h	14 Aug 2012 08:31:56 -0000	1.104
+++ gold/layout.h	23 Aug 2012 02:32:30 -0000
@@ -528,6 +528,30 @@ class Layout
   get_section_order_map()
   { return &this->section_order_map_; }
 
+  // Struct to store segment info when mapping some input sections to
+  // unique segments using linker plugins.  Mapping an input section to
+  // a unique segment is done by first placing such input sections in
+  // unique output sections and then mapping the output section to a
+  // unique segment.  NAME is the name of the output section.  FLAGS
+  // and ALIGN are the extra flags and alignment of the segment.
+  struct Unique_segment_info
+  {
+    // Identifier for the Segment.  ELF Segments dont have names.
+    const char* name;
+    // Additional Segment flags.
+    uint64_t flags;
+    // Segment alignment.
+    uint64_t align;
+  };
+
+  // Mapping from input section to segment.
+  typedef std::map<Const_section_id, Unique_segment_info*>
+  Section_segment_map;
+
+  // Maps section SECN to SEGMENT s.
+  void
+  insert_section_segment_map(Const_section_id secn, Unique_segment_info *s);
+  
   bool
   is_section_ordering_specified()
   { return this->section_ordering_specified_; }
@@ -536,6 +560,14 @@ class Layout
   set_section_ordering_specified()
   { this->section_ordering_specified_ = true; }
 
+  bool
+  is_unique_segment_for_sections_specified() const
+  { 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
@@ -1070,6 +1102,11 @@ class Layout
 		     elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
 		     Output_section_order order, bool is_relro);
 
+  // Clear the input section flags that should not be copied to the
+  // output section.
+  elfcpp::Elf_Xword
+  get_output_section_flags (elfcpp::Elf_Xword input_section_flags);
+
   // Choose the output section for NAME in RELOBJ.
   Output_section*
   choose_output_section(const Relobj* relobj, const char* name,
@@ -1336,6 +1373,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 a 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_;
@@ -1350,6 +1390,11 @@ 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 unique segment. This is done by first
+  // placing such input sections in unique output sections and then mapping
+  // the output section to a unique segment.  Unique_segment_info stores
+  // any additional flags and alignment of the new segment.
+  Section_segment_map section_segment_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.157
diff -u -u -p -r1.157 object.cc
--- gold/object.cc	14 Aug 2012 08:31:56 -0000	1.157
+++ gold/object.cc	23 Aug 2012 02:32:30 -0000
@@ -1221,15 +1221,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 this
+// information is not available in the first pass.
 
 template<int size, bool big_endian>
 void
@@ -1238,26 +1242,44 @@ 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());
+  /* 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());
+
+  /* Only one of is_pass_one and is_pass_two is true.  Both are false when
+     a two-pass approach is not needed.  */
+  bool is_pass_one = false;
+  bool is_pass_two = false;
 
-  // Both is_gc_pass_one and is_gc_pass_two should not be true.
-  gold_assert(!(is_gc_pass_one  && is_gc_pass_two));
+  Symbols_data* gc_sd = NULL;
 
+  /* 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)
+    {
+      gc_sd = this->get_symbols_data();
+      if (gc_sd == NULL)
+	{
+	  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;
+	}
+    }
+    
   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.
@@ -1265,10 +1287,6 @@ 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)
-    {
-      gc_sd = this->get_symbols_data();
-    }
 
   const unsigned char* section_headers_data = NULL;
   section_size_type section_names_size;
@@ -1277,7 +1295,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;
@@ -1303,9 +1321,9 @@ Sized_relobj_file<size, big_endian>::do_
   const unsigned char* pshdrs;
 
   // Get the section names.
-  const unsigned char* pnamesu = (is_gc_or_icf)
-				 ? gc_sd->section_names_data
-				 : sd->section_names->data();
+  const unsigned char* pnamesu = (is_two_pass
+				  ? gc_sd->section_names_data
+				  : sd->section_names->data());
 
   const char* pnames = reinterpret_cast<const char*>(pnamesu);
 
@@ -1355,7 +1373,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);
@@ -1365,7 +1383,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;
@@ -1417,7 +1435,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))
 	    {
@@ -1491,7 +1509,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)
 	      || layout->keep_input_section (this, name)
@@ -1537,7 +1555,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;
@@ -1552,7 +1570,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
@@ -1577,7 +1595,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)
 	    {
@@ -1611,7 +1629,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],
@@ -1626,11 +1644,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.
@@ -1661,7 +1679,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
@@ -1670,7 +1688,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();
@@ -1717,7 +1735,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)
@@ -1740,7 +1758,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();
@@ -1761,7 +1779,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.168
diff -u -u -p -r1.168 output.cc
--- gold/output.cc	11 Aug 2012 04:41:28 -0000	1.168
+++ gold/output.cc	23 Aug 2012 02:32:30 -0000
@@ -2257,7 +2257,10 @@ 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),
+    extra_segment_flags_(0),
+    segment_alignment_(0),
     checkpoint_(NULL),
     lookup_maps_(new Output_section_lookup_maps),
     free_list_(),
@@ -3991,7 +3994,8 @@ Output_segment::Output_segment(elfcpp::E
     flags_(flags),
     is_max_align_known_(false),
     are_addresses_set_(false),
-    is_large_data_segment_(false)
+    is_large_data_segment_(false),
+    is_unique_segment_(false)
 {
   // The ELF ABI specifies that a PT_TLS segment always has PF_R as
   // the flags.
Index: gold/output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.136
diff -u -u -p -r1.136 output.h
--- gold/output.h	11 Aug 2012 04:41:28 -0000	1.136
+++ gold/output.h	23 Aug 2012 02:32:31 -0000
@@ -3265,6 +3265,29 @@ 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; }
+
+  uint64_t extra_segment_flags() const
+  { return this->extra_segment_flags_; }
+
+  void
+  set_extra_segment_flags(uint64_t flags)
+  { this->extra_segment_flags_ = flags; }
+
+  uint64_t segment_alignment() const
+  { return this->segment_alignment_; }
+
+  void
+  set_segment_alignment(uint64_t align)
+  { this->segment_alignment_ = align; }
+  
+
   // If a section requires postprocessing, return the buffer to use.
   unsigned char*
   postprocessing_buffer() const
@@ -4216,9 +4239,17 @@ 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 a 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_;
+  // Additional segment flags, specified via linker plugin, when mapping some
+  // input sections to unique segments.
+  uint64_t extra_segment_flags_; 
+  // Segment alignment specified via linker plugin, when mapping some
+  // input sections to unique segments.
+  uint64_t segment_alignment_;
   // Saved checkpoint.
   Checkpoint_output_section* checkpoint_;
   // Fast lookup maps for merged and relaxed input sections.
@@ -4294,6 +4325,16 @@ class Output_segment
   set_is_large_data_segment()
   { this->is_large_data_segment_ = true; }
 
+  bool
+  is_unique_segment() const
+  { return this->is_unique_segment_; }
+
+  // Mark segment as unique, happens when linker plugins request that
+  // certain input sections be mapped to unique segments.
+  void
+  set_is_unique_segment()
+  { this->is_unique_segment_ = true; }
+
   // Return the maximum alignment of the Output_data.
   uint64_t
   maximum_alignment();
@@ -4504,6 +4545,8 @@ class Output_segment
   bool are_addresses_set_ : 1;
   // Whether this segment holds large data sections.
   bool is_large_data_segment_ : 1;
+  // Whether this was marked as a unique segment via a linker plugin.
+  bool is_unique_segment_ : 1;
 };
 
 // This class represents the output file.
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	23 Aug 2012 02:32:31 -0000
@@ -115,6 +115,15 @@ 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,
+			    uint64_t align,
+			    const struct ld_plugin_section *section_list,
+			    unsigned int num_sections);
 };
 
 #endif // ENABLE_PLUGINS
@@ -159,7 +168,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 +282,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 +1703,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 a 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
+// a 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.
+// ALIGN specifies the alignment of the segment.
+
+static enum ld_plugin_status
+unique_segment_for_sections(const char* segment_name,
+			    uint64_t flags,
+			    uint64_t align,
+			    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);
+
+  Layout::Unique_segment_info* s = new Layout::Unique_segment_info;
+  s->name = segment_name;
+  s->flags = flags;
+  s->align = align;
+
+  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);
+      layout->insert_section_segment_map(secn_id, s);
+    }
+
+  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.195
diff -u -u -p -r1.195 Makefile.am
--- gold/testsuite/Makefile.am	14 Aug 2012 08:31:57 -0000	1.195
+++ gold/testsuite/Makefile.am	23 Aug 2012 02:32:31 -0000
@@ -1529,13 +1529,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) -Wl 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/Makefile.in
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.in,v
retrieving revision 1.205
diff -u -u -p -r1.205 Makefile.in
--- gold/testsuite/Makefile.in	14 Aug 2012 08:31:57 -0000	1.205
+++ gold/testsuite/Makefile.in	23 Aug 2012 02:32:32 -0000
@@ -329,7 +329,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__E
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_7.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_7.syms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_9.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_final_layout.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_final_layout.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_final_layout.readelf.stdout
 # Make a copy of two_file_test_1.o, which does not define the symbol _Z4t16av.
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_36 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_1.err \
@@ -4875,6 +4876,8 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_section_order.so" plugin_final_layout.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.stdout: plugin_final_layout
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(TEST_NM) -n plugin_final_layout > plugin_final_layout.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.readelf.stdout: plugin_final_layout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(TEST_READELF) -Wl plugin_final_layout > plugin_final_layout_readelf.stdout
 
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_section_order.so: plugin_section_order.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(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	23 Aug 2012 02:32:32 -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	23 Aug 2012 02:32:32 -0000
@@ -36,6 +36,9 @@ 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,
@@ -52,11 +55,13 @@ onload(struct ld_plugin_tv *tv)
       switch (entry->tv_tag)
         {
         case LDPT_REGISTER_CLAIM_FILE_HOOK:
-          assert((*entry->tv_u.tv_register_claim_file) (claim_file_hook) == LDPS_OK);
+          assert((*entry->tv_u.tv_register_claim_file) (claim_file_hook)
+		 == LDPS_OK);
           break;
 	case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
-          assert((*entry->tv_u.tv_register_all_symbols_read) (all_symbols_read_hook)
-		  == LDPS_OK);
+          assert((*entry->tv_u.tv_register_all_symbols_read)
+		     (all_symbols_read_hook)
+		 == LDPS_OK);
           break;
         case LDPT_GET_INPUT_SECTION_COUNT:
           get_input_section_count = *entry->tv_u.tv_get_input_section_count;
@@ -68,7 +73,8 @@ onload(struct ld_plugin_tv *tv)
           get_input_section_name = *entry->tv_u.tv_get_input_section_name;
           break;
         case LDPT_GET_INPUT_SECTION_CONTENTS:
-          get_input_section_contents = *entry->tv_u.tv_get_input_section_contents;
+          get_input_section_contents
+	      = *entry->tv_u.tv_get_input_section_contents;
           break;
 	case LDPT_UPDATE_SECTION_ORDER:
 	  update_section_order = *entry->tv_u.tv_update_section_order;
@@ -76,6 +82,13 @@ 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 +99,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 +132,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,8 +178,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, 0x1000,
+				   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	23 Aug 2012 02:32:32 -0000
@@ -318,6 +318,32 @@ 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.  If the plugin wants to call
+   unique_segment_for_sections, it must call this function from a
+   claim_file_handler or when it is first loaded.  */
+
+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 a 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.  The
+   parameter SEGMENT_ALIGNMENT when non-zero will override the default.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_unique_segment_for_sections) (
+    const char* segment_name,
+    uint64_t segment_flags,
+    uint64_t segment_alignment,
+    const struct ld_plugin_section * section_list,
+    unsigned int num_sections);
+
 enum ld_plugin_level
 {
   LDPL_INFO,
@@ -355,7 +381,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 +413,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;
 };
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment.
  2012-08-23  4:14         ` Sriraman Tallam
@ 2012-08-24 17:41           ` Ian Lance Taylor
  2012-08-24 17:44           ` Cary Coutant
  1 sibling, 0 replies; 9+ messages in thread
From: Ian Lance Taylor @ 2012-08-24 17:41 UTC (permalink / raw)
  To: Sriraman Tallam; +Cc: Cary Coutant, binutils

On Wed, Aug 22, 2012 at 8:12 PM, Sriraman Tallam <tmsriram@google.com> wrote:
> Hi Ian,
>
>     I have made all the changes and attached the patch.

> +  flags = this->get_output_section_flags (flags);

No space before parenthesis.

> +    // Identifier for the Segment.  ELF Segments dont have names.
> +    const char* name;
> +    // Additional Segment flags.

s/Segment/segment/ three times.

> +  void
> +  set_segment_alignment(uint64_t align)
> +  { this->segment_alignment_ = align; }
> +
> +

Only one blank line here.

> +/* The linker's interface for specifying that a specific set of sections
> +   must be mapped to a unique segment.  ELF segments do not have names
> +   and the NAME is used as an identifier only.

As I understand it, this comment isn't precisely accurate.  It's true
that ELF segments don't have names, but NAME is used as the name of
the newly created output section that is then placed in the unique
PT_LOAD segment.  Please fix accordingly.

This patch is OK with those changes.

Thanks.

Ian

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment.
  2012-08-23  4:14         ` Sriraman Tallam
  2012-08-24 17:41           ` Ian Lance Taylor
@ 2012-08-24 17:44           ` Cary Coutant
  2012-08-24 19:01             ` Sriraman Tallam
  1 sibling, 1 reply; 9+ messages in thread
From: Cary Coutant @ 2012-08-24 17:44 UTC (permalink / raw)
  To: Sriraman Tallam; +Cc: Ian Lance Taylor, binutils

>     I have made all the changes and attached the patch.

@@ -1734,8 +1788,13 @@ Layout::attach_allocated_section_to_segm
        p != this->segment_list_.end();
        ++p)
     {
+      // No need to go through the loop if a unique segment is needed.
+      if (os->is_unique_segment())
+        break;

I'd suggest moving this test outside the for loop. If this condition
is true, there's no point even entering the loop. (I'd hope the
compiler is smart enough to figure that out anyway, but I think it
would be clearer to the reader.

Aside from that and what Ian noted, it looks good to me.

-cary

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment.
  2012-08-24 17:44           ` Cary Coutant
@ 2012-08-24 19:01             ` Sriraman Tallam
  0 siblings, 0 replies; 9+ messages in thread
From: Sriraman Tallam @ 2012-08-24 19:01 UTC (permalink / raw)
  To: Cary Coutant; +Cc: Ian Lance Taylor, binutils

[-- Attachment #1: Type: text/plain, Size: 856 bytes --]

Hi Ian/Cary,

Thanks. Made all the changes and submitted. I will update GCC trunk
with the new plugin-api.h.

Submitted patch attached.

-Sri.

On Fri, Aug 24, 2012 at 10:40 AM, Cary Coutant <ccoutant@google.com> wrote:
>>     I have made all the changes and attached the patch.
>
> @@ -1734,8 +1788,13 @@ Layout::attach_allocated_section_to_segm
>         p != this->segment_list_.end();
>         ++p)
>      {
> +      // No need to go through the loop if a unique segment is needed.
> +      if (os->is_unique_segment())
> +        break;
>
> I'd suggest moving this test outside the for loop. If this condition
> is true, there's no point even entering the loop. (I'd hope the
> compiler is smart enough to figure that out anyway, but I think it
> would be clearer to the reader.
>
> Aside from that and what Ian noted, it looks good to me.
>
> -cary

[-- Attachment #2: segment_patch.txt --]
[-- Type: text/plain, Size: 46097 bytes --]

Index: gold/ChangeLog
===================================================================
RCS file: /cvs/src/src/gold/ChangeLog,v
retrieving revision 1.941
diff -u -u -p -r1.941 ChangeLog
--- gold/ChangeLog	22 Aug 2012 18:26:32 -0000	1.941
+++ gold/ChangeLog	24 Aug 2012 18:16:58 -0000
@@ -1,3 +1,59 @@
+2012-08-24  Sriraman Tallam  <tmsriram@google.com>
+
+	* gold.cc (queue_middle_tasks): Call layout again when unique
+	segments for sections is desired.
+	* layout.cc (Layout::Layout): Initialize new members.
+	(Layout::get_output_section_flags): New function.
+	(Layout::choose_output_section): Call get_output_section_flags.
+	(Layout::layout): Make output section for mapping to a unique segment.
+	(Layout::insert_section_segment_map): New function.
+	(Layout::attach_allocated_section_to_segment): Make unique segment for
+	output sections marked so. 
+	(Layout::segment_precedes): Check for unique segments when sorting.
+	* layout.h (Layout::Unique_segment_info): New struct.
+	(Layout::Section_segment_map): New typedef.
+	(Layout::insert_section_segment_map): New function.
+	(Layout::get_output_section_flags): New function.
+	(Layout::is_unique_segment_for_sections_specified): New function.
+	(Layout::set_unique_segment_for_sections_specified): New function.
+	(Layout::unique_segment_for_sections_specified_): New member.
+	(Layout::section_segment_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
+	members.
+	* output.h (Output_section::is_unique_segment): New function.
+	(Output_section::set_is_unique_segment): New function.
+	(Output_section::is_unique_segment_): New member.
+	(Output_section::extra_segment_flags): New function.
+	(Output_section::set_extra_segment_flags): New function.
+	(Output_section::extra_segment_flags_): New member.
+	(Output_section::segment_alignment): New function.
+	(Output_section::set_segment_alignment): New function.
+	(Output_section::segment_alignment_): New member.
+	(Output_segment::Output_segment): Initialize is_unique_segment_.
+	(Output_segment::is_unique_segment): New function.
+	(Output_segment::set_is_unique_segment): New function.
+	(Output_segment::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.
+	
+
 2012-08-22  Cary Coutant  <ccoutant@google.com>
 
 	* layout.cc (Layout::include_section): Don't assert on GROUP
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	24 Aug 2012 18:16:58 -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.235
diff -u -u -p -r1.235 layout.cc
--- gold/layout.cc	22 Aug 2012 18:26:32 -0000	1.235
+++ gold/layout.cc	24 Aug 2012 18:16:58 -0000
@@ -408,12 +408,14 @@ 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_(),
     input_section_position_(),
     input_section_glob_(),
     incremental_base_(NULL),
@@ -824,6 +826,27 @@ Layout::keep_input_section(const Relobj*
   return name != NULL && keep;
 }
 
+// Clear the input section flags that should not be copied to the
+// output section.
+
+elfcpp::Elf_Xword
+Layout::get_output_section_flags(elfcpp::Elf_Xword input_section_flags)
+{
+  // Some flags in the input section should not be automatically
+  // copied to the output section.
+  input_section_flags &= ~ (elfcpp::SHF_INFO_LINK
+			    | elfcpp::SHF_GROUP
+			    | elfcpp::SHF_MERGE
+			    | elfcpp::SHF_STRINGS);
+
+  // We only clear the SHF_LINK_ORDER flag in for
+  // a non-relocatable link.
+  if (!parameters->options().relocatable())
+    input_section_flags &= ~elfcpp::SHF_LINK_ORDER;
+
+  return input_section_flags;
+}
+
 // 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
@@ -842,17 +865,7 @@ Layout::choose_output_section(const Relo
   // sections to segments.
   gold_assert(!is_input_section || !this->sections_are_attached_);
 
-  // Some flags in the input section should not be automatically
-  // copied to the output section.
-  flags &= ~ (elfcpp::SHF_INFO_LINK
-	      | elfcpp::SHF_GROUP
-	      | elfcpp::SHF_MERGE
-	      | elfcpp::SHF_STRINGS);
-
-  // We only clear the SHF_LINK_ORDER flag in for
-  // a non-relocatable link.
-  if (!parameters->options().relocatable())
-    flags &= ~elfcpp::SHF_LINK_ORDER;
+  flags = this->get_output_section_flags(flags);
 
   if (this->script_options_->saw_sections_clause())
     {
@@ -1054,9 +1067,37 @@ Layout::layout(Sized_relobj_file<size, b
     }
   else
     {
-      os = this->choose_output_section(object, name, sh_type,
-				       shdr.get_sh_flags(), true,
-				       ORDER_INVALID, false);
+      // Plugins can choose to place one or more subsets of sections in
+      // unique segments and this is done by mapping these section subsets
+      // to unique output sections.  Check if this section needs to be
+      // remapped to a unique output section.
+      Section_segment_map::iterator it
+	  = this->section_segment_map_.find(Const_section_id(object, shndx));
+      if (it == this->section_segment_map_.end())
+	{
+          os = this->choose_output_section(object, name, sh_type,
+					   shdr.get_sh_flags(), true,
+					   ORDER_INVALID, false);
+	}
+      else
+	{
+	  // We know the name of the output section, directly call
+	  // get_output_section here by-passing choose_output_section.
+	  elfcpp::Elf_Xword flags
+	    = this->get_output_section_flags(shdr.get_sh_flags());
+
+	  const char* os_name = it->second->name;
+	  Stringpool::Key name_key;
+	  os_name = this->namepool_.add(os_name, true, &name_key);
+	  os = this->get_output_section(os_name, name_key, sh_type, flags,
+					ORDER_INVALID, false);
+	  if (!os->is_unique_segment())
+	    {
+	      os->set_is_unique_segment();
+	      os->set_extra_segment_flags(it->second->flags);
+	      os->set_segment_alignment(it->second->align);
+	    }
+	}
       if (os == NULL)
 	return NULL;
     }
@@ -1116,6 +1157,15 @@ Layout::layout(Sized_relobj_file<size, b
   return os;
 }
 
+// Maps section SECN to SEGMENT s.
+void
+Layout::insert_section_segment_map(Const_section_id secn,
+				   Unique_segment_info *s)
+{
+  gold_assert(this->unique_segment_for_sections_specified_); 
+  this->section_segment_map_[secn] = s;
+}
+
 // Handle a relocation section when doing a relocatable link.
 
 template<int size, bool big_endian>
@@ -1718,6 +1768,10 @@ 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,
+  // coming from a linker plugin, do that.
+  seg_flags |= os->extra_segment_flags();
+
   // Check for --section-start.
   uint64_t addr;
   bool is_address_set = parameters->options().section_start(os->name(), &addr);
@@ -1730,45 +1784,51 @@ Layout::attach_allocated_section_to_segm
   // have to use a linker script.
 
   Segment_list::const_iterator p;
-  for (p = this->segment_list_.begin();
-       p != this->segment_list_.end();
-       ++p)
+  if (!os->is_unique_segment())
     {
-      if ((*p)->type() != elfcpp::PT_LOAD)
-	continue;
-      if (!parameters->options().omagic()
-	  && ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W))
-	continue;
-      if ((target->isolate_execinstr() || parameters->options().rosegment())
-	  && ((*p)->flags() & elfcpp::PF_X) != (seg_flags & elfcpp::PF_X))
-	continue;
-      // If -Tbss was specified, we need to separate the data and BSS
-      // segments.
-      if (parameters->options().user_set_Tbss())
-	{
-	  if ((os->type() == elfcpp::SHT_NOBITS)
-	      == (*p)->has_any_data_sections())
-	    continue;
-	}
-      if (os->is_large_data_section() && !(*p)->is_large_data_segment())
-	continue;
-
-      if (is_address_set)
+      for (p = this->segment_list_.begin();
+ 	   p != this->segment_list_.end();
+	   ++p)
 	{
-	  if ((*p)->are_addresses_set())
-	    continue;
-
-	  (*p)->add_initial_output_data(os);
-	  (*p)->update_flags_for_output_section(seg_flags);
-	  (*p)->set_addresses(addr, addr);
-	  break;
-	}
-
-      (*p)->add_output_section_to_load(this, os, seg_flags);
-      break;
+	  if ((*p)->type() != elfcpp::PT_LOAD)                        
+	    continue;                        
+	  if ((*p)->is_unique_segment())                        
+	    continue;                        
+	  if (!parameters->options().omagic()                        
+	      && ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W))                        
+	    continue;                        
+	  if ((target->isolate_execinstr() || parameters->options().rosegment())                        
+	      && ((*p)->flags() & elfcpp::PF_X) != (seg_flags & elfcpp::PF_X))                        
+	    continue;                        
+	  // If -Tbss was specified, we need to separate the data and BSS                        
+	  // segments.                        
+	  if (parameters->options().user_set_Tbss())                        
+	    {                        
+	      if ((os->type() == elfcpp::SHT_NOBITS)                        
+	          == (*p)->has_any_data_sections())                        
+	        continue;                        
+	    }                        
+	  if (os->is_large_data_section() && !(*p)->is_large_data_segment())                        
+	    continue;                        
+	                    
+	  if (is_address_set)                        
+	    {                        
+	      if ((*p)->are_addresses_set())                        
+	        continue;                        
+	                    
+	      (*p)->add_initial_output_data(os);                        
+	      (*p)->update_flags_for_output_section(seg_flags);                        
+	      (*p)->set_addresses(addr, addr);                        
+	      break;                        
+	    }                        
+	                    
+	  (*p)->add_output_section_to_load(this, os, seg_flags);                        
+	  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);
@@ -1777,6 +1837,14 @@ Layout::attach_allocated_section_to_segm
       oseg->add_output_section_to_load(this, os, seg_flags);
       if (is_address_set)
 	oseg->set_addresses(addr, addr);
+      // Check if segment should be marked unique.  For segments marked
+      // unique by linker plugins, set the new alignment if specified.
+      if (os->is_unique_segment())
+	{
+	  oseg->set_is_unique_segment();
+	  if (os->segment_alignment() != 0)
+	    oseg->set_minimum_p_align(os->segment_alignment());
+	}
     }
 
   // If we see a loadable SHT_NOTE section, we create a PT_NOTE
@@ -3121,9 +3189,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;
 }
 
Index: gold/layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.104
diff -u -u -p -r1.104 layout.h
--- gold/layout.h	14 Aug 2012 08:31:56 -0000	1.104
+++ gold/layout.h	24 Aug 2012 18:16:58 -0000
@@ -528,6 +528,30 @@ class Layout
   get_section_order_map()
   { return &this->section_order_map_; }
 
+  // Struct to store segment info when mapping some input sections to
+  // unique segments using linker plugins.  Mapping an input section to
+  // a unique segment is done by first placing such input sections in
+  // unique output sections and then mapping the output section to a
+  // unique segment.  NAME is the name of the output section.  FLAGS
+  // and ALIGN are the extra flags and alignment of the segment.
+  struct Unique_segment_info
+  {
+    // Identifier for the segment.  ELF segments dont have names.
+    const char* name;
+    // Additional segment flags.
+    uint64_t flags;
+    // Segment alignment.
+    uint64_t align;
+  };
+
+  // Mapping from input section to segment.
+  typedef std::map<Const_section_id, Unique_segment_info*>
+  Section_segment_map;
+
+  // Maps section SECN to SEGMENT s.
+  void
+  insert_section_segment_map(Const_section_id secn, Unique_segment_info *s);
+  
   bool
   is_section_ordering_specified()
   { return this->section_ordering_specified_; }
@@ -536,6 +560,14 @@ class Layout
   set_section_ordering_specified()
   { this->section_ordering_specified_ = true; }
 
+  bool
+  is_unique_segment_for_sections_specified() const
+  { 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
@@ -1070,6 +1102,11 @@ class Layout
 		     elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
 		     Output_section_order order, bool is_relro);
 
+  // Clear the input section flags that should not be copied to the
+  // output section.
+  elfcpp::Elf_Xword
+  get_output_section_flags (elfcpp::Elf_Xword input_section_flags);
+
   // Choose the output section for NAME in RELOBJ.
   Output_section*
   choose_output_section(const Relobj* relobj, const char* name,
@@ -1336,6 +1373,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 a 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_;
@@ -1350,6 +1390,11 @@ 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 unique segment. This is done by first
+  // placing such input sections in unique output sections and then mapping
+  // the output section to a unique segment.  Unique_segment_info stores
+  // any additional flags and alignment of the new segment.
+  Section_segment_map section_segment_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.157
diff -u -u -p -r1.157 object.cc
--- gold/object.cc	14 Aug 2012 08:31:56 -0000	1.157
+++ gold/object.cc	24 Aug 2012 18:16:59 -0000
@@ -1221,15 +1221,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 this
+// information is not available in the first pass.
 
 template<int size, bool big_endian>
 void
@@ -1238,26 +1242,44 @@ 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());
+  /* 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());
+
+  /* Only one of is_pass_one and is_pass_two is true.  Both are false when
+     a two-pass approach is not needed.  */
+  bool is_pass_one = false;
+  bool is_pass_two = false;
 
-  // Both is_gc_pass_one and is_gc_pass_two should not be true.
-  gold_assert(!(is_gc_pass_one  && is_gc_pass_two));
+  Symbols_data* gc_sd = NULL;
 
+  /* 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)
+    {
+      gc_sd = this->get_symbols_data();
+      if (gc_sd == NULL)
+	{
+	  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;
+	}
+    }
+    
   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.
@@ -1265,10 +1287,6 @@ 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)
-    {
-      gc_sd = this->get_symbols_data();
-    }
 
   const unsigned char* section_headers_data = NULL;
   section_size_type section_names_size;
@@ -1277,7 +1295,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;
@@ -1303,9 +1321,9 @@ Sized_relobj_file<size, big_endian>::do_
   const unsigned char* pshdrs;
 
   // Get the section names.
-  const unsigned char* pnamesu = (is_gc_or_icf)
-				 ? gc_sd->section_names_data
-				 : sd->section_names->data();
+  const unsigned char* pnamesu = (is_two_pass
+				  ? gc_sd->section_names_data
+				  : sd->section_names->data());
 
   const char* pnames = reinterpret_cast<const char*>(pnamesu);
 
@@ -1355,7 +1373,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);
@@ -1365,7 +1383,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;
@@ -1417,7 +1435,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))
 	    {
@@ -1491,7 +1509,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)
 	      || layout->keep_input_section (this, name)
@@ -1537,7 +1555,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;
@@ -1552,7 +1570,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
@@ -1577,7 +1595,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)
 	    {
@@ -1611,7 +1629,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],
@@ -1626,11 +1644,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.
@@ -1661,7 +1679,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
@@ -1670,7 +1688,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();
@@ -1717,7 +1735,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)
@@ -1740,7 +1758,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();
@@ -1761,7 +1779,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.168
diff -u -u -p -r1.168 output.cc
--- gold/output.cc	11 Aug 2012 04:41:28 -0000	1.168
+++ gold/output.cc	24 Aug 2012 18:16:59 -0000
@@ -2257,7 +2257,10 @@ 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),
+    extra_segment_flags_(0),
+    segment_alignment_(0),
     checkpoint_(NULL),
     lookup_maps_(new Output_section_lookup_maps),
     free_list_(),
@@ -3991,7 +3994,8 @@ Output_segment::Output_segment(elfcpp::E
     flags_(flags),
     is_max_align_known_(false),
     are_addresses_set_(false),
-    is_large_data_segment_(false)
+    is_large_data_segment_(false),
+    is_unique_segment_(false)
 {
   // The ELF ABI specifies that a PT_TLS segment always has PF_R as
   // the flags.
Index: gold/output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.136
diff -u -u -p -r1.136 output.h
--- gold/output.h	11 Aug 2012 04:41:28 -0000	1.136
+++ gold/output.h	24 Aug 2012 18:16:59 -0000
@@ -3265,6 +3265,28 @@ 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; }
+
+  uint64_t extra_segment_flags() const
+  { return this->extra_segment_flags_; }
+
+  void
+  set_extra_segment_flags(uint64_t flags)
+  { this->extra_segment_flags_ = flags; }
+
+  uint64_t segment_alignment() const
+  { return this->segment_alignment_; }
+
+  void
+  set_segment_alignment(uint64_t align)
+  { this->segment_alignment_ = align; }
+  
   // If a section requires postprocessing, return the buffer to use.
   unsigned char*
   postprocessing_buffer() const
@@ -4216,9 +4238,17 @@ 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 a 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_;
+  // Additional segment flags, specified via linker plugin, when mapping some
+  // input sections to unique segments.
+  uint64_t extra_segment_flags_; 
+  // Segment alignment specified via linker plugin, when mapping some
+  // input sections to unique segments.
+  uint64_t segment_alignment_;
   // Saved checkpoint.
   Checkpoint_output_section* checkpoint_;
   // Fast lookup maps for merged and relaxed input sections.
@@ -4294,6 +4324,16 @@ class Output_segment
   set_is_large_data_segment()
   { this->is_large_data_segment_ = true; }
 
+  bool
+  is_unique_segment() const
+  { return this->is_unique_segment_; }
+
+  // Mark segment as unique, happens when linker plugins request that
+  // certain input sections be mapped to unique segments.
+  void
+  set_is_unique_segment()
+  { this->is_unique_segment_ = true; }
+
   // Return the maximum alignment of the Output_data.
   uint64_t
   maximum_alignment();
@@ -4504,6 +4544,8 @@ class Output_segment
   bool are_addresses_set_ : 1;
   // Whether this segment holds large data sections.
   bool is_large_data_segment_ : 1;
+  // Whether this was marked as a unique segment via a linker plugin.
+  bool is_unique_segment_ : 1;
 };
 
 // This class represents the output file.
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	24 Aug 2012 18:16:59 -0000
@@ -115,6 +115,15 @@ 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,
+			    uint64_t align,
+			    const struct ld_plugin_section *section_list,
+			    unsigned int num_sections);
 };
 
 #endif // ENABLE_PLUGINS
@@ -159,7 +168,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 +282,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 +1703,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 a 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
+// a 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.
+// ALIGN specifies the alignment of the segment.
+
+static enum ld_plugin_status
+unique_segment_for_sections(const char* segment_name,
+			    uint64_t flags,
+			    uint64_t align,
+			    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);
+
+  Layout::Unique_segment_info* s = new Layout::Unique_segment_info;
+  s->name = segment_name;
+  s->flags = flags;
+  s->align = align;
+
+  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);
+      layout->insert_section_segment_map(secn_id, s);
+    }
+
+  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.195
diff -u -u -p -r1.195 Makefile.am
--- gold/testsuite/Makefile.am	14 Aug 2012 08:31:57 -0000	1.195
+++ gold/testsuite/Makefile.am	24 Aug 2012 18:16:59 -0000
@@ -1529,13 +1529,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) -Wl 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/Makefile.in
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.in,v
retrieving revision 1.205
diff -u -u -p -r1.205 Makefile.in
--- gold/testsuite/Makefile.in	14 Aug 2012 08:31:57 -0000	1.205
+++ gold/testsuite/Makefile.in	24 Aug 2012 18:16:59 -0000
@@ -329,7 +329,8 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__E
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_7.err \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_7.syms \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_9.err \
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_final_layout.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_final_layout.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_final_layout.readelf.stdout
 # Make a copy of two_file_test_1.o, which does not define the symbol _Z4t16av.
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@am__append_36 =  \
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	plugin_test_1.err \
@@ -4875,6 +4876,8 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(CXXLINK) -Bgcctestdir/ -Wl,--plugin,"./plugin_section_order.so" plugin_final_layout.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.stdout: plugin_final_layout
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(TEST_NM) -n plugin_final_layout > plugin_final_layout.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_final_layout.readelf.stdout: plugin_final_layout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(TEST_READELF) -Wl plugin_final_layout > plugin_final_layout_readelf.stdout
 
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@plugin_section_order.so: plugin_section_order.o
 @GCC_TRUE@@NATIVE_LINKER_TRUE@@PLUGINS_TRUE@	$(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	24 Aug 2012 18:16:59 -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	24 Aug 2012 18:16:59 -0000
@@ -36,6 +36,9 @@ 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,
@@ -52,11 +55,13 @@ onload(struct ld_plugin_tv *tv)
       switch (entry->tv_tag)
         {
         case LDPT_REGISTER_CLAIM_FILE_HOOK:
-          assert((*entry->tv_u.tv_register_claim_file) (claim_file_hook) == LDPS_OK);
+          assert((*entry->tv_u.tv_register_claim_file) (claim_file_hook)
+		 == LDPS_OK);
           break;
 	case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
-          assert((*entry->tv_u.tv_register_all_symbols_read) (all_symbols_read_hook)
-		  == LDPS_OK);
+          assert((*entry->tv_u.tv_register_all_symbols_read)
+		     (all_symbols_read_hook)
+		 == LDPS_OK);
           break;
         case LDPT_GET_INPUT_SECTION_COUNT:
           get_input_section_count = *entry->tv_u.tv_get_input_section_count;
@@ -68,7 +73,8 @@ onload(struct ld_plugin_tv *tv)
           get_input_section_name = *entry->tv_u.tv_get_input_section_name;
           break;
         case LDPT_GET_INPUT_SECTION_CONTENTS:
-          get_input_section_contents = *entry->tv_u.tv_get_input_section_contents;
+          get_input_section_contents
+	      = *entry->tv_u.tv_get_input_section_contents;
           break;
 	case LDPT_UPDATE_SECTION_ORDER:
 	  update_section_order = *entry->tv_u.tv_update_section_order;
@@ -76,6 +82,13 @@ 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 +99,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 +132,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,8 +178,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, 0x1000,
+				   section_list, num_entries);
+    }
 
   return LDPS_OK;
 }
-
Index: include/ChangeLog
===================================================================
RCS file: /cvs/src/src/include/ChangeLog,v
retrieving revision 1.587
diff -u -u -p -r1.587 ChangeLog
--- include/ChangeLog	24 Aug 2012 07:52:49 -0000	1.587
+++ include/ChangeLog	24 Aug 2012 18:16:59 -0000
@@ -1,3 +1,13 @@
+2012-08-24  Sriraman Tallam  <tmsriram@google.com>
+
+	* 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.
+
 2012-08-24  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>
 
 	* opcode/arm.h (ARM_CPU_IS_ANY): New define.
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	24 Aug 2012 18:16:59 -0000
@@ -318,6 +318,33 @@ 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.  If the plugin wants to call
+   unique_segment_for_sections, it must call this function from a
+   claim_file_handler or when it is first loaded.  */
+
+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 a unique segment.  ELF segments do not have names
+   and the NAME is used as the name of the newly created output section
+   that is then placed in the unique PT_LOAD 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 that would be set by default is not possible.  The
+   parameter SEGMENT_ALIGNMENT when non-zero will override the default.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_unique_segment_for_sections) (
+    const char* segment_name,
+    uint64_t segment_flags,
+    uint64_t segment_alignment,
+    const struct ld_plugin_section * section_list,
+    unsigned int num_sections);
+
 enum ld_plugin_level
 {
   LDPL_INFO,
@@ -355,7 +382,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 +414,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;
 };
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-08-24 18:38 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-21  0:28 [patch] Gold linker patch to provide plugin support for mapping some text sections to an unique ELF segment Sriraman Tallam
2012-07-31 17:21 ` Sriraman Tallam
2012-08-03  6:44   ` Cary Coutant
2012-08-10  0:56     ` Sriraman Tallam
2012-08-22 21:41       ` Ian Lance Taylor
2012-08-23  4:14         ` Sriraman Tallam
2012-08-24 17:41           ` Ian Lance Taylor
2012-08-24 17:44           ` Cary Coutant
2012-08-24 19:01             ` Sriraman Tallam

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).