This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] add section alignment/size hooks to gold plugin interface, revised


Second attempt at posting revised patch (first email was blocked by
SpamAssassin).

Hi Cary,

I've incorporated all of your suggestions, revised patch attached.
Thanks for your feedback.

Regards,

Than

include/
2016-02-26  Than McIntosh <thanm@google.com>

        * plugin-api.h: Add new hooks to the plugin transfer vector to
        to support querying section alignment and section size.
        (ld_plugin_get_input_section_alignment): New hook.
        (ld_plugin_get_input_section_size): New hook.
        (ld_plugin_tag): Add LDPT_GET_INPUT_SECTION_ALIGNMENT
          and LDPT_GET_INPUT_SECTION_SIZE.
        (ld_plugin_tv): Add tv_get_input_section_alignment and
          tv_get_input_section_size.

gold/
2016-02-26  Than McIntosh  <thanm@google.com>

        * plugin.cc (Plugin::load): Include hooks for get_input_section_size
        and get_input_section_alignment in transfer vector.
        (get_input_section_alignment): New function.
        (get_input_section_size): New function.
        * testsuite/Makefile.am: Add plugin_layout_with_alignment.sh test.
        * testsuite/Makefile.in: [Regenerate.]
        * testsuite/plugin_section_alignment.cc: New test file.
        * testsuite/plugin_layout_with_alignment.cc: New test file.
        * testsuite/plugin_layout_with_alignment.sh: New test file.

---

diff --git a/gold/plugin.cc b/gold/plugin.cc
index c01e4cd..a0ef240 100644
--- a/gold/plugin.cc
+++ b/gold/plugin.cc
@@ -155,6 +155,15 @@ unique_segment_for_sections(const char* segment_name,
     uint64_t align,
     const struct ld_plugin_section *section_list,
     unsigned int num_sections);
+
+static enum ld_plugin_status
+get_input_section_alignment(const struct ld_plugin_section section,
+                            unsigned int* addralign);
+
+static enum ld_plugin_status
+get_input_section_size(const struct ld_plugin_section section,
+                       uint64_t* secsize);
+
 };

 #endif // ENABLE_PLUGINS
@@ -199,7 +208,7 @@ Plugin::load()
   sscanf(ver, "%d.%d", &major, &minor);

   // Allocate and populate a transfer vector.
-  const int tv_fixed_size = 26;
+  const int tv_fixed_size = 28;

   int tv_size = this->args_.size() + tv_fixed_size;
   ld_plugin_tv* tv = new ld_plugin_tv[tv_size];
@@ -322,6 +331,14 @@ Plugin::load()
   tv[i].tv_u.tv_unique_segment_for_sections = unique_segment_for_sections;

   ++i;
+  tv[i].tv_tag = LDPT_GET_INPUT_SECTION_ALIGNMENT;
+  tv[i].tv_u.tv_get_input_section_alignment = get_input_section_alignment;
+
+  ++i;
+  tv[i].tv_tag = LDPT_GET_INPUT_SECTION_SIZE;
+  tv[i].tv_u.tv_get_input_section_size = get_input_section_size;
+
+  ++i;
   tv[i].tv_tag = LDPT_NULL;
   tv[i].tv_u.tv_val = 0;

@@ -1703,6 +1720,53 @@ get_input_section_contents(const struct
ld_plugin_section section,
   return LDPS_OK;
 }

