Plugin interfaces to do Pettis Hansen style code layout in the gold linker.

Sriraman Tallam tmsriram@google.com
Sun Mar 13 02:37:00 GMT 2011


Hi Cary,


  Like we discussed, I made all the changes. I now have a separate
list of unclaimed objects in the Plugin manager and the handle will be
an index into it. I have also added a new hook called
"inspect_unclaimed_object". This handler allows the plugin to examine
the contents of an unclaimed object. Now, I have disallowed examining
claimed objects here as the methods to get their contents etc. are not
defined in Pluginobj. Also, I have kept the original interfaces to get
section count or type or contents. I think I would need this interface
for my work rather than only get contents based on filters. I guess
more interfaces can be added easily.

Thanks,
-Sri.


Change Log for plugin-api.h


	* plugin-api.h
	(ld_plugin_inspect_unclaimed_object_handler): New typedef.
	(ld_plugin_register_inspect_unclaimed_object): New typedef.
	(ld_plugin_get_section_count): New typedef.
	(ld_plugin_get_section_type): New typedef.
	(ld_plugin_get_section_name): New typedef.
	(ld_plugin_get_section_contents): New typedef.
	(ld_plugin_read_layout_from_file): New typedef.
	(ld_plugin_allow_section_ordering): New typedef.
	(LDPT_REGISTER_INSPECT_UNCLAIMED_OBJECT_HOOK): New enum value.
	(LDPT_GET_SECTION_COUNT): New enum value.
	(LDPT_GET_SECTION_TYPE): New enum value.
	(LDPT_GET_SECTION_NAME): New enum value.
	(LDPT_GET_SECTION_CONTENTS): New enum value.
	(LDPT_READ_LAYOUT_FROM_FILE): New enum value.
	(LDPT_ALLOW_SECTION_ORDERING): New enum value.
	(tv_get_section_count): New struct members.
	(tv_get_section_type): New struct members.
	(tv_get_section_name): New struct members.
	(tv_get_section_contents): New struct members.
	(tv_read_layout_from_file): New struct members.
	(tv_allow_section_ordering): New struct members.

ChangeLog for gold:


	* layout.cc (Layout::Layout): Initialize section_ordering_specified_,
	input_section_position_, and input_section_glob_.
	(Layout::update_layout_of_sections): New function.
	(read_layout_from_file): Add parameter filename and call function
	section_ordering_specified.
	* layout.h (is_section_ordering_specified): New function.
	(section_ordering_specified): New function.
	(read_layout_from_file): Add parameter filename.
	(update_layout_of_sections): New function.
	(section_ordering_specified_): New boolean member.
	* main.cc(main): Call load_plugins after layout object is defined.
	Call read_layout_from_file when section ordering is specified.
	* output.cc (Output_section::add_input_section): Use
	function section_ordering_specified to check if section ordering is
	needed.
	(Output_section::update_section_layout): New function.
	(Output_section::sort_attached_input_sections): Check if input section
	must be reordered.
	* output.h (Output_section::update_section_layout): New function.
	* plugin.cc (register_inspect_unclaimed_object): New function.
	(get_section_count): New function.
	(get_section_type): New function.
	(get_section_name): New function.
	(get_section_contents): New function.
	(read_layout_from_file): New function.
	(allow_section_ordering): New function.	
	(Plugin::inspect_unclaimed_object): New function.
	(Plugin_manager::inspect_unclaimed_object): New function.
	(Plugin_manager::get_unclaimed_object): New function.
	(Plugin::load): Add the new interfaces to the transfer vector.
	(Plugin_manager::load_plugins): New parameter.
	* plugin.h (input_objects): New function
	(Plugin::inspect_unclaimed_object): New function.
	(Plugin::set_inspect_unclaimed_object_handler): New function.
	(Plugin__manager::load_plugins): New parameter.
	(Plugin_manager::inspect_unclaimed_object): New function.
	(Plugin_manager::get_unclaimed_object): New function.
	(Plugin_manager::in_inspect_unclaimed_object_handler): New function.
	(Plugin_manager::set_inspect_unclaimed_object_handler): New function.
	(Plugin_manager::unclaimed_object): New function.
	(Plugin_manager::Unclaimed_object_list): New typedef.
	(Plugin_manager::unclaimed_objects_): New member.
	(Plugin_manager::in_inspect_unclaimed_object_handler_): New member.
	(layout): New function.
	* readsyms.cc (Read_symbols::do_read_symbols): Call the plugin handler.
	* testsuite/plugin_test.c (register_inspect_unclaimed_object_hook):
	New function pointer.
	(get_section_count): New function pointer.
	(get_section_type): New function pointer.
	(get_section_name): New function pointer.
	(get_section_contents): New function pointer.
	(read_layout_from_file): New function pointer.
	(allow_section_ordering): New function pointer.
	(inspect_unclaimed_object_hook): New function.
	(onload): Check if the new interfaces exist.



