]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add binutils-sharable.patch
authorH.J. Lu <hjl.tools@gmail.com>
Mon, 4 Nov 2013 18:15:09 +0000 (10:15 -0800)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 6 Nov 2013 17:09:32 +0000 (09:09 -0800)
patches/README [new file with mode: 0644]
patches/binutils-sharable.patch [new file with mode: 0644]

diff --git a/patches/README b/patches/README
new file mode 100644 (file)
index 0000000..124532f
--- /dev/null
@@ -0,0 +1,32 @@
+#! /bin/sh
+
+# If you don't use rpm, you can use this file to apply additional Linux
+# patches. At the top level of the binutils source tree, do
+#
+# /bin/sh patches/README
+#
+# You may have to do
+#
+# cd bfd
+# make headers
+#
+# if the build fails.
+
+dir=`dirname $0`
+clean=$1
+
+patches="
+       binutils-sharable.patch
+"
+
+for p in $patches
+do
+  if [ ! -n "$clean" ]
+  then
+    suffix=$(echo $p | sed -e "s/.*-\([^-]\+\).patch/\1/")
+    backup="-b --suffix .$suffix"
+  fi
+  patch -E -p1 $backup < $dir/$p || exit 1
+done
+find -name "*.orig" | xargs rm -fv
+find -name "*.gmo" | xargs rm -fv
diff --git a/patches/binutils-sharable.patch b/patches/binutils-sharable.patch
new file mode 100644 (file)
index 0000000..49d4f60
--- /dev/null
@@ -0,0 +1,1285 @@
+From d982080fe4d81ee0a863a0258b317377260a3a8f Mon Sep 17 00:00:00 2001
+From: "H.J. Lu" <hjl.tools@gmail.com>
+Date: Mon, 4 Nov 2013 09:44:13 -0800
+Subject: [PATCH] Add PT_GNU_SHR/SHF_GNU_SHARABLE/SHN_GNU_SHARABLE_COMMON
+ support to gas/ld
+
+PT_GNU_SHR/SHF_GNU_SHARABLE/SHN_GNU_SHARABLE_COMMON are used to group
+data into a PT_GNU_SHR to improve performance on NUMA system.
+---
+ ChangeLog.sharable            | 140 ++++++++++++++++++++++++++
+ bfd/elf-bfd.h                 |  21 +++-
+ bfd/elf.c                     | 103 +++++++++++++++++++
+ bfd/elf32-i386.c              |  55 ++++++++--
+ bfd/elf64-x86-64.c            |  73 +++++++++++---
+ bfd/elflink.c                 | 228 +++++++++++++++++++++++++++++++++++++++++-
+ bfd/elfnn-ia64.c              |  16 ++-
+ binutils/readelf.c            |   5 +
+ gas/config/obj-elf.c          |  42 ++++++++
+ include/bfdlink.h             |   3 +
+ include/elf/common.h          |   6 ++
+ ld/emulparams/elf32_x86_64.sh |   1 +
+ ld/emulparams/elf64_ia64.sh   |   1 +
+ ld/emulparams/elf_i386.sh     |   1 +
+ ld/emulparams/elf_x86_64.sh   |   1 +
+ ld/emultempl/elf32.em         |   7 ++
+ ld/ldmain.c                   |   1 +
+ ld/scripttempl/elf.sc         |  35 +++++++
+ 18 files changed, 712 insertions(+), 27 deletions(-)
+ create mode 100644 ChangeLog.sharable
+
+diff --git a/ChangeLog.sharable b/ChangeLog.sharable
+new file mode 100644
+index 0000000..3ccf957
+--- /dev/null
++++ b/ChangeLog.sharable
+@@ -0,0 +1,140 @@
++bfd/
++
++2013-04-05  H.J. Lu  <hongjiu.lu@intel.com>
++
++      * elf-bfd.h (struct elf_backend_data <merge_symbol>):  Add abfd,
++      newdyn and olddyn.  Remove const from oldsec.
++      (_bfd_elf_sharable_merge_symbol): Updated.
++      * elf64-x86-64.c (elf_x86_64_merge_symbol): Likewise.
++      * elflink.c (_bfd_elf_merge_symbol): Update bed->merge_symbol
++      call.
++
++2009-12-12  H.J. Lu  <hongjiu.lu@intel.com>
++
++      * elf.c: Fix shadowed variable warnings.
++      * elf64-x86-64.c: Likewise.
++      * elflink.c: Likewise.
++
++2007-01-23  H.J. Lu  <hongjiu.lu@intel.com>
++
++      * elf-bfd.h (_bfd_elf_sharable_com_section): New.
++      (_bfd_elf_add_sharable_symbol): Likewise.
++      (_bfd_elf_sharable_section_from_bfd_section): Likewise.
++      (_bfd_elf_sharable_symbol_processing): Likewise.
++      (_bfd_elf_sharable_common_definition): Likewise.
++      (_bfd_elf_sharable_common_section_index): Likewise.
++      (_bfd_elf_sharable_common_section): Likewise.
++      (_bfd_elf_sharable_merge_symbol): Likewise.
++
++      * elf.c (special_sections_g): Add ".gnu.linkonce.shrb" and
++      ".gnu.linkonce.shrd".
++      (special_sections_s): Add ".sharable_bss" and ".sharable_data".
++      (get_program_header_size): Handle PT_GNU_SHR segment.
++      (_bfd_elf_map_sections_to_segments): Likewise.
++      (assign_file_positions_for_load_sections): Likewise.
++
++      * elf32-i386.c (elf_i386_link_hash_table): Add sdynsharablebss
++      and srelsharablebss fields.
++      (elf_i386_link_hash_table_create): Initialize sdynsharablebss
++      and srelsharablebss.
++      (elf_i386_create_dynamic_sections): Handle sdynsharablebss and
++      srelsharablebss.
++      (elf_i386_adjust_dynamic_symbol): Likewise.
++      (elf_i386_size_dynamic_sections): Likewise.
++      (elf_i386_finish_dynamic_symbol): Likewise.
++      (elf_backend_add_symbol_hook): Defined.
++      (elf_backend_section_from_bfd_section): Likewise.
++      (elf_backend_symbol_processing): Likewise.
++      (elf_backend_common_section_index): Likewise.
++      (elf_backend_common_section): Likewise.
++      (elf_backend_common_definition): Likewise.
++      (elf_backend_merge_symbol): Likewise.
++
++      * elf64-x86-64.c (elf64_x86_64_link_hash_table): Add
++      sdynsharablebss and srelsharablebss fields.
++      (elf64_x86_64_link_hash_table_create): Initialize sdynsharablebss
++      and srelsharablebss.
++      (elf64_x86_64_create_dynamic_sections): Handle sdynsharablebss
++      and srelsharablebss.
++      (elf64_x86_64_adjust_dynamic_symbol): Likewise.
++      (elf64_x86_64_size_dynamic_sections): Likewise.
++      (elf64_x86_64_finish_dynamic_symbol): Likewise.
++      (elf64_x86_64_add_symbol_hook): Handle sharable symbols.
++      (elf64_x86_64_elf_section_from_bfd_section): Likewise.
++      (elf64_x86_64_symbol_processing): Likewise.
++      (elf64_x86_64_merge_symbol): Likewise.
++      (elf64_x86_64_common_definition): Handle sharable sections.
++      (elf64_x86_64_common_section_index): Likewise.
++      (elf64_x86_64_common_section): Likewise.
++
++      * elflink.c (_bfd_elf_create_dynamic_sections): Handle
++      .dynsharablebss section.
++      (_bfd_elf_sharable_com_section): New.
++      (get_sharable_common_section): Likewise.
++      (_bfd_elf_add_sharable_symbol): Likewise.
++      (_bfd_elf_sharable_section_from_bfd_section): Likewise.
++      (_bfd_elf_sharable_symbol_processing): Likewise.
++      (_bfd_elf_sharable_common_definition): Likewise.
++      (_bfd_elf_sharable_common_section_index): Likewise.
++      (_bfd_elf_sharable_common_section): Likewise.
++      (_bfd_elf_sharable_merge_symbol): Likewise.
++
++      * elfnn-ia64.c (elfNN_ia64_add_symbol_hook): Handle sharable
++      symbols.
++      (elf_backend_add_symbol_hook): Defined.
++      (elf_backend_section_from_bfd_section): Likewise.
++      (elf_backend_symbol_processing): Likewise.
++      (elf_backend_common_section_index): Likewise.
++      (elf_backend_common_section): Likewise.
++      (elf_backend_common_definition): Likewise.
++      (elf_backend_merge_symbol): Likewise.
++
++binutils/
++
++2007-01-04  H.J. Lu  <hongjiu.lu@intel.com>
++
++      * readelf.c (dump_relocations): Handle sharable sections.
++      (get_segment_type): Handle sharable segment.
++      (get_symbol_index_type): Handle sharable sections.
++
++gas/
++
++2007-01-04  H.J. Lu  <hongjiu.lu@intel.com>
++
++      * config/obj-elf.c (obj_elf_sharable_common): New.
++      (elf_pseudo_table): Add "sharable_common".
++      (obj_elf_change_section): Handle sharable sections.
++
++include/
++
++2007-01-23  H.J. Lu  <hongjiu.lu@intel.com>
++
++      * bfdlink.h (bfd_link_info): Add sharable_sections.
++
++include/elf/
++
++2007-01-04  H.J. Lu  <hongjiu.lu@intel.com>
++
++      * common.h (PT_GNU_SHR): New.
++      (SHF_GNU_SHARABLE): Likewise.
++      (SHN_GNU_SHARABLE_COMMON): Likewise.
++
++ld/
++
++2011-01-08  H.J. Lu  <hongjiu.lu@intel.com>
++
++      * emulparams/elf32_x86_64.sh (SHARABLE_SECTIONS): Set to yes.
++
++2007-01-04  H.J. Lu  <hongjiu.lu@intel.com>
++
++      * emulparams/elf64_ia64.sh (SHARABLE_SECTIONS): Set to yes.
++      * emulparams/elf_i386.sh (SHARABLE_SECTIONS): Likewise.
++      * emulparams/elf_x86_64.sh (SHARABLE_SECTIONS): Likewise.
++
++      * emultempl/elf32.em (gld${EMULATION_NAME}_before_parse): Set
++      link_info.sharable_sections based on $SHARABLE_SECTIONS.
++      (gld${EMULATION_NAME}_place_orphan): Don't allow orphaned
++      sharable sections.
++
++      * ldmain.c (main): Initialize link_info.sharable_sections.
++      * scripttempl/elf.sc: Support sharable sections.
+diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
+index add80b3..525d4b9 100644
+--- a/bfd/elf-bfd.h
++++ b/bfd/elf-bfd.h
+@@ -1210,8 +1210,9 @@ struct elf_backend_data
+   /* Return TRUE if we can merge 2 definitions.  */
+   bfd_boolean (*merge_symbol) (struct elf_link_hash_entry *,
+                              const Elf_Internal_Sym *, asection **,
++                             bfd_boolean, bfd_boolean, bfd *,
+                              bfd_boolean, bfd_boolean,
+-                             bfd *, const asection *);
++                             bfd *, asection *);
+   /* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
+   bfd_boolean (*elf_hash_symbol) (struct elf_link_hash_entry *);
+@@ -2148,6 +2149,24 @@ extern bfd_boolean bfd_elf_link_add_symbols
+   (bfd *, struct bfd_link_info *);
+ extern bfd_boolean _bfd_elf_add_dynamic_entry
+   (struct bfd_link_info *, bfd_vma, bfd_vma);
++extern asection _bfd_elf_sharable_com_section;
++extern bfd_boolean _bfd_elf_add_sharable_symbol
++  (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **,
++   flagword *, asection **, bfd_vma *);
++extern bfd_boolean _bfd_elf_sharable_section_from_bfd_section
++  (bfd *, asection *, int *);
++extern void _bfd_elf_sharable_symbol_processing
++  (bfd *, asymbol *);
++extern bfd_boolean _bfd_elf_sharable_common_definition
++  (Elf_Internal_Sym *);
++extern unsigned int _bfd_elf_sharable_common_section_index
++  (asection *);
++extern asection *_bfd_elf_sharable_common_section
++  (asection *);
++extern bfd_boolean _bfd_elf_sharable_merge_symbol
++  (struct elf_link_hash_entry *, const Elf_Internal_Sym *,
++   asection **, bfd_boolean, bfd_boolean, bfd *,
++   bfd_boolean, bfd_boolean, bfd *, asection *);
+ extern bfd_boolean bfd_elf_link_record_dynamic_symbol
+   (struct bfd_link_info *, struct elf_link_hash_entry *);
+diff --git a/bfd/elf.c b/bfd/elf.c
+index 8df38ee..88c182e 100644
+--- a/bfd/elf.c
++++ b/bfd/elf.c
+@@ -2102,6 +2102,8 @@ static const struct bfd_elf_special_section special_sections_g[] =
+   { STRING_COMMA_LEN (".gnu.liblist"),     0, SHT_GNU_LIBLIST, SHF_ALLOC },
+   { STRING_COMMA_LEN (".gnu.conflict"),    0, SHT_RELA,        SHF_ALLOC },
+   { STRING_COMMA_LEN (".gnu.hash"),        0, SHT_GNU_HASH,    SHF_ALLOC },
++  { STRING_COMMA_LEN (".gnu.linkonce.shrb"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_GNU_SHARABLE},
++  { STRING_COMMA_LEN (".gnu.linkonce.shrd"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_GNU_SHARABLE},
+   { NULL,                        0,        0, 0,               0 }
+ };
+@@ -2156,6 +2158,8 @@ static const struct bfd_elf_special_section special_sections_s[] =
+   /* See struct bfd_elf_special_section declaration for the semantics of
+      this special case where .prefix_length != strlen (.prefix).  */
+   { ".stabstr",                       5,  3, SHT_STRTAB, 0 },
++  { STRING_COMMA_LEN (".sharable_bss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_GNU_SHARABLE},
++  { STRING_COMMA_LEN (".sharable_data"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_GNU_SHARABLE},
+   { NULL,                       0,  0, 0,          0 }
+ };
+@@ -3615,6 +3619,32 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
+       }
+     }
++  /* Check to see if we need a PT_GNU_SHR segment for sharable data
++     sections.  */
++  for (s = abfd->sections; s != NULL; s = s->next)
++    {
++      if ((elf_section_flags (s) & SHF_GNU_SHARABLE) != 0
++        && elf_section_type (s) == SHT_PROGBITS)
++      {
++        /* We need a PT_GNU_SHR segment.  */
++        ++segs;
++        break;
++      }
++    }
++
++  /* Check to see if we need a PT_GNU_SHR segment for sharable bss
++     sections.  */
++  for (s = abfd->sections; s != NULL; s = s->next)
++    {
++      if ((elf_section_flags (s) & SHF_GNU_SHARABLE) != 0
++        && elf_section_type (s) == SHT_NOBITS)
++      {
++        /* We need a PT_GNU_SHR segment.  */
++        ++segs;
++        break;
++      }
++    }
++
+   /* Let the backend count up any program headers it might need.  */
+   bed = get_elf_backend_data (abfd);
+   if (bed->elf_backend_additional_program_headers)
+@@ -3785,6 +3815,8 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
+       bfd_boolean phdr_in_segment = TRUE;
+       bfd_boolean writable;
+       int tls_count = 0;
++      int sharable_data_count = 0, sharable_bss_count = 0;
++      asection *first_sharable_data = NULL, *first_sharable_bss = NULL;
+       asection *first_tls = NULL;
+       asection *dynsec, *eh_frame_hdr;
+       bfd_size_type amt;
+@@ -4093,6 +4125,22 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
+               first_tls = s;
+             tls_count++;
+           }
++        if (elf_section_flags (s) & SHF_GNU_SHARABLE)
++          {
++            if (elf_section_type (s) == SHT_PROGBITS)
++              {
++                if (! sharable_data_count)
++                  first_sharable_data = s;
++                sharable_data_count++;
++              }
++            else
++              {
++                BFD_ASSERT (elf_section_type (s) == SHT_NOBITS);
++                if (! sharable_bss_count)
++                  first_sharable_bss = s;
++                sharable_bss_count++;
++              }
++          }
+       }
+       /* If there are any SHF_TLS output sections, add PT_TLS segment.  */
+@@ -4120,6 +4168,60 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
+         pm = &m->next;
+       }
++      /* If there are any output SHF_GNU_SHARABLE data sections, add a
++       PT_GNU_SHR segment.  */
++      if (sharable_data_count > 0)
++      {
++        int j;
++
++        amt = sizeof (struct elf_segment_map);
++        amt += (sharable_data_count - 1) * sizeof (asection *);
++        m = bfd_zalloc (abfd, amt);
++        if (m == NULL)
++          goto error_return;
++        m->next = NULL;
++        m->p_type = PT_GNU_SHR;
++        m->count = sharable_data_count;
++        /* Mandated PF_R.  */
++        m->p_flags = PF_R;
++        m->p_flags_valid = 1;
++        for (j = 0; j < sharable_data_count; ++j)
++          {
++            m->sections[j] = first_sharable_data;
++            first_sharable_data = first_sharable_data->next;
++          }
++
++        *pm = m;
++         pm = &m->next;
++      }
++
++      /* If there are any output SHF_GNU_SHARABLE bss sections, add a
++       PT_GNU_SHR segment.  */
++      if (sharable_bss_count > 0)
++      {
++        int j;
++
++        amt = sizeof (struct elf_segment_map);
++        amt += (sharable_bss_count - 1) * sizeof (asection *);
++        m = bfd_zalloc (abfd, amt);
++        if (m == NULL)
++          goto error_return;
++        m->next = NULL;
++        m->p_type = PT_GNU_SHR;
++        m->count = sharable_bss_count;
++        /* Mandated PF_R.  */
++        m->p_flags = PF_R;
++        m->p_flags_valid = 1;
++        for (j = 0; j < sharable_bss_count; ++j)
++          {
++            m->sections[j] = first_sharable_bss;
++            first_sharable_bss = first_sharable_bss->next;
++          }
++
++        *pm = m;
++         pm = &m->next;
++      }
++
+       /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
+        segment.  */
+       eh_frame_hdr = elf_eh_frame_hdr (abfd);
+@@ -4661,6 +4763,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
+         align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec);
+         if ((p->p_type == PT_LOAD
++             || p->p_type == PT_GNU_SHR
+              || p->p_type == PT_TLS)
+             && (this_hdr->sh_type != SHT_NOBITS
+                 || ((this_hdr->sh_flags & SHF_ALLOC) != 0
+diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
+index 560e05c..bd5a1d2 100644
+--- a/bfd/elf32-i386.c
++++ b/bfd/elf32-i386.c
+@@ -819,6 +819,9 @@ struct elf_i386_link_hash_table
+   /* The index of the next unused R_386_IRELATIVE slot in .rel.plt.  */
+   bfd_vma next_irelative_index;
++
++  asection *sdynsharablebss;
++  asection *srelsharablebss;
+ };
+ /* Get the i386 ELF linker hash table from a link_info structure.  */
+@@ -997,10 +1000,19 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
+   htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
+   if (!info->shared)
+-    htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss");
++    {
++      htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss");
++      htab->sdynsharablebss
++      = bfd_get_linker_section (dynobj, ".dynsharablebss");
++      htab->srelsharablebss
++      = bfd_get_linker_section (dynobj, ".rel.sharable_bss");
++    }
+   if (!htab->sdynbss
+-      || (!info->shared && !htab->srelbss))
++      || (!info->shared
++        && (!htab->srelbss
++            || !htab->sdynsharablebss
++            || !htab->srelsharablebss)))
+     abort ();
+   if (get_elf_i386_backend_data (dynobj)->is_vxworks
+@@ -2154,17 +2166,23 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
+      both the dynamic object and the regular object will refer to the
+      same memory location for the variable.  */
++  s = htab->sdynbss;
++
+   /* We must generate a R_386_COPY reloc to tell the dynamic linker to
+      copy the initial value out of the dynamic object and into the
+      runtime process image.  */
+   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
+     {
+-      htab->srelbss->size += sizeof (Elf32_External_Rel);
++      if (elf_section_flags (h->root.u.def.section) & SHF_GNU_SHARABLE)
++      {
++        htab->srelsharablebss->size += sizeof (Elf32_External_Rel);
++        s = htab->sdynsharablebss;
++      }
++      else
++      htab->srelbss->size += sizeof (Elf32_External_Rel);
+       h->needs_copy = 1;
+     }
+-  s = htab->sdynbss;
+-
+   return _bfd_elf_adjust_dynamic_copy (h, s);
+ }
+@@ -2886,6 +2904,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
+              || s == htab->elf.iplt
+              || s == htab->elf.igotplt
+              || s == htab->plt_eh_frame
++             || s == htab->sdynsharablebss
+              || s == htab->sdynbss)
+       {
+         /* Strip these too.  */
+@@ -4682,20 +4701,26 @@ do_glob_dat:
+   if (h->needs_copy)
+     {
+       Elf_Internal_Rela rel;
++      asection *s;
++
++      if (h->root.u.def.section == htab->sdynsharablebss)
++      s = htab->srelsharablebss;
++      else
++      s = htab->srelbss;
+       /* This symbol needs a copy reloc.  Set it up.  */
+       if (h->dynindx == -1
+         || (h->root.type != bfd_link_hash_defined
+             && h->root.type != bfd_link_hash_defweak)
+-        || htab->srelbss == NULL)
++        || s == NULL)
+       abort ();
+       rel.r_offset = (h->root.u.def.value
+                     + h->root.u.def.section->output_section->vma
+                     + h->root.u.def.section->output_offset);
+       rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY);
+-      elf_append_rel (output_bfd, htab->srelbss, &rel);
++      elf_append_rel (output_bfd, s, &rel);
+     }
+   return TRUE;
+@@ -5016,7 +5041,8 @@ elf_i386_add_symbol_hook (bfd * abfd,
+         || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+     elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+-  return TRUE;
++  return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
++                                     secp, valp);
+ }
+ #define TARGET_LITTLE_SYM             bfd_elf32_i386_vec
+@@ -5070,6 +5096,19 @@ elf_i386_add_symbol_hook (bfd * abfd,
+ #undef        elf_backend_post_process_headers
+ #define       elf_backend_post_process_headers        _bfd_elf_set_osabi
++#define elf_backend_section_from_bfd_section \
++  _bfd_elf_sharable_section_from_bfd_section
++#define elf_backend_symbol_processing \
++  _bfd_elf_sharable_symbol_processing
++#define elf_backend_common_section_index \
++  _bfd_elf_sharable_common_section_index
++#define elf_backend_common_section \
++  _bfd_elf_sharable_common_section
++#define elf_backend_common_definition \
++  _bfd_elf_sharable_common_definition
++#define elf_backend_merge_symbol \
++  _bfd_elf_sharable_merge_symbol
++
+ #include "elf32-target.h"
+ /* FreeBSD support.  */
+diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
+index f748641..bc5b578 100644
+--- a/bfd/elf64-x86-64.c
++++ b/bfd/elf64-x86-64.c
+@@ -771,6 +771,9 @@ struct elf_x86_64_link_hash_table
+   bfd_vma next_jump_slot_index;
+   /* The index of the next R_X86_64_IRELATIVE entry in .rela.plt.  */
+   bfd_vma next_irelative_index;
++
++  asection *sdynsharablebss;
++  asection *srelsharablebss;
+ };
+ /* Get the x86-64 ELF linker hash table from a link_info structure.  */
+@@ -968,10 +971,19 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj,
+   htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
+   if (!info->shared)
+-    htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss");
++    {
++      htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss");
++      htab->sdynsharablebss
++      = bfd_get_linker_section (dynobj, ".dynsharablebss");
++      htab->srelsharablebss
++      = bfd_get_linker_section (dynobj, ".rela.sharable_bss");
++    }
+   if (!htab->sdynbss
+-      || (!info->shared && !htab->srelbss))
++      || (!info->shared
++        && (!htab->srelbss
++            || !htab->sdynsharablebss
++            || !htab->srelsharablebss)))
+     abort ();
+   if (!info->no_ld_generated_unwind_info
+@@ -2248,6 +2260,8 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
+   if (htab == NULL)
+     return FALSE;
++  s = htab->sdynbss;
++
+   /* We must generate a R_X86_64_COPY reloc to tell the dynamic linker
+      to copy the initial value out of the dynamic object and into the
+      runtime process image.  */
+@@ -2255,12 +2269,16 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
+     {
+       const struct elf_backend_data *bed;
+       bed = get_elf_backend_data (info->output_bfd);
+-      htab->srelbss->size += bed->s->sizeof_rela;
++      if (elf_section_flags (h->root.u.def.section) & SHF_GNU_SHARABLE)
++      {
++        htab->srelsharablebss->size += bed->s->sizeof_rela;
++        s = htab->sdynsharablebss;
++      }
++      else
++      htab->srelbss->size += bed->s->sizeof_rela;
+       h->needs_copy = 1;
+     }
+-  s = htab->sdynbss;
+-
+   return _bfd_elf_adjust_dynamic_copy (h, s);
+ }
+@@ -2960,6 +2978,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
+         || s == htab->elf.iplt
+         || s == htab->elf.igotplt
+         || s == htab->plt_eh_frame
++        || s == htab->sdynsharablebss
+         || s == htab->sdynbss)
+       {
+         /* Strip this section if we don't need it; see the
+@@ -4720,13 +4739,19 @@ do_glob_dat:
+   if (h->needs_copy)
+     {
+       Elf_Internal_Rela rela;
++      asection *s;
++
++      if (h->root.u.def.section == htab->sdynsharablebss)
++      s = htab->srelsharablebss;
++      else
++      s = htab->srelbss;
+       /* This symbol needs a copy reloc.  Set it up.  */
+       if (h->dynindx == -1
+         || (h->root.type != bfd_link_hash_defined
+             && h->root.type != bfd_link_hash_defweak)
+-        || htab->srelbss == NULL)
++        || s == NULL)
+       abort ();
+       rela.r_offset = (h->root.u.def.value
+@@ -4734,7 +4759,7 @@ do_glob_dat:
+                      + h->root.u.def.section->output_offset);
+       rela.r_info = htab->r_info (h->dynindx, R_X86_64_COPY);
+       rela.r_addend = 0;
+-      elf_append_rela (output_bfd, htab->srelbss, &rela);
++      elf_append_rela (output_bfd, s, &rela);
+     }
+   return TRUE;
+@@ -5069,7 +5094,8 @@ elf_x86_64_add_symbol_hook (bfd *abfd,
+         || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+     elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+-  return TRUE;
++  return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
++                                     secp, valp);
+ }
+@@ -5085,7 +5111,8 @@ elf_x86_64_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
+       *index_return = SHN_X86_64_LCOMMON;
+       return TRUE;
+     }
+-  return FALSE;
++  return _bfd_elf_sharable_section_from_bfd_section (abfd, sec,
++                                                   index_return);
+ }
+ /* Process a symbol.  */
+@@ -5103,22 +5130,26 @@ elf_x86_64_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
+       asym->value = elfsym->internal_elf_sym.st_size;
+       /* Common symbol doesn't set BSF_GLOBAL.  */
+       asym->flags &= ~BSF_GLOBAL;
++      return;
+       break;
+     }
++
++  _bfd_elf_sharable_symbol_processing (abfd, asym);
+ }
+ static bfd_boolean
+ elf_x86_64_common_definition (Elf_Internal_Sym *sym)
+ {
+   return (sym->st_shndx == SHN_COMMON
+-        || sym->st_shndx == SHN_X86_64_LCOMMON);
++        || sym->st_shndx == SHN_X86_64_LCOMMON
++        || _bfd_elf_sharable_common_definition (sym));
+ }
+ static unsigned int
+ elf_x86_64_common_section_index (asection *sec)
+ {
+   if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0)
+-    return SHN_COMMON;
++    return _bfd_elf_sharable_common_section_index (sec);
+   else
+     return SHN_X86_64_LCOMMON;
+ }
+@@ -5127,7 +5158,7 @@ static asection *
+ elf_x86_64_common_section (asection *sec)
+ {
+   if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0)
+-    return bfd_com_section_ptr;
++    return _bfd_elf_sharable_common_section (sec);
+   else
+     return &_bfd_elf_large_com_section;
+ }
+@@ -5137,9 +5168,12 @@ elf_x86_64_merge_symbol (struct elf_link_hash_entry *h,
+                        const Elf_Internal_Sym *sym,
+                        asection **psec,
+                        bfd_boolean newdef,
++                       bfd_boolean newdyn,
++                       bfd *abfd,
+                        bfd_boolean olddef,
++                       bfd_boolean olddyn,
+                        bfd *oldbfd,
+-                       const asection *oldsec)
++                       asection *oldsec)
+ {
+   /* A normal common symbol and a large common symbol result in a
+      normal common symbol.  We turn the large common symbol into a
+@@ -5148,7 +5182,8 @@ elf_x86_64_merge_symbol (struct elf_link_hash_entry *h,
+       && h->root.type == bfd_link_hash_common
+       && !newdef
+       && bfd_is_com_section (*psec)
+-      && oldsec != *psec)
++      && oldsec != *psec
++      && _bfd_elf_sharable_common_section_index (oldsec) == SHN_COMMON)
+     {
+       if (sym->st_shndx == SHN_COMMON
+         && (elf_section_flags (oldsec) & SHF_X86_64_LARGE) != 0)
+@@ -5156,13 +5191,19 @@ elf_x86_64_merge_symbol (struct elf_link_hash_entry *h,
+         h->root.u.c.p->section
+           = bfd_make_section_old_way (oldbfd, "COMMON");
+         h->root.u.c.p->section->flags = SEC_ALLOC;
++        return TRUE;
+       }
+       else if (sym->st_shndx == SHN_X86_64_LCOMMON
+              && (elf_section_flags (oldsec) & SHF_X86_64_LARGE) == 0)
+-      *psec = bfd_com_section_ptr;
++      {
++        *psec = bfd_com_section_ptr;
++        return TRUE;
++      }
+     }
+-  return TRUE;
++  return _bfd_elf_sharable_merge_symbol (h, sym, psec, newdef, newdyn,
++                                       abfd, olddef, olddyn, oldbfd,
++                                       oldsec);
+ }
+ static int
+diff --git a/bfd/elflink.c b/bfd/elflink.c
+index 1e6abd9..e187d91 100644
+--- a/bfd/elflink.c
++++ b/bfd/elflink.c
+@@ -385,6 +385,27 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
+         if (s == NULL
+             || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+           return FALSE;
++
++        if (info->sharable_sections)
++          {
++            s = bfd_make_section (abfd, ".dynsharablebss");
++            if (s == NULL
++                || ! bfd_set_section_flags (abfd, s,
++                                            (SEC_ALLOC
++                                             | SEC_LINKER_CREATED)))
++              return FALSE;
++
++            s = bfd_make_section (abfd,
++                                  (bed->default_use_rela_p
++                                   ? ".rela.sharable_bss"
++                                   : ".rel.sharable_bss"));
++            if (s == NULL
++                || ! bfd_set_section_flags (abfd, s,
++                                            flags | SEC_READONLY)
++                || ! bfd_set_section_alignment (abfd, s,
++                                                bed->s->log_file_align))
++              return FALSE;
++          }
+       }
+     }
+@@ -1347,7 +1368,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
+      backend to check if we can merge them.  */
+   if (bed->merge_symbol != NULL)
+     {
+-      if (!bed->merge_symbol (h, sym, psec, newdef, olddef, oldbfd, oldsec))
++      if (!bed->merge_symbol (h, sym, psec, newdef, newdyn, abfd,
++                            olddef, olddyn, oldbfd, oldsec))
+       return FALSE;
+       sec = *psec;
+     }
+@@ -13047,3 +13069,207 @@ elf_append_rel (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
+   BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size);
+   bed->s->swap_reloc_out (abfd, rel, loc);
+ }
++
++asection _bfd_elf_sharable_com_section
++  = BFD_FAKE_SECTION (_bfd_elf_sharable_com_section, SEC_IS_COMMON,
++                    NULL, "SHARABLE_COMMON", 0);
++ 
++static asection *
++get_sharable_common_section (bfd *abfd)
++{
++  asection *scomm = bfd_get_section_by_name (abfd, "SHARABLE_COMMON");
++
++  if (scomm == NULL)
++    {
++      scomm = bfd_make_section_with_flags (abfd,
++                                         "SHARABLE_COMMON",
++                                         (SEC_ALLOC
++                                          | SEC_IS_COMMON
++                                          | SEC_LINKER_CREATED));
++      if (scomm == NULL)
++      return scomm;
++      elf_section_flags (scomm) |= SHF_GNU_SHARABLE;
++    }
++
++  return scomm;
++}
++
++bfd_boolean
++_bfd_elf_add_sharable_symbol (bfd *abfd ATTRIBUTE_UNUSED,
++                            struct bfd_link_info *info ATTRIBUTE_UNUSED,
++                            Elf_Internal_Sym *sym,
++                            const char **namep ATTRIBUTE_UNUSED,
++                            flagword *flagsp ATTRIBUTE_UNUSED,
++                            asection **secp,
++                            bfd_vma *valp)
++{
++  asection *scomm;
++
++  switch (sym->st_shndx)
++    {
++    case SHN_GNU_SHARABLE_COMMON:
++      scomm = get_sharable_common_section (abfd);
++      if (scomm == NULL)
++      return FALSE;
++      *secp = scomm;
++      *valp = sym->st_size;
++      break;
++    }
++  return TRUE;
++}
++
++bfd_boolean
++_bfd_elf_sharable_section_from_bfd_section
++  (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, int *index_return)
++{
++  if (sec == &_bfd_elf_sharable_com_section)
++    {
++      *index_return = SHN_GNU_SHARABLE_COMMON;
++      return TRUE;
++    }
++  return FALSE;
++}
++
++void
++_bfd_elf_sharable_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
++                                   asymbol *asym)
++{
++  elf_symbol_type *elfsym = (elf_symbol_type *) asym;
++
++  switch (elfsym->internal_elf_sym.st_shndx)
++    {
++    case SHN_GNU_SHARABLE_COMMON:
++      asym->section = &_bfd_elf_sharable_com_section;
++      asym->value = elfsym->internal_elf_sym.st_size;
++      asym->flags &= ~BSF_GLOBAL;
++      break;
++    }
++}
++
++bfd_boolean
++_bfd_elf_sharable_common_definition (Elf_Internal_Sym *sym)
++{
++  return (sym->st_shndx == SHN_COMMON
++        || sym->st_shndx == SHN_GNU_SHARABLE_COMMON);
++}
++
++unsigned int
++_bfd_elf_sharable_common_section_index (asection *sec)
++{
++  if ((elf_section_flags (sec) & SHF_GNU_SHARABLE) == 0)
++    return SHN_COMMON;
++  else
++    return SHN_GNU_SHARABLE_COMMON;
++}
++
++asection *
++_bfd_elf_sharable_common_section (asection *sec)
++{
++  if ((elf_section_flags (sec) & SHF_GNU_SHARABLE) == 0)
++    return bfd_com_section_ptr;
++  else
++    return &_bfd_elf_sharable_com_section;
++}
++
++bfd_boolean
++_bfd_elf_sharable_merge_symbol (struct elf_link_hash_entry *h,
++                              const Elf_Internal_Sym *sym,
++                              asection **psec,
++                              bfd_boolean newdef,
++                              bfd_boolean newdyn,
++                              bfd *abfd,
++                              bfd_boolean olddef,
++                              bfd_boolean olddyn,
++                              bfd *oldbfd,
++                              asection *oldsec)
++{
++  asection *sec = *psec;
++
++  /* Check sharable symbol.  If one is undefined, it is OK.  */
++  if (oldsec && !bfd_is_und_section (sec))
++    {
++      bfd_boolean sharable, oldsharable;
++     
++      sharable = (elf_section_data (sec)
++                && (elf_section_flags (sec) & SHF_GNU_SHARABLE));
++      oldsharable = (elf_section_data (oldsec)
++                   && (elf_section_flags (oldsec)
++                       & SHF_GNU_SHARABLE));
++
++      if (sharable != oldsharable)
++      {
++        bfd *nsbfd, *sbfd;
++        asection *nssec, *ssec;
++        bfd_boolean nsdyn, sdyn, nsdef, sdef;
++
++        if (oldsharable)
++          {
++            sbfd = oldbfd;
++            nsbfd = abfd;
++            ssec = oldsec;
++            nssec = sec;
++            sdyn = olddyn;
++            nsdyn = newdyn;
++            sdef = olddef;
++            nsdef = newdef;
++          }
++        else
++          {
++            sbfd = abfd;
++            nsbfd = oldbfd;
++            ssec = sec;
++            nssec = oldsec;
++            sdyn = newdyn;
++            nsdyn = olddyn;
++            sdef = newdef;
++            nsdef = olddef;
++          }
++
++        if (sdef && !sdyn)
++          {
++            /* If the sharable definition comes from a relocatable
++               file, it will override the non-sharable one in DSO. */
++            return TRUE;
++          }
++        else if (!nsdef
++                 && !nsdyn
++                 && (h->root.type == bfd_link_hash_common
++                     || bfd_is_com_section (nssec)))
++          {
++            asection *scomm;
++
++            /* When the non-sharable common symbol in a relocatable
++               file, we can turn it into sharable.  If the sharable
++               symbol isn't common, the non-sharable common symbol
++               will be overidden.  We only need to handle the
++               sharable common symbol and the non-sharable common
++               symbol.  We just turn the non-sharable common symbol
++               into the sharable one. */
++            if (sym->st_shndx == SHN_GNU_SHARABLE_COMMON)
++              {
++                scomm = get_sharable_common_section (oldbfd);
++                if (scomm == NULL)
++                  return FALSE;
++                h->root.u.c.p->section = scomm;
++              }
++            else
++              {
++                scomm = get_sharable_common_section (abfd);
++                if (scomm == NULL)
++                  return FALSE;
++                *psec = scomm;
++              }
++
++            return TRUE;
++          }
++
++        (*_bfd_error_handler)
++          (_("%s: sharable symbol in %B section %A mismatches non-shrable symbol in %B section %A"),
++           sbfd, ssec, nsbfd, nssec, h->root.root.string);
++        bfd_set_error (bfd_error_bad_value);
++        return FALSE;
++      }
++    }
++
++  return TRUE;
++}
+diff --git a/bfd/elfnn-ia64.c b/bfd/elfnn-ia64.c
+index 117b4c8..33c7ee4 100644
+--- a/bfd/elfnn-ia64.c
++++ b/bfd/elfnn-ia64.c
+@@ -1055,7 +1055,8 @@ elfNN_ia64_add_symbol_hook (bfd *abfd,
+       *valp = sym->st_size;
+     }
+-  return TRUE;
++  return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
++                                     secp, valp);
+ }
+ /* Return the number of additional phdrs we will need.  */
+@@ -5069,6 +5070,19 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
+ #define elf_backend_special_sections  elfNN_ia64_special_sections
+ #define elf_backend_default_execstack 0
++#define elf_backend_section_from_bfd_section \
++  _bfd_elf_sharable_section_from_bfd_section
++#define elf_backend_symbol_processing \
++  _bfd_elf_sharable_symbol_processing
++#define elf_backend_common_section_index \
++  _bfd_elf_sharable_common_section_index
++#define elf_backend_common_section \
++  _bfd_elf_sharable_common_section
++#define elf_backend_common_definition \
++  _bfd_elf_sharable_common_definition
++#define elf_backend_merge_symbol \
++  _bfd_elf_sharable_merge_symbol
++
+ /* FIXME: PR 290: The Intel C compiler generates SHT_IA_64_UNWIND with
+    SHF_LINK_ORDER. But it doesn't set the sh_link or sh_info fields.
+    We don't want to flood users with so many error messages. We turn
+diff --git a/binutils/readelf.c b/binutils/readelf.c
+index 0389f14..cdc18ba 100644
+--- a/binutils/readelf.c
++++ b/binutils/readelf.c
+@@ -1406,6 +1406,8 @@ dump_relocations (FILE * file,
+                       sec_name = "ABS";
+                     else if (psym->st_shndx == SHN_COMMON)
+                       sec_name = "COMMON";
++                    else if (psym->st_shndx == SHN_GNU_SHARABLE_COMMON)
++                      sec_name = "GNU_SHARABLE_COMMON";
+                     else if ((elf_header.e_machine == EM_MIPS
+                               && psym->st_shndx == SHN_MIPS_SCOMMON)
+                              || (elf_header.e_machine == EM_TI_C6000
+@@ -3035,6 +3037,7 @@ get_segment_type (unsigned long p_type)
+     case PT_SHLIB:    return "SHLIB";
+     case PT_PHDR:     return "PHDR";
+     case PT_TLS:      return "TLS";
++    case PT_GNU_SHR:  return "GNU_SHR";
+     case PT_GNU_EH_FRAME:
+                       return "GNU_EH_FRAME";
+@@ -9264,6 +9267,8 @@ get_symbol_index_type (unsigned int type)
+     case SHN_UNDEF:   return "UND";
+     case SHN_ABS:     return "ABS";
+     case SHN_COMMON:  return "COM";
++    case SHN_GNU_SHARABLE_COMMON:
++                      return "GNU_SHARABLE_COM";
+     default:
+       if (type == SHN_IA_64_ANSI_COMMON
+         && elf_header.e_machine == EM_IA_64
+diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
+index 3377261..286df1f 100644
+--- a/gas/config/obj-elf.c
++++ b/gas/config/obj-elf.c
+@@ -78,6 +78,7 @@ static void obj_elf_subsection (int);
+ static void obj_elf_popsection (int);
+ static void obj_elf_gnu_attribute (int);
+ static void obj_elf_tls_common (int);
++static void obj_elf_sharable_common (int);
+ static void obj_elf_lcomm (int);
+ static void obj_elf_struct (int);
+@@ -138,6 +139,8 @@ static const pseudo_typeS elf_pseudo_table[] =
+   {"tls_common", obj_elf_tls_common, 0},
++  {"sharable_common", obj_elf_sharable_common, 0},
++
+   /* End sentinel.  */
+   {NULL, NULL, 0},
+ };
+@@ -393,6 +396,39 @@ obj_elf_tls_common (int ignore ATTRIBUTE_UNUSED)
+ }
+ static void
++obj_elf_sharable_common (int ignore ATTRIBUTE_UNUSED)
++{
++  static segT sharable_bss_section;
++  asection *saved_com_section_ptr = elf_com_section_ptr;
++  asection *saved_bss_section = bss_section;
++
++  if (sharable_bss_section == NULL)
++    {
++      flagword applicable;
++      segT seg = now_seg;
++      subsegT subseg = now_subseg;
++
++      /* The .sharable_bss section is for local .sharable_common
++       symbols.  */
++      sharable_bss_section = subseg_new (".sharable_bss", 0);
++      applicable = bfd_applicable_section_flags (stdoutput);
++      bfd_set_section_flags (stdoutput, sharable_bss_section,
++                           applicable & SEC_ALLOC);
++      seg_info (sharable_bss_section)->bss = 1;
++
++      subseg_set (seg, subseg);
++    }
++
++  elf_com_section_ptr = &_bfd_elf_sharable_com_section;
++  bss_section = sharable_bss_section;
++
++  s_comm_internal (0, elf_common_parse);
++
++  elf_com_section_ptr = saved_com_section_ptr;
++  bss_section = saved_bss_section;
++}
++
++static void
+ obj_elf_lcomm (int ignore ATTRIBUTE_UNUSED)
+ {
+   symbolS *symbolP = s_comm_internal (0, s_lcomm_internal);
+@@ -611,11 +647,17 @@ obj_elf_change_section (const char *name,
+                .section .lbss,"aw",@progbits
++               "@progbits" is incorrect.  Also for sharable bss
++               sections, gcc, as of 2005-07-06, will emit
++
++               .section .sharable_bss,"aw",@progbits
++
+                "@progbits" is incorrect.  */
+ #ifdef TC_I386
+             && (bed->s->arch_size != 64
+                 || !(ssect->attr & SHF_X86_64_LARGE))
+ #endif
++            && !(ssect->attr & SHF_GNU_SHARABLE)
+             && ssect->type != SHT_INIT_ARRAY
+             && ssect->type != SHT_FINI_ARRAY
+             && ssect->type != SHT_PREINIT_ARRAY)
+diff --git a/include/bfdlink.h b/include/bfdlink.h
+index 1ac0738..8f6f2dc 100644
+--- a/include/bfdlink.h
++++ b/include/bfdlink.h
+@@ -387,6 +387,9 @@ struct bfd_link_info
+      --dynamic-list command line options.  */
+   unsigned int dynamic: 1;
++  /* TRUE if sharables sections may be created.  */
++  unsigned int sharable_sections: 1;
++
+   /* TRUE if PT_GNU_STACK segment should be created with PF_R|PF_W|PF_X
+      flags.  */
+   unsigned int execstack: 1;
+diff --git a/include/elf/common.h b/include/elf/common.h
+index cd3bcdd..4f5e4b6 100644
+--- a/include/elf/common.h
++++ b/include/elf/common.h
+@@ -437,6 +437,7 @@
+ #define PT_SUNW_EH_FRAME PT_GNU_EH_FRAME      /* Solaris uses the same value */
+ #define PT_GNU_STACK  (PT_LOOS + 0x474e551) /* Stack flags */
+ #define PT_GNU_RELRO  (PT_LOOS + 0x474e552) /* Read-only after relocation */
++#define PT_GNU_SHR    (PT_LOOS + 0x474e554) /* Sharable segment */
+ /* Program segment permissions, in program header p_flags field.  */
+@@ -519,6 +520,8 @@
+                                          are not to be further
+                                          relocated.  */
++#define SHF_GNU_SHARABLE 0x01000000   /* sharable section */
++
+ /* Values of note segment descriptor types for core files.  */
+ #define NT_PRSTATUS   1               /* Contains copy of prstatus struct */
+@@ -688,6 +691,9 @@
+ #define STT_LOPROC    13              /* Processor-specific semantics */
+ #define STT_HIPROC    15              /* Processor-specific semantics */
++/* Associated symbol is in common sharable */
++#define SHN_GNU_SHARABLE_COMMON (SHN_LOOS + 10)
++
+ /* The following constants control how a symbol may be accessed once it has
+    become part of an executable or shared library.  */
+diff --git a/ld/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
+index d34297b..9fb8982 100644
+--- a/ld/emulparams/elf32_x86_64.sh
++++ b/ld/emulparams/elf32_x86_64.sh
+@@ -16,6 +16,7 @@ LARGE_SECTIONS=yes
+ LARGE_BSS_AFTER_BSS=
+ SEPARATE_GOTPLT="SIZEOF (.got.plt) >= 24 ? 24 : 0"
+ IREL_IN_PLT=
++SHARABLE_SECTIONS=yes
+ if [ "x${host}" = "x${target}" ]; then
+   case " $EMULATION_LIBPATH " in
+diff --git a/ld/emulparams/elf64_ia64.sh b/ld/emulparams/elf64_ia64.sh
+index 7e5e54d..d8cf531 100644
+--- a/ld/emulparams/elf64_ia64.sh
++++ b/ld/emulparams/elf64_ia64.sh
+@@ -37,3 +37,4 @@ OTHER_READONLY_SECTIONS="${OTHER_READONLY_SECTIONS}
+ # .dtors.  They have to be next to .sbss/.sbss2/.sdata/.sdata2.
+ SMALL_DATA_CTOR=" "
+ SMALL_DATA_DTOR=" "
++SHARABLE_SECTIONS=yes
+diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh
+index add700f..dc2d6ef 100644
+--- a/ld/emulparams/elf_i386.sh
++++ b/ld/emulparams/elf_i386.sh
+@@ -13,6 +13,7 @@ GENERATE_PIE_SCRIPT=yes
+ NO_SMALL_DATA=yes
+ SEPARATE_GOTPLT="SIZEOF (.got.plt) >= 12 ? 12 : 0"
+ IREL_IN_PLT=
++SHARABLE_SECTIONS=yes
+ # Linux modify the default library search path to first include
+ # a 32-bit specific directory.
+diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
+index 4842257..e9cd479 100644
+--- a/ld/emulparams/elf_x86_64.sh
++++ b/ld/emulparams/elf_x86_64.sh
+@@ -16,6 +16,7 @@ LARGE_SECTIONS=yes
+ LARGE_BSS_AFTER_BSS=
+ SEPARATE_GOTPLT="SIZEOF (.got.plt) >= 24 ? 24 : 0"
+ IREL_IN_PLT=
++SHARABLE_SECTIONS=yes
+ if [ "x${host}" = "x${target}" ]; then
+   case " $EMULATION_LIBPATH " in
+diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
+index 682f5e5..510ca2f 100644
+--- a/ld/emultempl/elf32.em
++++ b/ld/emultempl/elf32.em
+@@ -105,6 +105,7 @@ gld${EMULATION_NAME}_before_parse (void)
+   input_flags.dynamic = ${DYNAMIC_LINK-TRUE};
+   config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`;
+   config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then echo TRUE ; else echo FALSE ; fi`;
++  link_info.sharable_sections = `if test "$SHARABLE_SECTIONS" = "yes" ; then echo TRUE ; else echo FALSE ; fi`;
+ }
+ EOF
+@@ -1816,6 +1817,12 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
+   int iself = s->owner->xvec->flavour == bfd_target_elf_flavour;
+   unsigned int sh_type = iself ? elf_section_type (s) : SHT_NULL;
++  /* Orphaned sharable sections won't have correct page
++     requirements.  */
++  if (elf_section_flags (s) & SHF_GNU_SHARABLE)
++    einfo ("%F%P: unable to place orphaned sharable section %A (%B)\n",
++         s, s->owner);
++
+   if (! link_info.relocatable
+       && link_info.combreloc
+       && (s->flags & SEC_ALLOC))
+diff --git a/ld/ldmain.c b/ld/ldmain.c
+index 019df71..8a5f01f 100644
+--- a/ld/ldmain.c
++++ b/ld/ldmain.c
+@@ -289,6 +289,7 @@ main (int argc, char **argv)
+   link_info.pei386_auto_import = -1;
+   link_info.spare_dynamic_tags = 5;
+   link_info.path_separator = ':';
++  link_info.sharable_sections = FALSE;
+   ldfile_add_arch ("");
+   emulation = get_emulation (argc, argv);
+diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
+index e8126cb..922a906 100644
+--- a/ld/scripttempl/elf.sc
++++ b/ld/scripttempl/elf.sc
+@@ -298,6 +298,40 @@ STACK="  .stack        ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} :
+     ${RELOCATING+${USER_LABEL_PREFIX}_stack = .;}
+     *(.stack)
+   }"
++test "${SHARABLE_SECTIONS}" = "yes" && OTHER_READWRITE_SECTIONS="
++  ${OTHER_READWRITE_SECTIONS}
++  /* Sharable data sections.  */
++  .sharable_data ${RELOCATING-0} : ${RELOCATING+ALIGN(${MAXPAGESIZE})}
++  {
++    ${RELOCATING+PROVIDE_HIDDEN (__sharable_data_start = .);}
++    *(.sharable_data${RELOCATING+ .sharable_data.* .gnu.linkonce.shrd.*})
++    /* Align here to ensure that the sharable data section ends at the
++       page boundary.  */
++    ${RELOCATING+. = ALIGN(. != 0 ? ${MAXPAGESIZE} : 1);}
++    ${RELOCATING+PROVIDE_HIDDEN (__sharable_data_end = .);}
++  }
++"
++test "${SHARABLE_SECTIONS}" = "yes" && OTHER_BSS_SECTIONS="
++  ${OTHER_BSS_SECTIONS}
++  /* Sharable bss sections  */
++  .sharable_bss ${RELOCATING-0} : ${RELOCATING+ALIGN(${MAXPAGESIZE})}
++  {
++    ${RELOCATING+PROVIDE_HIDDEN (__sharable_bss_start = .);}
++    *(.dynsharablebss)
++    *(.sharable_bss${RELOCATING+ .sharable_bss.* .gnu.linkonce.shrb.*}) 
++    *(SHARABLE_COMMON)
++    /* Align here to ensure that the sharable bss section ends at the
++       page boundary.  */
++    ${RELOCATING+. = ALIGN(. != 0 ? ${MAXPAGESIZE} : 1);}
++    ${RELOCATING+PROVIDE_HIDDEN (__sharable_bss_end = .);}
++  }
++"
++test "${SHARABLE_SECTIONS}" = "yes" && REL_SHARABLE="
++  .rel.sharable_data  ${RELOCATING-0} : { *(.rel.sharable_data${RELOCATING+ .rel.sharable_data.* .rel.gnu.linkonce.shrd.*}) }
++  .rela.sharable_data ${RELOCATING-0} : { *(.rela.sharable_data${RELOCATING+ .rela.sharable_data.* .rela.gnu.linkonce.shrd.*}) }
++  .rel.sharable_bss   ${RELOCATING-0} : { *(.rel.sharable_bss${RELOCATING+ .rel.sharable_bss.* .rel.gnu.linkonce.shrb.*}) }
++  .rela.sharable_bss  ${RELOCATING-0} : { *(.rela.sharable_bss${RELOCATING+ .rela.sharable_bss.* .rela.gnu.linkonce.shrb.*}) }
++"
+ TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${TEXT_START_ADDR})"
+ SHLIB_TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${SHLIB_TEXT_START_ADDR:-0})"
+@@ -392,6 +426,7 @@ eval $COMBRELOCCAT <<EOF
+   .rel.got      ${RELOCATING-0} : { *(.rel.got) }
+   .rela.got     ${RELOCATING-0} : { *(.rela.got) }
+   ${OTHER_GOT_RELOC_SECTIONS}
++  ${REL_SHARABLE}
+   ${REL_SDATA}
+   ${REL_SBSS}
+   ${REL_SDATA2}
+-- 
+1.8.3.1
+