diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/elf-bfd.h | 21 | ||||
-rw-r--r-- | bfd/elf.c | 103 | ||||
-rw-r--r-- | bfd/elf32-i386.c | 84 | ||||
-rw-r--r-- | bfd/elf64-x86-64.c | 88 | ||||
-rw-r--r-- | bfd/elflink.c | 228 | ||||
-rw-r--r-- | bfd/elfnn-ia64.c | 16 |
6 files changed, 516 insertions, 24 deletions
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 163ef35..63074d8 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 *); @@ -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 4179572..a90937b 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 f920208..5c7eb3b 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 bb83854..fe02b75 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 b8e0e76..3c9e9a6 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 |