diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2009-06-03 12:35:18 +0000 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2009-06-03 12:35:18 +0000 |
commit | 0018b0a3d56c9f71bc9590cfc0a1c90a05662ff1 (patch) | |
tree | e4ae60b9b96d979b201dc7f00ab8c9478eb571a9 /bfd/elf64-x86-64.c | |
parent | b517c9b6165399a02ab4cd32287118385a893b3d (diff) | |
download | gdb-0018b0a3d56c9f71bc9590cfc0a1c90a05662ff1.zip gdb-0018b0a3d56c9f71bc9590cfc0a1c90a05662ff1.tar.gz gdb-0018b0a3d56c9f71bc9590cfc0a1c90a05662ff1.tar.bz2 |
2009-06-03 H.J. Lu <hongjiu.lu@intel.com>
* elf32-i386.c (elf_i386_allocate_dynrelocs): Allocate
GOT entry for STT_GNU_IFUNC symbol with pointer equality.
(elf_i386_relocate_section): Adjust R_386_GOT32 relocation
against STT_GNU_IFUNC symbols for static executables.
(elf_i386_finish_dynamic_symbol): Load GOT entry with
PLT entry for STT_GNU_IFUNC symbol with pointer equality.
* elf64-x86-64.c (elf64_x86_64_allocate_dynrelocs): Allocate
GOT entry for STT_GNU_IFUNC symbol with pointer equality.
(elf64_x86_64_finish_dynamic_symbol): Load GOT entry with
PLT entry for STT_GNU_IFUNC symbol with pointer equality.
Diffstat (limited to 'bfd/elf64-x86-64.c')
-rw-r--r-- | bfd/elf64-x86-64.c | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index e858325..1dec3c3 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -1841,10 +1841,26 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* STT_GNU_IFUNC symbol uses .got.plt, not .got. But for shared library, we must go through GOT and we can't use R_X86_64_IRELATIVE unless it is forced local. */ - if (!info->shared + if (info->executable || info->symbolic || h->forced_local) - h->got.refcount = 0; + { + if (h->pointer_equality_needed + && htab->sgot != NULL) + { + /* We can't use .got.plt, which contains the real + function addres, since we need pointer equality. + We will load the GOT entry with the PLT entry + in elf64_x86_64_finish_dynamic_symbol and don't + need GOT relocation. */ + h->got.offset = htab->sgot->size; + htab->sgot->size += GOT_ENTRY_SIZE; + eh->tlsdesc_got = (bfd_vma) -1; + goto skip_relgot; + } + else + h->got.refcount = 0; + } } else if (htab->elf.dynamic_sections_created && h->plt.refcount > 0) @@ -1971,6 +1987,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) else h->got.offset = (bfd_vma) -1; +skip_relgot: if (eh->dyn_relocs == NULL) return TRUE; @@ -3727,8 +3744,28 @@ elf64_x86_64_finish_dynamic_symbol (bfd *output_bfd, of a version file, we just want to emit a RELATIVE reloc. The entry in the global offset table will already have been initialized in the relocate_section function. */ - if (info->shared - && SYMBOL_REFERENCES_LOCAL (info, h)) + if ((info->executable + || info->symbolic + || h->forced_local) + && h->def_regular + && h->pointer_equality_needed + && h->type == STT_GNU_IFUNC) + { + /* The STT_GNU_IFUNC symbol is locally defined. But we can't + use .got.plt, which contains the real function addres, + since we need pointer equality. We load the GOT entry + with the PLT entry without relocation. */ + asection *plt = htab->splt ? htab->splt : htab->iplt; + if (htab->sgot == NULL + || h->plt.offset == (bfd_vma) -1) + abort (); + bfd_put_64 (output_bfd, (plt->output_section->vma + + plt->output_offset + h->plt.offset), + htab->sgot->contents + h->got.offset); + return TRUE; + } + else if (info->shared + && SYMBOL_REFERENCES_LOCAL (info, h)) { if (!h->def_regular) return FALSE; |