aboutsummaryrefslogtreecommitdiff
path: root/patches/binutils-sharable.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/binutils-sharable.patch')
-rw-r--r--patches/binutils-sharable.patch1305
1 files changed, 1305 insertions, 0 deletions
diff --git a/patches/binutils-sharable.patch b/patches/binutils-sharable.patch
new file mode 100644
index 0000000..0bd574a
--- /dev/null
+++ b/patches/binutils-sharable.patch
@@ -0,0 +1,1305 @@
+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 5e53cba..0b694e4 100644
+--- a/bfd/elf-bfd.h
++++ b/bfd/elf-bfd.h
+@@ -1218,8 +1218,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 *);
+@@ -2150,6 +2151,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 c8238ba..2f5162d 100644
+--- a/bfd/elf.c
++++ b/bfd/elf.c
+@@ -2244,6 +2244,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 }
+ };
+
+@@ -2298,6 +2300,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 }
+ };
+
+@@ -3761,6 +3765,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)
+@@ -3931,6 +3961,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;
+@@ -4239,6 +4271,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. */
+@@ -4286,6 +4334,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);
+@@ -4826,6 +4928,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 e0eef28..e14ca09 100644
+--- a/bfd/elf32-i386.c
++++ b/bfd/elf32-i386.c
+@@ -842,6 +842,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. */
+@@ -1023,10 +1026,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
+@@ -2218,17 +2230,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 (info, h, s);
+ }
+
+@@ -2993,6 +3011,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
+ || s == htab->elf.igotplt
+ || s == htab->plt_got
+ || s == htab->plt_eh_frame
++ || s == htab->sdynsharablebss
+ || s == htab->sdynbss)
+ {
+ /* Strip these too. */
+@@ -4852,20 +4871,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;
+@@ -5260,7 +5285,8 @@ elf_i386_add_symbol_hook (bfd * abfd,
+ && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
+ 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 i386_elf32_vec
+@@ -5311,6 +5337,19 @@ elf_i386_add_symbol_hook (bfd * abfd,
+ #define elf_backend_hash_symbol elf_i386_hash_symbol
+ #define elf_backend_add_symbol_hook elf_i386_add_symbol_hook
+
++#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 4aff9b0..dd996cf 100644
+--- a/bfd/elf64-x86-64.c
++++ b/bfd/elf64-x86-64.c
+@@ -866,6 +866,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. */
+@@ -1074,10 +1077,10 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj,
+ if (info->executable)
+ {
+ /* Always allow copy relocs for building executables. */
++ const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
+ asection *s = bfd_get_linker_section (dynobj, ".rela.bss");
+ if (s == NULL)
+ {
+- const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
+ s = bfd_make_section_anyway_with_flags (dynobj,
+ ".rela.bss",
+ (bed->dynamic_sec_flags
+@@ -1088,6 +1091,32 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj,
+ return FALSE;
+ }
+ htab->srelbss = s;
++
++ s = bfd_get_linker_section (dynobj, ".dynsharablebss");
++ if (s == NULL)
++ {
++ s = bfd_make_section_anyway_with_flags (dynobj,
++ ".dynsharablebss",
++ (SEC_ALLOC
++ | SEC_LINKER_CREATED));
++ if (s == NULL)
++ return FALSE;
++ }
++ htab->sdynsharablebss = s;
++
++ s = bfd_get_linker_section (dynobj, ".rela.sharable_bss");
++ if (s == NULL)
++ {
++ s = bfd_make_section_anyway_with_flags (dynobj,
++ ".rela.sharable_bss",
++ (bed->dynamic_sec_flags
++ | SEC_READONLY));
++ if (s == NULL
++ || ! bfd_set_section_alignment (dynobj, s,
++ bed->s->log_file_align))
++ return FALSE;
++ }
++ htab->srelsharablebss = s;
+ }
+
+ if (!info->no_ld_generated_unwind_info
+@@ -2444,6 +2473,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. */
+@@ -2451,12 +2482,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 (info, h, s);
+ }
+
+@@ -3243,6 +3278,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
+ || s == htab->plt_bnd
+ || s == htab->plt_got
+ || s == htab->plt_eh_frame
++ || s == htab->sdynsharablebss
+ || s == htab->sdynbss)
+ {
+ /* Strip this section if we don't need it; see the
+@@ -5206,13 +5242,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
+@@ -5220,7 +5262,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;
+@@ -5665,7 +5707,8 @@ elf_x86_64_add_symbol_hook (bfd *abfd,
+ && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+
+- return TRUE;
++ return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
++ secp, valp);
+ }
+
+
+@@ -5681,7 +5724,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. */
+@@ -5699,22 +5743,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;
+ }
+@@ -5723,7 +5771,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;
+ }
+@@ -5733,9 +5781,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
+@@ -5744,7 +5795,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)
+@@ -5752,13 +5804,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 2da6d1b..983874d 100644
+--- a/bfd/elflink.c
++++ b/bfd/elflink.c
+@@ -386,6 +386,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;
++ }
+ }
+ }
+
+@@ -1327,7 +1348,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;
+ }
+@@ -13233,3 +13255,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 a8d8d0b..02420ec 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. */
+@@ -5068,6 +5069,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 d9ddb35..67adbb7 100644
+--- a/binutils/readelf.c
++++ b/binutils/readelf.c
+@@ -1538,6 +1538,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
+@@ -3478,6 +3480,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";
+@@ -9998,6 +10001,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 e2ef99e..d2b6f7b 100644
+--- a/gas/config/obj-elf.c
++++ b/gas/config/obj-elf.c
+@@ -76,6 +76,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);
+
+@@ -136,6 +137,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},
+ };
+@@ -391,6 +394,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);
+@@ -609,11 +645,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 f3181ba..f1bfaf2 100644
+--- a/include/bfdlink.h
++++ b/include/bfdlink.h
+@@ -396,6 +396,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 1d68f80..b27021f 100644
+--- a/include/elf/common.h
++++ b/include/elf/common.h
+@@ -435,6 +435,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. */
+
+@@ -517,6 +518,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 */
+@@ -686,6 +689,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 11d17ad..012ca78 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 2ebfaac..d1b8eb1 100644
+--- a/ld/emulparams/elf_i386.sh
++++ b/ld/emulparams/elf_i386.sh
+@@ -17,6 +17,7 @@ IREL_IN_PLT=
+ TINY_READONLY_SECTION="
+ .plt.got ${RELOCATING-0} : { *(.plt.got) }
+ "
++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 aa26a1b..b33143a 100644
+--- a/ld/emulparams/elf_x86_64.sh
++++ b/ld/emulparams/elf_x86_64.sh
+@@ -21,6 +21,7 @@ TINY_READONLY_SECTION="
+ .plt.got ${RELOCATING-0} : { *(.plt.got) }
+ .plt.bnd ${RELOCATING-0} : { *(.plt.bnd) }
+ "
++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 137446f..1d402e6 100644
+--- a/ld/emultempl/elf32.em
++++ b/ld/emultempl/elf32.em
+@@ -102,6 +102,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
+@@ -1788,6 +1789,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 bc24957..4295ba7 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 4368fd9..0904495 100644
+--- a/ld/scripttempl/elf.sc
++++ b/ld/scripttempl/elf.sc
+@@ -303,6 +303,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})"
+@@ -403,6 +437,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}