On Wed, Mar 9, 2011 at 4:40 PM, Cary Coutant <ccoutant@google.com> wrote:
> Here are my comments on your patch. Thanks for working on this -- I
> think it's going to be valuable.
>
> -cary
>
>
>
> Index: plugin-api.h
> ===================================================================
>
> You'll need a separate ChangeLog entry for include/. Also, we use
> C-style coding conventions in include/plugin-api.h. In particular,
> "char* filename" should be "char *filename", etc.
>
> +/* The linker's interface for retrieving the handle (pointer) to an object. */
> +
> +typedef
> +enum ld_plugin_status
> +(*ld_plugin_get_object_handle) (const char* filename, void** handle);
>
> I'm curious how this interface is going to be used. Where does the
> plugin obtain a filename where it doesn't already have a handle? Are
> you going to claim the files, or merely observe them and pass them
> through unclaimed? If this is the case, why not just keep a list of
> the handles in your plugin, and arrange for the handles to remain
> valid even for unclaimed files (in the current plugin architecture,
> the handle is just an index into the list of claimed files)?
>
> +typedef
> +enum ld_plugin_status
> +(*ld_plugin_get_section_name) (void* handle, unsigned int shndx,
> +                               char** section_name_ptr);
> +/* The linker's interface for retrieving the contents of a specific section
> +   in an object.  */
>
> Missing blank line before this comment.
>
> +/* The linker's interface for specifying the desired order of sections
> +   through a file.  */
> +
> +typedef
> +enum ld_plugin_status
> +(*ld_plugin_read_layout_from_file) (const char* filename);
> +
> +/* The linker's interface for specifying that reordering of sections is
> +   desired.  */
> +
> +typedef
> +enum ld_plugin_status
> +(*ld_plugin_allow_section_ordering) (void);
>
> Why do we need both of these interfaces? Couldn't
> read_layout_from_file imply allow_section_ordering?
>
> Index: layout.cc
> ===================================================================
> +    relaxation_debug_check_(NULL),
> +    section_ordering_specified_(false),
> +    input_section_position_(),
> +    input_section_glob_()
> +
>
> Extra blank line here.
>
> +      if ((*p) == NULL)
> +        continue;
> +      (*p)->update_section_layout(this);
>
> This could just be:
>
> +      if ((*p) != NULL)
> +        (*p)->update_section_layout(this);
>
> Index: layout.h
> ===================================================================
>
> +  bool
> +  is_section_ordering_specified()
> +  { return section_ordering_specified_; }
> +
> +  void
> +  section_ordering_specified()
> +  { section_ordering_specified_ = true; }
> +
> +
>
> Extra blank line here.
>
>   unsigned int
>   find_section_order_index(const std::string&);
>
> +   void
> +  read_layout_from_file(const char* filename);
> +
>   void
> +  update_layout_of_sections();
>
> These functions should all have comments.
>
> +  bool section_ordering_specified_;
>
> Need a comment here, too.
>
> Index: main.cc
> ===================================================================
>
> +  const char* section_ordering_file =
> parameters->options().section_ordering_file();
>
> Line too long.
>
> Index: output.cc
> ===================================================================
>
> +         Object* obj = ((*p).is_input_section() ? (*p).relobj()
> +                        : (*p).relaxed_input_section()->relobj());
>
> I'd prefer to see this written like this:
>
> +         Object* obj = ((*p).is_input_section()
> +                        ? (*p).relobj()
> +                        : (*p).relaxed_input_section()->relobj());
>
> +          std::string section_name = obj->section_name((*p).shndx());
> +         unsigned int section_order_index =
> +            layout->find_section_order_index(std::string(section_name));
>
> section_name is already a string here -- no conversion necessary.
>
> Index: plugin.cc
> ===================================================================
>
> @@ -404,7 +458,7 @@ Plugin_manager::all_symbols_read(Workque
> -  this->layout_ = layout;
> +  gold_assert (this->layout_ == layout);
>
> Why not just drop layout from the parameter list for all_symbols_read?
>
> +// Find the object having the given name.
> +// Parameters :
> +// FILENAME : The name of the object whose handle needs to be
> +//            retrieved.
> +// HANDLE   : Storage for the retrieved handle.
>
> This comment formatting style doesn't match the rest of the file (or
> anywhere else in gold, except for icf.cc). I don't need to see it
> changed, though -- I'm not sure about Ian's preferences.
>
> +  if (input_objects == NULL)
> +    {
> +      return LDPS_ERR;
> +    }
>
> Excessive use of braces?
>
>
> +      if (strcmp((*p)->name().c_str(), filename) == 0)
> +        {
> +          *handle = static_cast<void*>(*p);
> +          break;
> +        }
>
> You could just return LDPS_OK here, and return LDPS_ERR
> unconditionally below the loop.
>
> The handle returned here is very different from the handle returned by
> the existing set of interfaces, and you don't seem to do anything to
> tell them apart; this effectively makes it two separate and
> non-interoperable APIs. There also isn't any way for the linker side
> of the plugin interface to do a sanity check on the handle given it.
> I'd suggest keeping the notion of handle as an index into a list of
> objects, but extend that list to cover all objects rather than just
> the claimed ones.
>
> +static enum ld_plugin_status
> +get_section_type(void* handle, unsigned int shndx, unsigned int* type)
>
> +static enum ld_plugin_status
> +get_section_name(void* handle, unsigned int shndx, char** section_name_ptr)
>
> It's looking like you intend for the plugin to iterate over the
> sections one at a time, looking for a section by either type or name,
> or both. Depending on how you intend to actually use this (and keeping
> in mind generality for other potential uses), it might be better to
> replace these two interfaces with a single one that can find a section
> filtered by type, name, or both (with a provision for iterating
> through multiple results).
>
> Also note that the section_type() and section_name() object methods go
> to a File_view, and you need a task lock in order to call them (else
> you'll get a file descriptor leak). When during the link do you expect
> these interfaces to be used? If it's only from the claim-file handler,
> it should be OK, but if it's from the all-files-read handler, this is
> going to re-open the files. There should be some check in place to
> ensure it's called only when it's designed to be called.
>
-------------- next part --------------
Index: layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.190
diff -u -u -p -r1.190 layout.cc
--- layout.cc	10 Jan 2011 21:57:31 -0000	1.190
+++ layout.cc	13 Mar 2011 02:31:36 -0000
@@ -207,7 +207,10 @@ Layout::Layout(int number_of_input_files
     record_output_section_data_from_script_(false),
     script_output_section_data_list_(),
     segment_states_(NULL),
-    relaxation_debug_check_(NULL)
+    relaxation_debug_check_(NULL),
+    section_ordering_specified_(false),
+    input_section_position_(),
+    input_section_glob_()
 {
   // Make space for more than enough segments for a typical file.
   // This is just for efficiency--it's OK if we wind up needing more.
@@ -1817,13 +1820,28 @@ Layout::find_section_order_index(const s
   return 0;
 }
 
+// Updates the input section order of all output sections.  This
+// is called when the section order is specified via plugins.
+
+void
+Layout::update_layout_of_sections()
+{
+  for (Section_list::iterator p = this->section_list_.begin();
+       p != this->section_list_.end();
+       ++p)
+    {
+      if ((*p) == NULL)
+        continue;
+      (*p)->update_section_layout(this);
+    }
+}
+
 // Read the sequence of input sections from the file specified with
-// --section-ordering-file.
+// linker option --section-ordering-file.
 
 void
-Layout::read_layout_from_file()
+Layout::read_layout_from_file(const char* filename)
 {
-  const char* filename = parameters->options().section_ordering_file();
   std::ifstream in;
   std::string line;
 
@@ -1834,6 +1852,7 @@ Layout::read_layout_from_file()
 
   std::getline(in, line);   // this chops off the trailing \n, if any
   unsigned int position = 1;
+  this->section_ordering_specified();
 
   while (in)
     {
Index: layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.88
diff -u -u -p -r1.88 layout.h
--- layout.h	14 Dec 2010 19:03:30 -0000	1.88
+++ layout.h	13 Mar 2011 02:31:36 -0000
@@ -414,11 +414,25 @@ class Layout
 	 const char* name, const elfcpp::Shdr<size, big_endian>& shdr,
 	 unsigned int reloc_shndx, unsigned int reloc_type, off_t* offset);
 
+  bool
+  is_section_ordering_specified()
+  { return section_ordering_specified_; }
+
+  void
+  section_ordering_specified()
+  { section_ordering_specified_ = true; }
+
   unsigned int
   find_section_order_index(const std::string&);
 
+  // Read the sequence of input sections from the file specified with
+  // linker option --section-ordering-file.
+  void
+  read_layout_from_file(const char* filename);
+
+  // Updates the order of input sections in the output sections.
   void
-  read_layout_from_file();
+  update_layout_of_sections();
 
   // Layout an input reloc section when doing a relocatable link.  The
   // section is RELOC_SHNDX in OBJECT, with data in SHDR.
@@ -1147,6 +1161,9 @@ class Layout
   Segment_states* segment_states_;
   // A relaxation debug checker.  We only create one when in debugging mode.
   Relaxation_debug_check* relaxation_debug_check_;
+  // True if the input sections in the output sections should be sorted
+  // as specified in a section ordering file.
+  bool section_ordering_specified_;
   // 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: main.cc
===================================================================
RCS file: /cvs/src/src/gold/main.cc,v
retrieving revision 1.42
diff -u -u -p -r1.42 main.cc
--- main.cc	14 Dec 2010 19:03:30 -0000	1.42
+++ main.cc	13 Mar 2011 02:31:36 -0000
@@ -195,10 +195,6 @@ main(int argc, char** argv)
   if (parameters->options().relocatable())
     command_line.script_options().version_script_info()->clear();
 
-  // Load plugin libraries.
-  if (command_line.options().has_plugins())
-    command_line.options().plugins()->load_plugins();
-
   // The work queue.
   Workqueue workqueue(command_line.options());
 
@@ -231,8 +227,14 @@ main(int argc, char** argv)
   if (layout.incremental_inputs() != NULL)
     layout.incremental_inputs()->report_command_line(argc, argv);
 
-  if (parameters->options().section_ordering_file())
-    layout.read_layout_from_file();
+  // Load plugin libraries.
+  if (command_line.options().has_plugins())
+    command_line.options().plugins()->load_plugins(&layout);
+
+  const char* section_ordering_file
+    = parameters->options().section_ordering_file();
+  if (section_ordering_file)
+    layout.read_layout_from_file(section_ordering_file);
 
   // Get the search path from the -L options.
   Dirsearch search_path;
Index: output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.140
diff -u -u -p -r1.140 output.cc
--- output.cc	12 Feb 2011 03:19:24 -0000	1.140
+++ output.cc	13 Mar 2011 02:31:36 -0000
@@ -2165,10 +2165,10 @@ Output_section::add_input_section(Layout
       || this->must_sort_attached_input_sections()
       || parameters->options().user_set_Map()
       || parameters->target().may_relax()
-      || parameters->options().section_ordering_file())
+      || layout->is_section_ordering_specified())
     {
       Input_section isecn(object, shndx, input_section_size, addralign);
-      if (parameters->options().section_ordering_file())
+      if (layout->is_section_ordering_specified())
         {
           unsigned int section_order_index =
             layout->find_section_order_index(std::string(secname));
@@ -3041,6 +3041,34 @@ Output_section::Input_section_sort_secti
   return s1_secn_index < s2_secn_index;
 }
 
+// Updates the ordering of input sections in this output section.
+
+void
+Output_section::update_section_layout(Layout* layout)
+{
+  for (Input_section_list::iterator p = this->input_sections_.begin();
+       p != this->input_sections_.end();
+       ++p)
+    {
+      if ((*p).is_input_section()
+	  || (*p).is_relaxed_input_section())
+        {
+	  Object* obj = ((*p).is_input_section()
+			 ? (*p).relobj()
+		         : (*p).relaxed_input_section()->relobj());
+
+          std::string section_name = obj->section_name((*p).shndx());
+	  unsigned int section_order_index =
+            layout->find_section_order_index(section_name);
+	  if (section_order_index != 0)
+            {
+              (*p).set_section_order_index(section_order_index);
+              this->set_input_section_order_specified();
+	    }
+         }
+    }
+}
+
 // Sort the input sections attached to an output section.
 
 void
@@ -3083,7 +3111,7 @@ Output_section::sort_attached_input_sect
     }
   else
     {
-      gold_assert(parameters->options().section_ordering_file());
+      gold_assert(this->input_section_order_specified());
       std::sort(sort_list.begin(), sort_list.end(),
 	        Input_section_sort_section_order_index_compare());
     }
Index: output.h
===================================================================
RCS file: /cvs/src/src/gold/output.h,v
retrieving revision 1.118
diff -u -u -p -r1.118 output.h
--- output.h	23 Dec 2010 19:56:14 -0000	1.118
+++ output.h	13 Mar 2011 02:31:36 -0000
@@ -2564,6 +2564,9 @@ class Output_section : public Output_dat
   flags() const
   { return this->flags_; }
 
+  void
+  update_section_layout(Layout* layout);
+
   // Update the output section flags based on input section flags.
   void
   update_flags_for_input_section(elfcpp::Elf_Xword flags);
Index: plugin.cc
===================================================================
RCS file: /cvs/src/src/gold/plugin.cc,v
retrieving revision 1.43
diff -u -u -p -r1.43 plugin.cc
--- plugin.cc	8 Feb 2011 05:03:19 -0000	1.43
+++ plugin.cc	13 Mar 2011 02:31:36 -0000
@@ -57,6 +57,9 @@ static enum ld_plugin_status
 register_claim_file(ld_plugin_claim_file_handler handler);
 
 static enum ld_plugin_status
+register_inspect_unclaimed_object(ld_plugin_inspect_unclaimed_object_handler handler);
+
+static enum ld_plugin_status
 register_all_symbols_read(ld_plugin_all_symbols_read_handler handler);
 
 static enum ld_plugin_status
@@ -86,6 +89,28 @@ set_extra_library_path(const char *path)
 static enum ld_plugin_status
 message(int level, const char *format, ...);
 
+static enum ld_plugin_status
+get_section_count(const void* handle, unsigned int* count);
+
+static enum ld_plugin_status
+get_section_type(void* handle, unsigned int shndx,
+                 unsigned int* type);
+
+static enum ld_plugin_status
+get_section_name(void* handle, unsigned int shndx,
+                 char** section_name_ptr);
+
+static enum ld_plugin_status
+get_section_contents(void* handle, unsigned int shndx,
+                     unsigned char** section_contents,
+		     unsigned int* len);
+
+static enum ld_plugin_status
+read_layout_from_file(const char* filename);
+
+static enum ld_plugin_status
+allow_section_ordering();
+
 };
 
 #endif // ENABLE_PLUGINS
@@ -130,7 +155,7 @@ Plugin::load()
   sscanf(ver, "%d.%d", &major, &minor);
 
   // Allocate and populate a transfer vector.
-  const int tv_fixed_size = 16;
+  const int tv_fixed_size = 23;
   int tv_size = this->args_.size() + tv_fixed_size;
   ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
 
@@ -173,6 +198,11 @@ Plugin::load()
   tv[i].tv_u.tv_register_claim_file = register_claim_file;
 
   ++i;
+  tv[i].tv_tag = LDPT_REGISTER_INSPECT_UNCLAIMED_OBJECT_HOOK;
+  tv[i].tv_u.tv_register_inspect_unclaimed_object
+    = register_inspect_unclaimed_object;
+
+  ++i;
   tv[i].tv_tag = LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK;
   tv[i].tv_u.tv_register_all_symbols_read = register_all_symbols_read;
 
@@ -209,6 +239,30 @@ Plugin::load()
   tv[i].tv_u.tv_set_extra_library_path = set_extra_library_path;
 
   ++i;
+  tv[i].tv_tag = LDPT_GET_SECTION_COUNT;
+  tv[i].tv_u.tv_get_section_count = get_section_count;
+
+  ++i;
+  tv[i].tv_tag = LDPT_GET_SECTION_TYPE;
+  tv[i].tv_u.tv_get_section_type = get_section_type;
+
+  ++i;
+  tv[i].tv_tag = LDPT_GET_SECTION_NAME;
+  tv[i].tv_u.tv_get_section_name = get_section_name;
+
+  ++i;
+  tv[i].tv_tag = LDPT_GET_SECTION_CONTENTS;
+  tv[i].tv_u.tv_get_section_contents = get_section_contents;
+
+  ++i;
+  tv[i].tv_tag = LDPT_READ_LAYOUT_FROM_FILE;
+  tv[i].tv_u.tv_read_layout_from_file = read_layout_from_file;
+
+  ++i;
+  tv[i].tv_tag = LDPT_ALLOW_SECTION_ORDERING;
+  tv[i].tv_u.tv_allow_section_ordering = allow_section_ordering;
+
+  ++i;
   tv[i].tv_tag = LDPT_NULL;
   tv[i].tv_u.tv_val = 0;
 
@@ -237,6 +291,16 @@ Plugin::claim_file(struct ld_plugin_inpu
   return false;
 }
 
+// Call the plugin inspect_unclaimed_object handler.
+
+inline void
+Plugin::inspect_unclaimed_object(unsigned int index)
+{
+  void* handle =  reinterpret_cast<void*>(index);
+  if (this->inspect_unclaimed_object_handler_ != NULL)
+      (*this->inspect_unclaimed_object_handler_)(handle);
+}
+
 // Call the all-symbols-read handler.
 
 inline void
@@ -319,8 +383,9 @@ Plugin_manager::~Plugin_manager()
 // Load all plugin libraries.
 
 void
-Plugin_manager::load_plugins()
+Plugin_manager::load_plugins(Layout* layout)
 {
+  this->layout_ = layout;
   for (this->current_ = this->plugins_.begin();
        this->current_ != this->plugins_.end();
        ++this->current_)
@@ -365,6 +430,27 @@ Plugin_manager::claim_file(Input_file* i
   return NULL;
 }
 
+// Call the plugin inspect_unclaimed_object handlers to allow them to inspect
+// the unclaimed object. Pass the handle of the object which is the index
+// into the vector containing the unclaimed objects.
+
+void
+Plugin_manager::inspect_unclaimed_object(Object* obj)
+{
+  unsigned int index;
+  index = this->unclaimed_objects_.size();
+  this->unclaimed_objects_.push_back(obj);
+
+  this->in_inspect_unclaimed_object_handler_ = true;
+
+  for (this->current_ = this->plugins_.begin();
+       this->current_ != this->plugins_.end();
+       ++this->current_)
+    (*this->current_)->inspect_unclaimed_object(index);
+
+  this->in_inspect_unclaimed_object_handler_ = false;
+}
+
 // Save an archive.  This is used so that a plugin can add a file
 // which refers to a symbol which was not previously referenced.  In
 // that case we want to pretend that the symbol was referenced before,
@@ -395,7 +481,7 @@ Plugin_manager::save_input_group(Input_g
 void
 Plugin_manager::all_symbols_read(Workqueue* workqueue, Task* task,
                                  Input_objects* input_objects,
-	                         Symbol_table* symtab, Layout* layout,
+	                         Symbol_table* symtab,
 	                         Dirsearch* dirpath, Mapfile* mapfile,
 	                         Task_token** last_blocker)
 {
@@ -404,7 +490,6 @@ Plugin_manager::all_symbols_read(Workque
   this->task_ = task;
   this->input_objects_ = input_objects;
   this->symtab_ = symtab;
-  this->layout_ = layout;
   this->dirpath_ = dirpath;
   this->mapfile_ = mapfile;
   this->this_blocker_ = NULL;
@@ -635,6 +720,20 @@ Plugin_manager::release_input_file(unsig
   return LDPS_OK;
 }
 
+// Get the object from the list of unclaimed objects with
+// index specified in handle.
+
+Object*
+Plugin_manager::get_unclaimed_object(const void* handle)
+{
+  unsigned int index =  static_cast<unsigned int>(reinterpret_cast<intptr_t>(handle));
+  Object* obj = NULL;
+
+  obj = parameters->options().plugins()->unclaimed_object(index);
+
+  return obj;
+}
+
 // Add a new library path.
 
 ld_plugin_status
@@ -1168,7 +1267,6 @@ Plugin_hook::run(Workqueue* workqueue)
                                              this,
                                              this->input_objects_,
                                              this->symtab_,
-                                             this->layout_,
                                              this->dirpath_,
                                              this->mapfile_,
                                              &this->this_blocker_);
@@ -1190,6 +1288,18 @@ register_claim_file(ld_plugin_claim_file
   return LDPS_OK;
 }
 
+//Register a inspect_unclaimed_object handler.
+
+static enum ld_plugin_status
+register_inspect_unclaimed_object
+  (ld_plugin_inspect_unclaimed_object_handler handler)
+{
+  gold_assert(parameters->options().has_plugins());
+  parameters->options().plugins()->set_inspect_unclaimed_object_handler(
+    handler);
+  return LDPS_OK;
+}
+
 // Register an all-symbols-read handler.
 
 static enum ld_plugin_status
@@ -1317,6 +1427,123 @@ message(int level, const char* format, .
   return LDPS_OK;
 }
 
+// Get the section count of the object corresponding to the handle.  This
+// plugin interface can only be called in the inspect_unclaimed_object
+// handler of the plugin.
+
+static enum ld_plugin_status
+get_section_count(const void* handle, unsigned int* count)
+{
+  gold_assert(parameters->options().has_plugins());
+
+  if (!parameters->options().plugins()->in_inspect_unclaimed_object_handler())
+    return LDPS_ERR;
+
+  Object* obj = parameters->options().plugins()->get_unclaimed_object(handle);
+
+  if (obj == NULL)
+    return LDPS_BAD_HANDLE;
+
+  *count = obj->shnum();
+  return LDPS_OK;
+}
+
+// Get the type of the specified section in the object corresponding
+// to the handle.  This plugin interface can only be called in the
+// inspect_unclaimed_object handler of the plugin.
+
+static enum ld_plugin_status
+get_section_type(void* handle, unsigned int shndx, unsigned int* type)
+{
+  gold_assert(parameters->options().has_plugins());
+
+  if (!parameters->options().plugins()->in_inspect_unclaimed_object_handler())
+    return LDPS_ERR;
+
+  Object* obj = parameters->options().plugins()->get_unclaimed_object(handle);
+
+  if (obj == NULL)
+    return LDPS_BAD_HANDLE;
+
+  *type = obj->section_type(shndx);
+  return LDPS_OK;
+}
+
+// Get the name of the specified section in the object corresponding
+// to the handle.  This plugin interface can only be called in the
+// inspect_unclaimed_object handler of the plugin.
+
+static enum ld_plugin_status
+get_section_name(void* handle, unsigned int shndx, char** section_name_ptr)
+{
+  gold_assert(parameters->options().has_plugins());
+
+  if (!parameters->options().plugins()->in_inspect_unclaimed_object_handler())
+    return LDPS_ERR;
+
+  Object* obj = parameters->options().plugins()->get_unclaimed_object(handle);
+
+  if (obj == NULL)
+    return LDPS_BAD_HANDLE;
+
+  const char* section_name = obj->section_name(shndx).c_str();
+  *section_name_ptr = (char*)malloc(strlen(section_name) + 1);
+  strcpy(*section_name_ptr, section_name);
+  return LDPS_OK;
+}
+
+// Get the contents of the specified section in the object corresponding
+// to the handle.  This plugin interface can only be called in the
+// inspect_unclaimed_object handler of the plugin.
+
+static enum ld_plugin_status
+get_section_contents(void* handle, unsigned int shndx,
+                     unsigned char** section_contents_ptr,
+		     unsigned int* len)
+{
+  gold_assert(parameters->options().has_plugins());
+
+  if (!parameters->options().plugins()->in_inspect_unclaimed_object_handler())
+    return LDPS_ERR;
+
+  Object* obj = parameters->options().plugins()->get_unclaimed_object(handle);
+
+  if (obj == NULL)
+    return LDPS_BAD_HANDLE;
+
+  section_size_type plen;
+  const unsigned char* section_contents = obj->section_contents(shndx, &plen,
+                                                              false);
+  *section_contents_ptr = (unsigned char*)malloc(plen);
+  memcpy(*section_contents_ptr, section_contents, plen);
+  *len = plen;
+  return LDPS_OK;
+}
+
+// Specify the ordering of sections in the final layout in a file. This
+// does what the linker option --section-ordering-file does.
+
+static enum ld_plugin_status
+read_layout_from_file(const char* filename)
+{
+  gold_assert(parameters->options().has_plugins());
+  Layout* layout = parameters->options().plugins()->layout();
+  layout->read_layout_from_file(filename);
+  layout->update_layout_of_sections();
+  return LDPS_OK;
+}
+
+// Let the linker know that the sections could be reordered.
+
+static enum ld_plugin_status
+allow_section_ordering()
+{
+  gold_assert(parameters->options().has_plugins());
+  Layout* layout = parameters->options().plugins()->layout();
+  layout->section_ordering_specified();
+  return LDPS_OK;
+}
+
 #endif // ENABLE_PLUGINS
 
 // Allocate a Pluginobj object of the appropriate size and endianness.
Index: plugin.h
===================================================================
RCS file: /cvs/src/src/gold/plugin.h,v
retrieving revision 1.16
diff -u -u -p -r1.16 plugin.h
--- plugin.h	24 Jan 2011 21:48:40 -0000	1.16
+++ plugin.h	13 Mar 2011 02:31:36 -0000
@@ -58,6 +58,7 @@ class Plugin
       filename_(filename),
       args_(),
       claim_file_handler_(NULL),
+      inspect_unclaimed_object_handler_(NULL),
       all_symbols_read_handler_(NULL),
       cleanup_handler_(NULL),
       cleanup_done_(false)
@@ -74,6 +75,10 @@ class Plugin
   bool
   claim_file(struct ld_plugin_input_file* plugin_input_file);
 
+  // Call the inspect_unclaimed_object handler.
+  void
+  inspect_unclaimed_object(unsigned int index);
+
   // Call the all-symbols-read handler.
   void
   all_symbols_read();
@@ -87,6 +92,12 @@ class Plugin
   set_claim_file_handler(ld_plugin_claim_file_handler handler)
   { this->claim_file_handler_ = handler; }
 
+  // Register a inspect_unclaimed_object handler.
+  void
+  set_inspect_unclaimed_object_handler
+    (ld_plugin_inspect_unclaimed_object_handler handler)
+  { this->inspect_unclaimed_object_handler_ = handler; }
+
   // Register an all-symbols-read handler.
   void
   set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler)
@@ -116,6 +127,7 @@ class Plugin
   std::vector<std::string> args_;
   // The plugin's event handlers.
   ld_plugin_claim_file_handler claim_file_handler_;
+  ld_plugin_inspect_unclaimed_object_handler inspect_unclaimed_object_handler_;
   ld_plugin_all_symbols_read_handler all_symbols_read_handler_;
   ld_plugin_cleanup_handler cleanup_handler_;
   // TRUE if the cleanup handlers have been called.
@@ -128,9 +140,11 @@ class Plugin_manager
 {
  public:
   Plugin_manager(const General_options& options)
-    : plugins_(), objects_(), deferred_layout_objects_(), input_file_(NULL),
+    : plugins_(), objects_(), unclaimed_objects_(),
+      deferred_layout_objects_(), input_file_(NULL),
       plugin_input_file_(), rescannable_(), undefined_symbols_(),
       any_claimed_(false), in_replacement_phase_(false), any_added_(false),
+      in_inspect_unclaimed_object_handler_(false),
       options_(options), workqueue_(NULL), task_(NULL), input_objects_(NULL),
       symtab_(NULL), layout_(NULL), dirpath_(NULL), mapfile_(NULL),
       this_blocker_(NULL), extra_search_path_()
@@ -153,12 +167,26 @@ class Plugin_manager
 
   // Load all plugin libraries.
   void
-  load_plugins();
+  load_plugins(Layout* layout);
 
   // Call the plugin claim-file handlers in turn to see if any claim the file.
   Pluginobj*
   claim_file(Input_file* input_file, off_t offset, off_t filesize);
 
+  // Call the plugin inspect_unclaimed_object handlers to allow them
+  // to inspect the file.
+  void
+  inspect_unclaimed_object(Object* obj);
+
+  Object*
+  get_unclaimed_object(const void* handle);
+
+  // True if the inspect_unclaimed_object handler of the plugins are being
+  // called.
+  bool
+  in_inspect_unclaimed_object_handler()
+  { return in_inspect_unclaimed_object_handler_; }
+
   // Let the plugin manager save an archive for later rescanning.
   // This takes ownership of the Archive pointer.
   void
@@ -173,7 +201,7 @@ class Plugin_manager
   void
   all_symbols_read(Workqueue* workqueue, Task* task,
                    Input_objects* input_objects, Symbol_table* symtab,
-                   Layout* layout, Dirsearch* dirpath, Mapfile* mapfile,
+                   Dirsearch* dirpath, Mapfile* mapfile,
                    Task_token** last_blocker);
 
   // Tell the plugin manager that we've a new undefined symbol which
@@ -197,6 +225,15 @@ class Plugin_manager
     (*this->current_)->set_claim_file_handler(handler);
   }
 
+  // Register a inspect_unclaimed_object handler.
+  void
+  set_inspect_unclaimed_object_handler
+    (ld_plugin_inspect_unclaimed_object_handler handler)
+  {
+    gold_assert(this->current_ != plugins_.end());
+    (*this->current_)->set_inspect_unclaimed_object_handler(handler);
+  }
+
   // Register an all-symbols-read handler.
   void
   set_all_symbols_read_handler(ld_plugin_all_symbols_read_handler handler)
@@ -227,6 +264,15 @@ class Plugin_manager
     return this->objects_[handle];
   }
 
+  // Return the unclaimed object associated with the given HANDLE.
+  Object*
+  unclaimed_object(unsigned int handle) const
+  {
+    if (handle >= this->unclaimed_objects_.size())
+      return NULL;
+    return this->unclaimed_objects_[handle];
+  }
+
   // Return TRUE if any input files have been claimed by a plugin
   // and we are still in the initial input phase.
   bool
@@ -262,6 +308,14 @@ class Plugin_manager
   in_replacement_phase() const
   { return this->in_replacement_phase_; }
 
+  Input_objects*
+  input_objects() const
+  { return input_objects_; }
+
+  Layout*
+  layout()
+  { return layout_; }
+
  private:
   Plugin_manager(const Plugin_manager&);
   Plugin_manager& operator=(const Plugin_manager&);
@@ -291,6 +345,7 @@ class Plugin_manager
 
   typedef std::list<Plugin*> Plugin_list;
   typedef std::vector<Pluginobj*> Object_list;
+  typedef std::vector<Object*> Unclaimed_object_list;
   typedef std::vector<Relobj*> Deferred_layout_list;
   typedef std::vector<Rescannable> Rescannable_list;
   typedef std::vector<Symbol*> Undefined_symbol_list;
@@ -312,6 +367,12 @@ class Plugin_manager
   // serves as the "handle" that we pass to the plugins.
   Object_list objects_;
 
+  // The list of unclaimed objects.  The negative of the index of an
+  // in this list serves as the "handle" that we pass to the plugins.
+  // Postive integer values for "handle" are for the claimed objects
+  // and negative values are for the unclaimed objects.
+  Unclaimed_object_list unclaimed_objects_;
+
   // The list of regular objects whose layout has been deferred.
   Deferred_layout_list deferred_layout_objects_;
 
@@ -337,6 +398,10 @@ class Plugin_manager
   // Whether any input files or libraries were added by a plugin.
   bool any_added_;
 
+  // Set to true when the inspect_unclaimed_object_handler of the plugins are being
+  // called.
+  bool in_inspect_unclaimed_object_handler_;
+
   const General_options& options_;
   Workqueue* workqueue_;
   Task* task_;
Index: readsyms.cc
===================================================================
RCS file: /cvs/src/src/gold/readsyms.cc,v
retrieving revision 1.47
diff -u -u -p -r1.47 readsyms.cc
--- readsyms.cc	24 Jan 2011 21:48:40 -0000	1.47
+++ readsyms.cc	13 Mar 2011 02:31:36 -0000
@@ -380,6 +380,10 @@ Read_symbols::do_read_symbols(Workqueue*
 	  return false;
 	}
 
+      // Allow the plugins to inspect the unclaimed object now.
+      if (parameters->options().has_plugins())
+        parameters->options().plugins()->inspect_unclaimed_object(obj);
+
       Read_symbols_data* sd = new Read_symbols_data;
       obj->read_symbols(sd);
 
cvs diff: Diffing po
cvs diff: Diffing testsuite
Index: testsuite/plugin_test.c
===================================================================
RCS file: /cvs/src/src/gold/testsuite/plugin_test.c,v
retrieving revision 1.4
diff -u -u -p -r1.4 plugin_test.c
--- testsuite/plugin_test.c	9 Nov 2009 16:11:34 -0000	1.4
+++ testsuite/plugin_test.c	13 Mar 2011 02:31:37 -0000
@@ -52,6 +52,8 @@ static struct claimed_file* first_claime
 static struct claimed_file* last_claimed_file = NULL;
 
 static ld_plugin_register_claim_file register_claim_file_hook = NULL;
+static ld_plugin_register_inspect_unclaimed_object
+  register_inspect_unclaimed_object_hook = NULL;
 static ld_plugin_register_all_symbols_read register_all_symbols_read_hook = NULL;
 static ld_plugin_register_cleanup register_cleanup_hook = NULL;
 static ld_plugin_add_symbols add_symbols = NULL;
@@ -60,6 +62,12 @@ static ld_plugin_add_input_file add_inpu
 static ld_plugin_message message = NULL;
 static ld_plugin_get_input_file get_input_file = NULL;
 static ld_plugin_release_input_file release_input_file = NULL;
+static ld_plugin_get_section_count get_section_count = NULL;
+static ld_plugin_get_section_type get_section_type = NULL;
+static ld_plugin_get_section_name get_section_name = NULL;
+static ld_plugin_get_section_contents get_section_contents = NULL;
+static ld_plugin_read_layout_from_file read_layout_from_file = NULL;
+static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
 
 #define MAXOPTS 10
 
@@ -69,6 +77,7 @@ static int nopts = 0;
 enum ld_plugin_status onload(struct ld_plugin_tv *tv);
 enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
                                       int *claimed);
+enum ld_plugin_status inspect_unclaimed_object_hook(void* handle);
 enum ld_plugin_status all_symbols_read_hook(void);
 enum ld_plugin_status cleanup_hook(void);
 
@@ -101,6 +110,10 @@ onload(struct ld_plugin_tv *tv)
         case LDPT_REGISTER_CLAIM_FILE_HOOK:
           register_claim_file_hook = entry->tv_u.tv_register_claim_file;
           break;
+	case LDPT_REGISTER_INSPECT_UNCLAIMED_OBJECT_HOOK:
+          register_inspect_unclaimed_object_hook
+            = entry->tv_u.tv_register_inspect_unclaimed_object;
+          break;
         case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
           register_all_symbols_read_hook =
             entry->tv_u.tv_register_all_symbols_read;
@@ -126,6 +139,24 @@ onload(struct ld_plugin_tv *tv)
         case LDPT_RELEASE_INPUT_FILE:
           release_input_file = entry->tv_u.tv_release_input_file;
           break;
+        case LDPT_GET_SECTION_COUNT:
+          get_section_count = *entry->tv_u.tv_get_section_count;
+          break;
+        case LDPT_GET_SECTION_TYPE:
+          get_section_type = *entry->tv_u.tv_get_section_type;
+          break;
+        case LDPT_GET_SECTION_NAME:
+          get_section_name = *entry->tv_u.tv_get_section_name;
+          break;
+        case LDPT_GET_SECTION_CONTENTS:
+          get_section_contents = *entry->tv_u.tv_get_section_contents;
+          break;
+	case LDPT_READ_LAYOUT_FROM_FILE:
+	  read_layout_from_file = *entry->tv_u.tv_read_layout_from_file;
+	  break;
+	case LDPT_ALLOW_SECTION_ORDERING:
+	  allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
+	  break;
         default:
           break;
         }
@@ -143,6 +174,13 @@ onload(struct ld_plugin_tv *tv)
       return LDPS_ERR;
     }
 
