summaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
Diffstat (limited to 'bfd')
-rw-r--r--bfd/elf-bfd.h21
-rw-r--r--bfd/elf.c103
-rw-r--r--bfd/elf32-i386.c84
-rw-r--r--bfd/elf64-x86-64.c88
-rw-r--r--bfd/elflink.c228
-rw-r--r--bfd/elfnn-ia64.c16
6 files changed, 516 insertions, 24 deletions
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 163ef35fadc..63074d8d622 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1283,8 +1283,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 *);
@@ -2268,6 +2269,24 @@ extern bfd_boolean _bfd_elf_add_dynamic_entry
(struct bfd_link_info *, bfd_vma, bfd_vma);
extern bfd_boolean _bfd_elf_link_check_relocs
(bfd *, struct bfd_link_info *);
+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 aaf2b5351d3..ac8bd60171e 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -2570,6 +2570,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 }
};
@@ -2624,6 +2626,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 }
};
@@ -4233,6 +4237,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)
@@ -4403,6 +4433,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;
@@ -4723,6 +4755,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. */
@@ -4770,6 +4818,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);
@@ -5307,6 +5409,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 417957214db..a90937b769c 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -887,6 +887,9 @@ struct elf_i386_link_hash_table
/* TRUE if there are dynamic relocs against IFUNC symbols that apply
to read-only sections. */
bfd_boolean readonly_dynrelocs_against_ifunc;
+
+ asection *sdynsharablebss;
+ asection *srelsharablebss;
};
/* Get the i386 ELF linker hash table from a link_info structure. */
@@ -1090,10 +1093,10 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
if (bfd_link_executable (info))
{
/* 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, ".rel.bss");
if (s == NULL)
{
- const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
s = bfd_make_section_anyway_with_flags (dynobj,
".rel.bss",
(bed->dynamic_sec_flags
@@ -1104,6 +1107,32 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
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, ".rel.sharable_bss");
+ if (s == NULL)
+ {
+ s = bfd_make_section_anyway_with_flags (dynobj,
+ ".rel.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 (get_elf_i386_backend_data (dynobj)->is_vxworks
@@ -2586,17 +2615,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);
}
@@ -3408,6 +3443,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. */
@@ -5560,20 +5596,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;
@@ -6032,6 +6074,22 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h)
return _bfd_elf_hash_symbol (h);
}
+/* Hook called by the linker routine which adds symbols from an object
+ file. */
+
+static bfd_boolean
+elf_i386_add_symbol_hook (bfd * abfd,
+ struct bfd_link_info * info,
+ Elf_Internal_Sym * sym,
+ const char ** namep,
+ flagword * flagsp,
+ asection ** secp,
+ bfd_vma * valp)
+{
+ return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
+ secp, valp);
+}
+
#define TARGET_LITTLE_SYM i386_elf32_vec
#define TARGET_LITTLE_NAME "elf32-i386"
#define ELF_ARCH bfd_arch_i386
@@ -6080,8 +6138,22 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h)
#define elf_backend_omit_section_dynsym \
((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
#define elf_backend_hash_symbol elf_i386_hash_symbol
+#define elf_backend_add_symbol_hook elf_i386_add_symbol_hook
#define elf_backend_fixup_symbol elf_i386_fixup_symbol
+#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 f9202085b38..5c7eb3be972 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -909,6 +909,9 @@ struct elf_x86_64_link_hash_table
/* TRUE if there are dynamic relocs against IFUNC symbols that apply
to read-only sections. */
bfd_boolean readonly_dynrelocs_against_ifunc;
+
+ asection *sdynsharablebss;
+ asection *srelsharablebss;
};
/* Get the x86-64 ELF linker hash table from a link_info structure. */
@@ -1133,10 +1136,10 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj,
if (bfd_link_executable (info))
{
/* 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
@@ -1147,6 +1150,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
@@ -2986,6 +3015,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. */
@@ -2993,12 +3024,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);
}
@@ -3812,6 +3847,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
@@ -6004,13 +6040,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
@@ -6018,7 +6060,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;
@@ -6540,7 +6582,8 @@ elf_x86_64_add_symbol_hook (bfd *abfd,
return TRUE;
}
- return TRUE;
+ return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
+ secp, valp);
}
@@ -6556,7 +6599,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. */
@@ -6574,22 +6618,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;
}
@@ -6598,7 +6646,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;
}
@@ -6608,9 +6656,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
@@ -6619,7 +6670,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)
@@ -6627,13 +6679,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 bb83854a275..fe02b75c8e5 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -448,6 +448,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;
+ }
}
}
@@ -1464,7 +1485,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;
}
@@ -13870,3 +13892,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 b8e0e76c942..3c9e9a662df 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. */
@@ -5066,6 +5067,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