+// Get the alignment of the specified section in the object corresponding
+// to the handle.  This plugin interface can only be called in the
+// claim_file handler of the plugin.
+
+static enum ld_plugin_status
+get_input_section_alignment(const struct ld_plugin_section section,
+                            unsigned int* addralign)
+{
+  gold_assert(parameters->options().has_plugins());
+
+  if (!parameters->options().plugins()->in_claim_file_handler())
+    return LDPS_ERR;
+
+  Object* obj
+    = parameters->options().plugins()->get_elf_object(section.handle);
+
+  if (obj == NULL)
+    return LDPS_BAD_HANDLE;
+
+  *addralign = obj->section_addralign(section.shndx);
+  return LDPS_OK;
+}
+
+// Get the size of the specified section in the object corresponding
+// to the handle.  This plugin interface can only be called in the
+// claim_file handler of the plugin.
+
+static enum ld_plugin_status
+get_input_section_size(const struct ld_plugin_section section,
+                       uint64_t* secsize)
+{
+  gold_assert(parameters->options().has_plugins());
+
+  if (!parameters->options().plugins()->in_claim_file_handler())
+    return LDPS_ERR;
+
+  Object* obj
+    = parameters->options().plugins()->get_elf_object(section.handle);
+
+  if (obj == NULL)
+    return LDPS_BAD_HANDLE;
+
+  *secsize = obj->section_size(section.shndx);
+  return LDPS_OK;
+}
+
+
 // Specify the ordering of sections in the final layout. The sections are
 // specified as (handle,shndx) pairs in the two arrays in the order in
 // which they should appear in the final layout.
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 32906db..34129f4 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -2085,6 +2085,21 @@ plugin_section_order.so: plugin_section_order.o
 plugin_section_order.o: plugin_section_order.c
  $(COMPILE) -O0 -c -fpic -o $@ $<

+check_SCRIPTS += plugin_layout_with_alignment.sh
+check_DATA += plugin_layout_with_alignment.stdout
+MOSTLYCLEANFILES += plugin_layout_with_alignment
+plugin_layout_with_alignment.o: plugin_layout_with_alignment.cc
+ $(CXXCOMPILE) -O0 -c -ffunction-sections  -fdata-sections -g -o $@ $<
+plugin_layout_with_alignment: plugin_layout_with_alignment.o
plugin_section_alignment.so gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/
-Wl,--plugin,"./plugin_section_alignment.so"
plugin_layout_with_alignment.o
+plugin_layout_with_alignment.stdout: plugin_layout_with_alignment
+ $(TEST_NM) -n --synthetic plugin_layout_with_alignment >
plugin_layout_with_alignment.stdout
+
+plugin_section_alignment.so: plugin_section_alignment.o
+ $(CXXLINK) -Bgcctestdir/ -shared plugin_section_alignment.o
+plugin_section_alignment.o: plugin_section_alignment.cc
+ $(CXXCOMPILE) -O0 -c -fpic -o $@ $<
+
 endif PLUGINS

 check_PROGRAMS += exclude_libs_test