+  if (register_inspect_unclaimed_object_hook == NULL)
+    {
+      fprintf(stderr,
+              "tv_register_inspect_unclaimed_object_hook interface missing\n");
+      return LDPS_ERR;
+    }
+
   if (register_all_symbols_read_hook == NULL)
     {
       fprintf(stderr, "tv_register_all_symbols_read_hook interface missing\n");
@@ -167,6 +205,14 @@ onload(struct ld_plugin_tv *tv)
       return LDPS_ERR;
     }
 
+  if ((*register_inspect_unclaimed_object_hook)
+        (inspect_unclaimed_object_hook) != LDPS_OK)
+    {
+      (*message)(LDPL_ERROR,
+                 "error registering inspect unclaimed object hook");
+      return LDPS_ERR;
+    }
+
   if ((*register_all_symbols_read_hook)(all_symbols_read_hook) != LDPS_OK)
     {
       (*message)(LDPL_ERROR, "error registering all symbols read hook");
@@ -179,10 +225,53 @@ onload(struct ld_plugin_tv *tv)
       return LDPS_ERR;
     }
 
+  if (get_section_count == NULL)
+    {
+      fprintf(stderr, "tv_get_section_count interface missing\n");
+      return LDPS_ERR;
+    }
+
+  if (get_section_type == NULL)
+    {
+      fprintf(stderr, "tv_get_section_type interface missing\n");
+      return LDPS_ERR;
+    }
+
+  if (get_section_name == NULL)
+    {
+      fprintf(stderr, "tv_get_section_name interface missing\n");
+      return LDPS_ERR;
+    }
+
+  if (get_section_contents == NULL)
+    {
+      fprintf(stderr, "tv_get_section_contents interface missing\n");
+      return LDPS_ERR;
+    }
+
+  if (read_layout_from_file == NULL)
+    {
+      fprintf(stderr, "tv_read_layout_from_file interface missing\n");
+      return LDPS_ERR;
+    }
+
+  if (allow_section_ordering == NULL)
+    {
+      fprintf(stderr, "tv_allow_section_ordering interface missing\n");
+      return LDPS_ERR;
+    }
+
   return LDPS_OK;
 }
 
 enum ld_plugin_status
