diff options
-rw-r--r-- | bfd/ChangeLog | 29 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 2 | ||||
-rw-r--r-- | bfd/elf32-i386.c | 42 | ||||
-rw-r--r-- | bfd/elf64-x86-64.c | 42 | ||||
-rw-r--r-- | bfd/elflink.c | 107 | ||||
-rw-r--r-- | ld/ChangeLog | 4 | ||||
-rw-r--r-- | ld/scripttempl/elf.sc | 2 |
7 files changed, 143 insertions, 85 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 8948973..c306b52 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,34 @@ 2009-06-06 H.J. Lu <hongjiu.lu@intel.com> + * elf32-i386.c (elf_i386_link_hash_table): Add irelifunc. + (elf_i386_link_hash_table_create): Initialize irelifunc. + (elf_i386_check_relocs): Updated. Set up irelifunc for + shared objects. + (elf_i386_allocate_dynrelocs): Use irelifunc for dynamic + relocation for non-GOT reference of STT_GNU_IFUNC symbol in + shared objects. + (elf_i386_relocate_section): Likewise. + + * elf64-x86-64.c (elf64_x86_64_link_hash_table): Add irelifunc. + (elf64_x86_64_link_hash_table_create): Initialize irelifunc. + (elf64_x86_64_check_relocs): Updated. Set up irelifunc for + shared objects. + (elf64_x86_64_allocate_dynrelocs): Use irelifunc for dynamic + relocation for non-GOT reference of STT_GNU_IFUNC symbol in + shared objects. + (elf64_x86_64_relocate_section): Likewise. + + * elf-bfd.h (_bfd_elf_create_static_ifunc_sections): Renamed to + ... + (_bfd_elf_create_ifunc_sections): This. + + * elflink.c (_bfd_elf_create_static_ifunc_sections): Renamd to + ... + (_bfd_elf_create_ifunc_sections): This. Create .rel[a].ifunc + for shared objects. + +2009-06-06 H.J. Lu <hongjiu.lu@intel.com> + * elf32-i386.c (elf_i386_check_relocs): Make room for dynamic relocation for R_386_32 against STT_GNU_IFUNC symbol when building shared object. Check info->executable instead of diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 258d11c..610aafc 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -2146,7 +2146,7 @@ extern int _bfd_elf_obj_attrs_arg_type (bfd *, int, int); extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *); extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *); -extern bfd_boolean _bfd_elf_create_static_ifunc_sections +extern bfd_boolean _bfd_elf_create_ifunc_sections (bfd *, struct bfd_link_info *); /* Large common section. */ diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 8fb8742..b2918cf 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -678,6 +678,7 @@ struct elf_i386_link_hash_table asection *igotplt; asection *iplt; asection *irelplt; + asection *irelifunc; /* The (unloaded but important) .rel.plt.unloaded section on VxWorks. */ asection *srelplt2; @@ -777,6 +778,7 @@ elf_i386_link_hash_table_create (bfd *abfd) ret->igotplt= NULL; ret->iplt = NULL; ret->irelplt= NULL; + ret->irelifunc = NULL; ret->tls_ldm_got.refcount = 0; ret->next_tls_desc_index = 0; ret->sgotplt_jump_table_size = 0; @@ -1279,21 +1281,30 @@ elf_i386_check_relocs (bfd *abfd, case R_386_PLT32: case R_386_GOT32: case R_386_GOTOFF: - if (!info->shared && htab->iplt == NULL) + if (htab->irelifunc == NULL && htab->iplt == NULL) { - if (!_bfd_elf_create_static_ifunc_sections (abfd, - info)) + if (!_bfd_elf_create_ifunc_sections (abfd, info)) return FALSE; - htab->iplt = bfd_get_section_by_name (abfd, ".iplt"); - htab->irelplt = bfd_get_section_by_name (abfd, - ".rel.iplt"); - htab->igotplt = bfd_get_section_by_name (abfd, - ".igot.plt"); - if (!htab->iplt - || !htab->irelplt - || !htab->igotplt) - abort (); + if (info->shared) + { + htab->irelifunc = bfd_get_section_by_name (abfd, + ".rel.ifunc"); + if (!htab->irelifunc) + abort (); + } + else + { + htab->iplt = bfd_get_section_by_name (abfd, ".iplt"); + htab->irelplt = bfd_get_section_by_name (abfd, + ".rel.iplt"); + htab->igotplt = bfd_get_section_by_name (abfd, + ".igot.plt"); + if (!htab->iplt + || !htab->irelplt + || !htab->igotplt) + abort (); + } } break; } @@ -2038,10 +2049,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* Finally, allocate space. */ for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection * sreloc = elf_section_data (p->sec)->sreloc; - sreloc->size += p->count * sizeof (Elf32_External_Rel); - } + htab->irelifunc->size += p->count * sizeof (Elf32_External_Rel); /* For STT_GNU_IFUNC symbol, .got.plt has the real function addres and .got has the PLT entry adddress. We will load @@ -3010,7 +3018,7 @@ elf_i386_relocate_section (bfd *output_bfd, else outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - sreloc = elf_section_data (input_section)->sreloc; + sreloc = htab->irelifunc; loc = sreloc->contents; loc += (sreloc->reloc_count++ * sizeof (Elf32_External_Rel)); diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 0ba5759..6819b34 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -496,6 +496,7 @@ struct elf64_x86_64_link_hash_table asection *igotplt; asection *iplt; asection *irelplt; + asection *irelifunc; /* The offset into splt of the PLT entry for the TLS descriptor resolver. Special values are 0, if not necessary (or not found @@ -591,6 +592,7 @@ elf64_x86_64_link_hash_table_create (bfd *abfd) ret->igotplt= NULL; ret->iplt = NULL; ret->irelplt= NULL; + ret->irelifunc = NULL; ret->sym_sec.abfd = NULL; ret->tlsdesc_plt = 0; ret->tlsdesc_got = 0; @@ -1065,21 +1067,30 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_X86_64_PLT32: case R_X86_64_GOTPCREL: case R_X86_64_GOTPCREL64: - if (!info->shared && htab->iplt == NULL) + if (htab->irelifunc == NULL && htab->iplt == NULL) { - if (!_bfd_elf_create_static_ifunc_sections (abfd, - info)) + if (!_bfd_elf_create_ifunc_sections (abfd, info)) return FALSE; - htab->iplt = bfd_get_section_by_name (abfd, ".iplt"); - htab->irelplt = bfd_get_section_by_name (abfd, - ".rela.iplt"); - htab->igotplt = bfd_get_section_by_name (abfd, - ".igot.plt"); - if (!htab->iplt - || !htab->irelplt - || !htab->igotplt) - abort (); + if (info->shared) + { + htab->irelifunc = bfd_get_section_by_name (abfd, + ".rela.ifunc"); + if (!htab->irelifunc) + abort (); + } + else + { + htab->iplt = bfd_get_section_by_name (abfd, ".iplt"); + htab->irelplt = bfd_get_section_by_name (abfd, + ".rela.iplt"); + htab->igotplt = bfd_get_section_by_name (abfd, + ".igot.plt"); + if (!htab->iplt + || !htab->irelplt + || !htab->igotplt) + abort (); + } } break; } @@ -1880,10 +1891,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* Finally, allocate space. */ for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection * sreloc = elf_section_data (p->sec)->sreloc; - sreloc->size += p->count * sizeof (Elf64_External_Rela); - } + htab->irelifunc->size += p->count * sizeof (Elf64_External_Rela); /* For STT_GNU_IFUNC symbol, .got.plt has the real function addres and .got has the PLT entry adddress. We will load @@ -2730,7 +2738,7 @@ elf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, outrel.r_addend = 0; } - sreloc = elf_section_data (input_section)->sreloc; + sreloc = htab->irelifunc; loc = sreloc->contents; loc += (sreloc->reloc_count++ * sizeof (Elf64_External_Rela)); diff --git a/bfd/elflink.c b/bfd/elflink.c index d182807..e3a1670 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -12492,31 +12492,17 @@ _bfd_elf_make_dynamic_reloc_section (asection * sec, return reloc_sec; } -/* Create sections needed by STT_GNU_IFUNC symbol for static - executables. */ +/* Create sections needed by STT_GNU_IFUNC symbol. */ bfd_boolean -_bfd_elf_create_static_ifunc_sections (bfd *abfd, - struct bfd_link_info *info) +_bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) { flagword flags, pltflags; int ptralign; asection *s; - const struct elf_backend_data *bed; - - /* Should never be called for shared library. */ - BFD_ASSERT (!info->shared); - - /* This function may be called more than once. */ - s = bfd_get_section_by_name (abfd, ".iplt"); - if (s != NULL) - return TRUE; - - bed = get_elf_backend_data (abfd); + const struct elf_backend_data *bed = get_elf_backend_data (abfd); - /* We need to create .iplt, .rel[a].iplt, .igot, .igot.plt, */ flags = bed->dynamic_sec_flags; - pltflags = flags; if (bed->plt_not_loaded) /* We do not clear SEC_ALLOC here because we still want the OS to @@ -12528,47 +12514,68 @@ _bfd_elf_create_static_ifunc_sections (bfd *abfd, if (bed->plt_readonly) pltflags |= SEC_READONLY; - s = bfd_make_section_with_flags (abfd, ".iplt", pltflags); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - - s = bfd_make_section_with_flags (abfd, - (bed->rela_plts_and_copies_p - ? ".rela.iplt" : ".rel.iplt"), - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - - switch (bed->s->arch_size) + if (info->shared) { - case 32: - ptralign = 2; - break; + /* We need to create .rel[a].ifunc for shared objects. */ + const char *rel_sec = (bed->rela_plts_and_copies_p + ? ".rela.ifunc" : ".rel.ifunc"); - case 64: - ptralign = 3; - break; - - default: - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* We don't need the .igot section if we have the .igot.plt - section. */ + /* This function should be called only once. */ + s = bfd_get_section_by_name (abfd, rel_sec); + if (s != NULL) + abort (); - if (bed->want_got_plt) - { - s = bfd_make_section_with_flags (abfd, ".igot.plt", flags); + s = bfd_make_section_with_flags (abfd, rel_sec, + flags | SEC_READONLY); if (s == NULL - || !bfd_set_section_alignment (abfd, s, ptralign)) + || ! bfd_set_section_alignment (abfd, s, + bed->s->log_file_align)) return FALSE; } else { - s = bfd_make_section_with_flags (abfd, ".igot", flags); + /* This function should be called only once. */ + s = bfd_get_section_by_name (abfd, ".iplt"); + if (s != NULL) + abort (); + + /* We need to create .iplt, .rel[a].iplt, .igot and .igot.plt + for static executables. */ + s = bfd_make_section_with_flags (abfd, ".iplt", pltflags); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) + return FALSE; + + s = bfd_make_section_with_flags (abfd, + (bed->rela_plts_and_copies_p + ? ".rela.iplt" : ".rel.iplt"), + flags | SEC_READONLY); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, + bed->s->log_file_align)) + return FALSE; + + switch (bed->s->arch_size) + { + case 32: + ptralign = 2; + break; + + case 64: + ptralign = 3; + break; + + default: + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* We don't need the .igot section if we have the .igot.plt + section. */ + if (bed->want_got_plt) + s = bfd_make_section_with_flags (abfd, ".igot.plt", flags); + else + s = bfd_make_section_with_flags (abfd, ".igot", flags); if (s == NULL || !bfd_set_section_alignment (abfd, s, ptralign)) return FALSE; diff --git a/ld/ChangeLog b/ld/ChangeLog index cd05d9d..89016cc 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,7 @@ +2009-06-06 H.J. Lu <hongjiu.lu@intel.com> + + * scripttempl/elf.sc: Add .rel.ifunc and .rela.ifunc. + 2009-06-05 H.J. Lu <hongjiu.lu@intel.com> * scripttempl/elf.sc: Remove .rel.ifunc.dyn and .rela.ifunc.dyn. diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc index 6d7652b..0d6cae9 100644 --- a/ld/scripttempl/elf.sc +++ b/ld/scripttempl/elf.sc @@ -326,6 +326,8 @@ eval $COMBRELOCCAT <<EOF .rel.bss ${RELOCATING-0} : { *(.rel.bss${RELOCATING+ .rel.bss.* .rel.gnu.linkonce.b.*}) } .rela.bss ${RELOCATING-0} : { *(.rela.bss${RELOCATING+ .rela.bss.* .rela.gnu.linkonce.b.*}) } ${REL_LARGE} + .rel.ifunc ${RELOCATING-0} : { *(.rel.ifunc) } + .rela.ifunc ${RELOCATING-0} : { *(.rela.ifunc) } EOF if [ -n "$COMBRELOC" ]; then |