diff --git a/gold/testsuite/plugin_layout_with_alignment.cc
b/gold/testsuite/plugin_layout_with_alignment.cc
new file mode 100644
index 0000000..0824d74
--- /dev/null
+++ b/gold/testsuite/plugin_layout_with_alignment.cc
@@ -0,0 +1,72 @@
+// plugin_layout_with_alignment.cc -- a test case for gold
+
+// Copyright (C) 2016 Free Software Foundation, Inc.
+// Written by Than McIntosh <thanm@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// Verify that plugin interfaces for section size and alignment work
+// correctly, and that section ordering via plugins is working
+// for .bss/.rodata/.data sections.
+
+// --- Initialized .rodata items
+
+__attribute__ ((section(".rodata.v1_a2")))
+const short rodata_item1 = 101;
+
+__attribute__ ((section(".rodata.v2_a1")))
+const char rodata_item2 = 'a';
+
+__attribute__ ((section(".rodata.v3_a8")))
+const double rodata_item3 = 777.777;
+
+__attribute__ ((section(".rodata.v4_a1")))
+const char rodata_item4[7] = {'1', '2', '3', '4', '5', '6', '7'};
+
+// --- Initialized .data items
+
+__attribute__ ((section(".data.v1_a2")))
+short rwdata_item1 = 101;
+
+__attribute__ ((section(".data.v2_a1")))
+char rwdata_item2 = 'a';
+
+__attribute__ ((section(".data.v3_a8")))
+double rwdata_item3 = 'b';
+
+__attribute__ ((section(".data.v4_a1")))
+char rwdata_item4[3] = {'a', 'b', 'c'};
+
+// --- Uninitialized .data items
+
+__attribute__ ((section(".bss.v1_a2")))
+short bss_item1;
+
+__attribute__ ((section(".bss.v2_a1")))
+char bss_item2;
+
+__attribute__ ((section(".bss.v3_a8")))
+struct blah { union { double d; char c; } u; } bss_item3;
+
+__attribute__ ((section(".bss.v4_a1")))
+char bss_item4[3];
+
+int main ()
+{
+  return 0;
+}
diff --git a/gold/testsuite/plugin_layout_with_alignment.sh
b/gold/testsuite/plugin_layout_with_alignment.sh
new file mode 100755
index 0000000..c5f07ae
--- /dev/null
+++ b/gold/testsuite/plugin_layout_with_alignment.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+# plugin_layout_with_alignment.sh -- test
+
+# Copyright (C) 2016 Free Software Foundation, Inc.
+# Written by Than McIntosh <thanm@google.com>.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# The goal of this program is to verify plugin alignment and size
+# interfaces and working correctly in combination with section ordering.
+# intended.  File plugin_layout_with_alignment.cc is in this test.
+
+
+set -e
+
+check()
+{
+    awk "
+BEGIN { saw1 = 0; saw2 = 0; saw3 = 0; saw4 = 0; counter = 1; err = 0;
ord = \"\"; }
+/.*$2\$/ { saw1 = counter; counter = counter + 1; ord = ord \" $2\";  }
+/.*$3\$/ { saw2 = counter; counter = counter + 1; ord = ord \" $3\";  }
+/.*$4\$/ { saw3 = counter; counter = counter + 1; ord = ord \" $4\";  }
+/.*$5\$/ { saw4 = counter; counter = counter + 1; ord = ord \" $5\";  }
+END {
+      if (!saw1) {
+  printf \"did not see $2\\n\";
+  exit 1;
+ }
+      if (!saw2) {
+  printf \"did not see $3\\n\";
+  exit 1;
+ }
+      if (!saw3) {
+  printf \"did not see $4\\n\";
+  exit 1;
+ }
+      if (!saw4) {
+  printf \"did not see $5\\n\";
+  exit 1;
+ }
+      if (saw1 != 1 || saw2 != 2 || saw3 != 3 || saw4 != 4) {
+  printf \"incorrect ordering:\\nwas:%s\\nshould have been: $2 $3 $4
$5\\n\", ord;
+  exit 1;
+ }
+    }" $1
+}
+
+check plugin_layout_with_alignment.stdout "bss_item3" "bss_item1"
"bss_item4" "bss_item2"
+check plugin_layout_with_alignment.stdout "rwdata_item2"
"rwdata_item4" "rwdata_item1" "rwdata_item3"
+check plugin_layout_with_alignment.stdout "rodata_item3"
"rodata_item1" "rodata_item2" "rodata_item4"
diff --git a/gold/testsuite/plugin_section_alignment.cc
b/gold/testsuite/plugin_section_alignment.cc
new file mode 100644
index 0000000..6f64bdc
--- /dev/null
+++ b/gold/testsuite/plugin_section_alignment.cc
@@ -0,0 +1,267 @@
+// plugin_section_alignment.cc -- plugins to test ordering with
{size,alignment}
+//
+// Copyright (C) 2016 Free Software Foundation, Inc.
+// Written by Than McIntosh <thanm@google.com>.
+//
+// This file is part of gold.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+//
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+#include "plugin-api.h"
+
+static ld_plugin_get_input_section_count get_input_section_count = NULL;
+static ld_plugin_get_input_section_alignment
get_input_section_alignment = NULL;
+static ld_plugin_get_input_section_size get_input_section_size = NULL;
+static ld_plugin_get_input_section_name get_input_section_name = NULL;
+static ld_plugin_update_section_order update_section_order = NULL;
+static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
+
+extern "C" {
+  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 all_symbols_read_hook(void);
+}
+
+typedef enum { FL_BSS, FL_DATA, FL_RODATA, FL_UNKNOWN } sec_flavor;
+
+inline static int is_prefix_of(const char *prefix, const char *str)
+{
+  return strncmp(prefix, str, strlen(prefix)) == 0;
+}
+
+inline static sec_flavor flavor_from_name(const char *secname)
+{
+  if (is_prefix_of(".data.v", secname)) {
+    return FL_DATA;
+  } else if (is_prefix_of(".bss.v", secname)) {
+    return FL_BSS;
+  } else if (is_prefix_of(".rodata.v", secname)) {
+    return FL_RODATA;
+  } else {
+    return FL_UNKNOWN;
+  }
+}
+
+struct SectionInfo {
+  ld_plugin_section plugin_section;
+  std::string name;
+  uint64_t size;
+  sec_flavor flavor;
+  unsigned align;
+
+  static bool SectionInfoLt(const SectionInfo &i1,
+                            const SectionInfo &i2)
+  {
+    if (i1.flavor != i2.flavor) {
+      return ((unsigned) i1.flavor) < ((unsigned) i2.flavor);
+    }
+    switch (i1.flavor) {
+      case FL_DATA:
+        // Sort data items by increasing alignment then increasing size
+        if (i1.align != i2.align) {
+          return ((unsigned) i1.align) < ((unsigned) i2.align);
+        }
+        if (i1.size != i2.size) {
+          return ((unsigned) i1.size) < ((unsigned) i2.size);
+        }
+        break;
+      case FL_BSS:
+        // Sort bss items by decreasing alignment then decreasing size
+        if (i1.align != i2.align) {
+          return ((unsigned) i2.align) < ((unsigned) i1.align);
+        }
+        if (i1.size != i2.size) {
+          return ((unsigned) i2.size) < ((unsigned) i1.size);
+        }
+        break;
+      case FL_RODATA:
+        // Sort rodata items by decreasing alignment then increasing size
+        if (i1.align != i2.align) {
+          return ((unsigned) i2.align) < ((unsigned) i1.align);
+        }
+        if (i1.size != i2.size) {
+          return ((unsigned) i1.size) < ((unsigned) i2.size);
+        }
+      default:
+        break;
+    }
+
+    // Break ties by name
+    return i1.name.compare(i2.name) < 0;
+  }
+
+};
+typedef std::vector<SectionInfo> section_info_vector;
+section_info_vector raw_sections;
+
+// Set to 1 for debugging output
+unsigned trace = 0;
+
+extern "C" {
+
+// Plugin entry point.
+enum ld_plugin_status onload(struct ld_plugin_tv *tv)
+{
+  struct ld_plugin_tv *entry;
+  for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
+  {
+    switch (entry->tv_tag)
+    {
+      case LDPT_OPTION:
+        if (!strcmp(entry->tv_u.tv_string,"-trace")) {
+          fprintf(stderr, "enabling tracing\n");
+          trace += 1;
+        } else {
+          fprintf(stderr, "unknown plugin option %s", entry->tv_u.tv_string);
+        }
+        break;
+      case LDPT_REGISTER_CLAIM_FILE_HOOK:
+        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);
+        break;
+      case LDPT_GET_INPUT_SECTION_COUNT:
+        get_input_section_count = *entry->tv_u.tv_get_input_section_count;
+        break;
+      case LDPT_GET_INPUT_SECTION_NAME:
+        get_input_section_name = *entry->tv_u.tv_get_input_section_name;
+        break;
+      case LDPT_GET_INPUT_SECTION_ALIGNMENT:
+        get_input_section_alignment =
+            *entry->tv_u.tv_get_input_section_alignment;
+        break;
+      case LDPT_GET_INPUT_SECTION_SIZE:
+        get_input_section_size = *entry->tv_u.tv_get_input_section_size;
+        break;
+      case LDPT_UPDATE_SECTION_ORDER:
+        update_section_order = *entry->tv_u.tv_update_section_order;
+        break;
+      case LDPT_ALLOW_SECTION_ORDERING:
+        allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
+        break;
+      default:
+        break;
+    }
+  }
+
+  if (get_input_section_count == NULL || get_input_section_alignment == NULL ||
+      get_input_section_size == NULL || get_input_section_name == NULL ||
+      update_section_order == NULL || allow_section_ordering == NULL) {
+    fprintf(stderr, "Some interfaces are missing\n");
+    return LDPS_ERR;
+  }
+
+  return LDPS_OK;
+}
+
+// This function is called by the linker for every new object it encounters.
+enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
+                                      int *claimed)
+{
+  static bool is_ordering_specified = false;
+  struct ld_plugin_section section;
+  unsigned count = 0;
+  unsigned shndx;
+
+  *claimed = 0;
+  if (!is_ordering_specified) {
+    // Inform the linker to prepare for section reordering.
+    (*allow_section_ordering)();
+    is_ordering_specified = true;
+  }
+
+  (*get_input_section_count)(file->handle, &count);
+
+  for (shndx = 0; shndx < count; ++shndx) {
+    char *name = NULL;
+
+    section.handle = file->handle;
+    section.shndx = shndx;
+    (*get_input_section_name)(section, &name);
+    if (is_prefix_of(".data.v", name) ||
+        is_prefix_of(".bss.v", name) ||
+        is_prefix_of(".rodata.v", name)) {
+      SectionInfo si;
+      si.plugin_section.handle = file->handle;
+      si.plugin_section.shndx = shndx;
+      (*get_input_section_size)(section, &si.size);
+      (*get_input_section_alignment)(section, &si.align);
+      si.name = name;
+      si.flavor = flavor_from_name(name);
+      raw_sections.push_back(si);
+    }
+  }
+
+  return LDPS_OK;
+}
+
+// This function is called by the linker after all the symbols have been read.
+// At this stage, it is fine to tell the linker the desired function order.
+
+enum ld_plugin_status all_symbols_read_hook(void)
+{
+  // We expect to see a total of twelve sections -- if this is not the case
+  // then something went wrong somewhere along the way.
+  if (raw_sections.size() != 12) {
+    fprintf(stderr, "Expected 12 sections, found %u sections",
+            (unsigned) raw_sections.size());
+    return LDPS_ERR;
+  }
+
+  std::sort(raw_sections.begin(), raw_sections.end(),
+            SectionInfo::SectionInfoLt);
+
+  struct ld_plugin_section section_list[12];
+  for (unsigned ii = 0; ii < 12; ++ii) {
+    section_list[ii] = raw_sections[ii].plugin_section;
+  }
+
+  if (trace) {
+    fprintf(stderr, "Specified section order is:\n");
+    for (section_info_vector::iterator it = raw_sections.begin();
+         it != raw_sections.end();
+         ++it) {
+      const SectionInfo &si = (*it);
+      fprintf(stderr, "Idx=%u Name=%s Align=%u Size=%u\n",
+              si.plugin_section.shndx, si.name.c_str(), si.align,
+              (unsigned) si.size);
+    }
+  }
+
+  update_section_order(section_list, 12);
+
+  return LDPS_OK;
+}
+
+} // end extern "C"
diff --git a/include/plugin-api.h b/include/plugin-api.h
index d7f9ee3..3ee2e2b 100644
--- a/include/plugin-api.h
+++ b/include/plugin-api.h
@@ -345,6 +345,26 @@ enum ld_plugin_status
     const struct ld_plugin_section * section_list,
     unsigned int num_sections);

+/* The linker's interface for retrieving the section alignment requirement
+   of a specific section in an object.  This interface should only be
invoked in the
+   claim_file handler.  This function sets *ADDRALIGN to the ELF sh_addralign
+   value of the input section.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_get_input_section_alignment) (const struct
ld_plugin_section section,
+                                          unsigned int *addralign);
+
+/* The linker's interface for retrieving the section size of a specific section
+   in an object.  This interface should only be invoked in the
claim_file handler.
+   This function sets *SECSIZE to the ELF sh_size
+   value of the input section.  */
+
+typedef
+enum ld_plugin_status
+(*ld_plugin_get_input_section_size) (const struct ld_plugin_section section,
+                                     uint64_t *secsize);
+
 enum ld_plugin_level
 {
   LDPL_INFO,
@@ -384,7 +404,9 @@ enum ld_plugin_tag
   LDPT_ALLOW_SECTION_ORDERING = 24,
   LDPT_GET_SYMBOLS_V2 = 25,
   LDPT_ALLOW_UNIQUE_SEGMENT_FOR_SECTIONS = 26,
-  LDPT_UNIQUE_SEGMENT_FOR_SECTIONS = 27
+  LDPT_UNIQUE_SEGMENT_FOR_SECTIONS = 27,
+  LDPT_GET_INPUT_SECTION_ALIGNMENT = 28,
+  LDPT_GET_INPUT_SECTION_SIZE = 29
 };

 /* The plugin transfer vector.  */
@@ -416,6 +438,8 @@ struct ld_plugin_tv
     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;
+    ld_plugin_get_input_section_alignment tv_get_input_section_alignment;
+    ld_plugin_get_input_section_size tv_get_input_section_size;
   } tv_u;
 };


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]