+inspect_unclaimed_object_hook (void* handle)
+{
+  (*message)(LDPL_INFO, "Inspect unclaimed object hook called with handle: %p",
+             handle);
+  return LDPS_OK;
+}
+enum ld_plugin_status
 claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
 {
   int len;
Index: plugin-api.h
===================================================================
RCS file: /cvs/src/src/include/plugin-api.h,v
retrieving revision 1.13
diff -u -u -p -r1.13 plugin-api.h
--- plugin-api.h	3 Jan 2011 21:05:50 -0000	1.13
+++ plugin-api.h	13 Mar 2011 02:24:32 -0000
@@ -157,6 +157,12 @@ enum ld_plugin_status
 (*ld_plugin_claim_file_handler) (
   const struct ld_plugin_input_file *file, int *claimed);
 
+/* The plugin library's "observe file" handler.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_inspect_unclaimed_object_handler) (void *);
+
 /* The plugin library's "all symbols read" handler.  */
 
 typedef
@@ -175,6 +181,13 @@ typedef
 enum ld_plugin_status
 (*ld_plugin_register_claim_file) (ld_plugin_claim_file_handler handler);
 
+/* The linker's interface for registering the "observe file" handler.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_register_inspect_unclaimed_object)
+  (ld_plugin_inspect_unclaimed_object_handler handler);
+
 /* The linker's interface for registering the "all symbols read" handler.  */
 
 typedef
@@ -240,6 +253,59 @@ typedef
 enum ld_plugin_status
 (*ld_plugin_message) (int level, const char *format, ...);
 
+/* The linker's interface for retrieving the number of sections in an object.
+   The handle is obtained in the inspect_unclaimed_object_handler.  This
+   interface should only be invoked in the inspect_unclaimed_object_handler. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_get_section_count) (const void* handle, unsigned int* count);
+
+/* The linker's interface for retrieving the section type of a specific
+   section in an object.  The handle is obtained in the
+   inspect_unclaimed_object_handler.  This interface should only be
+   invoked in the inspect_unclaimed_object_handler. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_get_section_type) (void* handle, unsigned int shndx,
+                               unsigned int* type);
+
+/* The linker's interface for retrieving the name of specific section in
+   an object. The handle is obtained in the inspect_unclaimed_object_handler.
+   This interface should only be invoked in the
+   inspect_unclaimed_object_handler. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_get_section_name) (void* handle, unsigned int shndx,
+                               char** section_name_ptr);
+
+/* The linker's interface for retrieving the contents of a specific section
+   in an object.  The handle is obtained in the
+   inspect_unclaimed_object_handler.  This interface should only be invoked
+   in the inspect_unclaimed_object_handler. */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_get_section_contents) (void* handle, unsigned int shndx,
+                                   unsigned char** section_contents,
+                                   unsigned int* len);
+
+/* The linker's interface for specifying the desired order of sections
+   through a file.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_read_layout_from_file) (const char* filename);
+
+/* The linker's interface for specifying that reordering of sections is
+   desired.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_allow_section_ordering) (void);
+
 enum ld_plugin_level
 {
   LDPL_INFO,
@@ -258,6 +324,7 @@ enum ld_plugin_tag
   LDPT_LINKER_OUTPUT,
   LDPT_OPTION,
   LDPT_REGISTER_CLAIM_FILE_HOOK,
+  LDPT_REGISTER_INSPECT_UNCLAIMED_OBJECT_HOOK,
   LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK,
   LDPT_REGISTER_CLEANUP_HOOK,
   LDPT_ADD_SYMBOLS,
@@ -269,7 +336,13 @@ enum ld_plugin_tag
   LDPT_ADD_INPUT_LIBRARY,
   LDPT_OUTPUT_NAME,
   LDPT_SET_EXTRA_LIBRARY_PATH,
-  LDPT_GNU_LD_VERSION
+  LDPT_GNU_LD_VERSION,
+  LDPT_GET_SECTION_COUNT,
+  LDPT_GET_SECTION_TYPE,
+  LDPT_GET_SECTION_NAME,
+  LDPT_GET_SECTION_CONTENTS,
+  LDPT_READ_LAYOUT_FROM_FILE,
+  LDPT_ALLOW_SECTION_ORDERING
 };
 
 /* The plugin transfer vector.  */
@@ -282,6 +355,8 @@ struct ld_plugin_tv
     int tv_val;
     const char *tv_string;
     ld_plugin_register_claim_file tv_register_claim_file;
+    ld_plugin_register_inspect_unclaimed_object
+      tv_register_inspect_unclaimed_object;
     ld_plugin_register_all_symbols_read tv_register_all_symbols_read;
     ld_plugin_register_cleanup tv_register_cleanup;
     ld_plugin_add_symbols tv_add_symbols;
@@ -292,6 +367,12 @@ struct ld_plugin_tv
     ld_plugin_release_input_file tv_release_input_file;
     ld_plugin_add_input_library tv_add_input_library;
     ld_plugin_set_extra_library_path tv_set_extra_library_path;
+    ld_plugin_get_section_count tv_get_section_count;
+    ld_plugin_get_section_type tv_get_section_type;
+    ld_plugin_get_section_name tv_get_section_name;
+    ld_plugin_get_section_contents tv_get_section_contents;
+    ld_plugin_read_layout_from_file tv_read_layout_from_file;
+    ld_plugin_allow_section_ordering tv_allow_section_ordering;
   } tv_u;
 };
 


More information about the Binutils mailing list