Home | History | Annotate | Line # | Download | only in bfd
elf-ifunc.c revision 1.1.1.3
      1      1.1  christos /* ELF STT_GNU_IFUNC support.
      2  1.1.1.3  christos    Copyright (C) 2009-2015 Free Software Foundation, Inc.
      3      1.1  christos 
      4      1.1  christos    This file is part of BFD, the Binary File Descriptor library.
      5      1.1  christos 
      6      1.1  christos    This program is free software; you can redistribute it and/or modify
      7      1.1  christos    it under the terms of the GNU General Public License as published by
      8      1.1  christos    the Free Software Foundation; either version 3 of the License, or
      9      1.1  christos    (at your option) any later version.
     10      1.1  christos 
     11      1.1  christos    This program is distributed in the hope that it will be useful,
     12      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14      1.1  christos    GNU General Public License for more details.
     15      1.1  christos 
     16      1.1  christos    You should have received a copy of the GNU General Public License
     17      1.1  christos    along with this program; if not, write to the Free Software
     18      1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     19      1.1  christos    MA 02110-1301, USA.  */
     20      1.1  christos 
     21      1.1  christos #include "sysdep.h"
     22      1.1  christos #include "bfd.h"
     23      1.1  christos #include "bfdlink.h"
     24      1.1  christos #include "libbfd.h"
     25      1.1  christos #define ARCH_SIZE 0
     26      1.1  christos #include "elf-bfd.h"
     27      1.1  christos #include "safe-ctype.h"
     28      1.1  christos #include "libiberty.h"
     29      1.1  christos #include "objalloc.h"
     30      1.1  christos 
     31      1.1  christos /* Create sections needed by STT_GNU_IFUNC symbol.  */
     32      1.1  christos 
     33      1.1  christos bfd_boolean
     34      1.1  christos _bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
     35      1.1  christos {
     36      1.1  christos   flagword flags, pltflags;
     37      1.1  christos   asection *s;
     38      1.1  christos   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
     39      1.1  christos   struct elf_link_hash_table *htab = elf_hash_table (info);
     40      1.1  christos 
     41      1.1  christos   if (htab->irelifunc != NULL || htab->iplt != NULL)
     42      1.1  christos     return TRUE;
     43      1.1  christos 
     44      1.1  christos   flags = bed->dynamic_sec_flags;
     45      1.1  christos   pltflags = flags;
     46      1.1  christos   if (bed->plt_not_loaded)
     47      1.1  christos     /* We do not clear SEC_ALLOC here because we still want the OS to
     48      1.1  christos        allocate space for the section; it's just that there's nothing
     49      1.1  christos        to read in from the object file.  */
     50      1.1  christos     pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
     51      1.1  christos   else
     52      1.1  christos     pltflags |= SEC_ALLOC | SEC_CODE | SEC_LOAD;
     53      1.1  christos   if (bed->plt_readonly)
     54      1.1  christos     pltflags |= SEC_READONLY;
     55      1.1  christos 
     56  1.1.1.3  christos   if (bfd_link_pic (info))
     57      1.1  christos     {
     58      1.1  christos       /* We need to create .rel[a].ifunc for shared objects.  */
     59      1.1  christos       const char *rel_sec = (bed->rela_plts_and_copies_p
     60      1.1  christos 			     ? ".rela.ifunc" : ".rel.ifunc");
     61      1.1  christos 
     62      1.1  christos       s = bfd_make_section_with_flags (abfd, rel_sec,
     63      1.1  christos 				       flags | SEC_READONLY);
     64      1.1  christos       if (s == NULL
     65      1.1  christos 	  || ! bfd_set_section_alignment (abfd, s,
     66      1.1  christos 					  bed->s->log_file_align))
     67      1.1  christos 	return FALSE;
     68      1.1  christos       htab->irelifunc = s;
     69      1.1  christos     }
     70      1.1  christos   else
     71      1.1  christos     {
     72      1.1  christos       /* We need to create .iplt, .rel[a].iplt, .igot and .igot.plt
     73      1.1  christos 	 for static executables.   */
     74      1.1  christos       s = bfd_make_section_with_flags (abfd, ".iplt", pltflags);
     75      1.1  christos       if (s == NULL
     76      1.1  christos 	  || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
     77      1.1  christos 	return FALSE;
     78      1.1  christos       htab->iplt = s;
     79      1.1  christos 
     80      1.1  christos       s = bfd_make_section_with_flags (abfd,
     81      1.1  christos 				       (bed->rela_plts_and_copies_p
     82      1.1  christos 					? ".rela.iplt" : ".rel.iplt"),
     83      1.1  christos 				       flags | SEC_READONLY);
     84      1.1  christos       if (s == NULL
     85      1.1  christos 	  || ! bfd_set_section_alignment (abfd, s,
     86      1.1  christos 					  bed->s->log_file_align))
     87      1.1  christos 	return FALSE;
     88      1.1  christos       htab->irelplt = s;
     89      1.1  christos 
     90      1.1  christos       /* We don't need the .igot section if we have the .igot.plt
     91      1.1  christos 	 section.  */
     92      1.1  christos       if (bed->want_got_plt)
     93      1.1  christos 	s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
     94      1.1  christos       else
     95      1.1  christos 	s = bfd_make_section_with_flags (abfd, ".igot", flags);
     96      1.1  christos       if (s == NULL
     97      1.1  christos 	  || !bfd_set_section_alignment (abfd, s,
     98      1.1  christos 					 bed->s->log_file_align))
     99      1.1  christos 	return FALSE;
    100      1.1  christos       htab->igotplt = s;
    101      1.1  christos     }
    102      1.1  christos 
    103      1.1  christos   return TRUE;
    104      1.1  christos }
    105      1.1  christos 
    106      1.1  christos /* Allocate space in .plt, .got and associated reloc sections for
    107      1.1  christos    dynamic relocs against a STT_GNU_IFUNC symbol definition.  */
    108      1.1  christos 
    109      1.1  christos bfd_boolean
    110      1.1  christos _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
    111      1.1  christos 				    struct elf_link_hash_entry *h,
    112      1.1  christos 				    struct elf_dyn_relocs **head,
    113      1.1  christos 				    unsigned int plt_entry_size,
    114  1.1.1.3  christos 				    unsigned int plt_header_size,
    115      1.1  christos 				    unsigned int got_entry_size)
    116      1.1  christos {
    117      1.1  christos   asection *plt, *gotplt, *relplt;
    118      1.1  christos   struct elf_dyn_relocs *p;
    119      1.1  christos   unsigned int sizeof_reloc;
    120      1.1  christos   const struct elf_backend_data *bed;
    121      1.1  christos   struct elf_link_hash_table *htab;
    122      1.1  christos 
    123      1.1  christos   /* When a shared library references a STT_GNU_IFUNC symbol defined
    124      1.1  christos      in executable, the address of the resolved function may be used.
    125      1.1  christos      But in non-shared executable, the address of its .plt slot may
    126      1.1  christos      be used.  Pointer equality may not work correctly.  PIE should
    127      1.1  christos      be used if pointer equality is required here.  */
    128  1.1.1.3  christos   if (!bfd_link_pic (info)
    129      1.1  christos       && (h->dynindx != -1
    130      1.1  christos 	  || info->export_dynamic)
    131      1.1  christos       && h->pointer_equality_needed)
    132      1.1  christos     {
    133  1.1.1.3  christos       info->callbacks->einfo
    134      1.1  christos 	(_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
    135      1.1  christos 	   "equality in `%B' can not be used when making an "
    136      1.1  christos 	   "executable; recompile with -fPIE and relink with -pie\n"),
    137      1.1  christos 	 h->root.root.string,
    138      1.1  christos 	 h->root.u.def.section->owner);
    139      1.1  christos       bfd_set_error (bfd_error_bad_value);
    140      1.1  christos       return FALSE;
    141      1.1  christos     }
    142      1.1  christos 
    143      1.1  christos   htab = elf_hash_table (info);
    144      1.1  christos 
    145  1.1.1.3  christos   /* When building shared library, we need to handle the case where it is
    146  1.1.1.3  christos      marked with regular reference, but not non-GOT reference since the
    147  1.1.1.3  christos      non-GOT reference bit may not be set here.  */
    148  1.1.1.3  christos   if (bfd_link_pic (info) && !h->non_got_ref && h->ref_regular)
    149  1.1.1.3  christos     for (p = *head; p != NULL; p = p->next)
    150  1.1.1.3  christos       if (p->count)
    151  1.1.1.3  christos 	{
    152  1.1.1.3  christos 	  h->non_got_ref = 1;
    153  1.1.1.3  christos 	  goto keep;
    154  1.1.1.3  christos 	}
    155  1.1.1.3  christos 
    156      1.1  christos   /* Support garbage collection against STT_GNU_IFUNC symbols.  */
    157      1.1  christos   if (h->plt.refcount <= 0 && h->got.refcount <= 0)
    158      1.1  christos     {
    159  1.1.1.2  christos       h->got = htab->init_got_offset;
    160  1.1.1.2  christos       h->plt = htab->init_plt_offset;
    161  1.1.1.2  christos       *head = NULL;
    162  1.1.1.2  christos       return TRUE;
    163      1.1  christos     }
    164      1.1  christos 
    165      1.1  christos   /* Return and discard space for dynamic relocations against it if
    166      1.1  christos      it is never referenced in a non-shared object.  */
    167      1.1  christos   if (!h->ref_regular)
    168      1.1  christos     {
    169      1.1  christos       if (h->plt.refcount > 0
    170      1.1  christos 	  || h->got.refcount > 0)
    171      1.1  christos 	abort ();
    172      1.1  christos       h->got = htab->init_got_offset;
    173      1.1  christos       h->plt = htab->init_plt_offset;
    174      1.1  christos       *head = NULL;
    175      1.1  christos       return TRUE;
    176      1.1  christos     }
    177      1.1  christos 
    178  1.1.1.2  christos keep:
    179      1.1  christos   bed = get_elf_backend_data (info->output_bfd);
    180      1.1  christos   if (bed->rela_plts_and_copies_p)
    181      1.1  christos     sizeof_reloc = bed->s->sizeof_rela;
    182      1.1  christos   else
    183      1.1  christos     sizeof_reloc = bed->s->sizeof_rel;
    184      1.1  christos 
    185      1.1  christos   /* When building a static executable, use .iplt, .igot.plt and
    186      1.1  christos      .rel[a].iplt sections for STT_GNU_IFUNC symbols.  */
    187      1.1  christos   if (htab->splt != NULL)
    188      1.1  christos     {
    189      1.1  christos       plt = htab->splt;
    190      1.1  christos       gotplt = htab->sgotplt;
    191      1.1  christos       relplt = htab->srelplt;
    192      1.1  christos 
    193      1.1  christos       /* If this is the first .plt entry, make room for the special
    194      1.1  christos 	 first entry.  */
    195      1.1  christos       if (plt->size == 0)
    196  1.1.1.3  christos 	plt->size += plt_header_size;
    197      1.1  christos     }
    198      1.1  christos   else
    199      1.1  christos     {
    200      1.1  christos       plt = htab->iplt;
    201      1.1  christos       gotplt = htab->igotplt;
    202      1.1  christos       relplt = htab->irelplt;
    203      1.1  christos     }
    204      1.1  christos 
    205      1.1  christos   /* Don't update value of STT_GNU_IFUNC symbol to PLT.  We need
    206  1.1.1.3  christos      the original value for R_*_IRELATIVE.  */
    207      1.1  christos   h->plt.offset = plt->size;
    208      1.1  christos 
    209      1.1  christos   /* Make room for this entry in the .plt/.iplt section.  */
    210      1.1  christos   plt->size += plt_entry_size;
    211      1.1  christos 
    212      1.1  christos   /* We also need to make an entry in the .got.plt/.got.iplt section,
    213      1.1  christos      which will be placed in the .got section by the linker script.  */
    214      1.1  christos   gotplt->size += got_entry_size;
    215      1.1  christos 
    216      1.1  christos   /* We also need to make an entry in the .rel[a].plt/.rel[a].iplt
    217      1.1  christos      section.  */
    218      1.1  christos   relplt->size += sizeof_reloc;
    219      1.1  christos   relplt->reloc_count++;
    220      1.1  christos 
    221      1.1  christos   /* We need dynamic relocation for STT_GNU_IFUNC symbol only when
    222      1.1  christos      there is a non-GOT reference in a shared object.  */
    223  1.1.1.3  christos   if (!bfd_link_pic (info)
    224      1.1  christos       || !h->non_got_ref)
    225      1.1  christos     *head = NULL;
    226      1.1  christos 
    227      1.1  christos   /* Finally, allocate space.  */
    228  1.1.1.2  christos   p = *head;
    229  1.1.1.2  christos   if (p != NULL)
    230  1.1.1.2  christos     {
    231  1.1.1.2  christos       bfd_size_type count = 0;
    232  1.1.1.2  christos       do
    233  1.1.1.2  christos 	{
    234  1.1.1.2  christos 	  count += p->count;
    235  1.1.1.2  christos 	  p = p->next;
    236  1.1.1.2  christos 	}
    237  1.1.1.2  christos       while (p != NULL);
    238  1.1.1.2  christos       htab->irelifunc->size += count * sizeof_reloc;
    239  1.1.1.2  christos     }
    240      1.1  christos 
    241  1.1.1.2  christos   /* For STT_GNU_IFUNC symbol, .got.plt has the real function address
    242      1.1  christos      and .got has the PLT entry adddress.  We will load the GOT entry
    243      1.1  christos      with the PLT entry in finish_dynamic_symbol if it is used.  For
    244      1.1  christos      branch, it uses .got.plt.  For symbol value,
    245      1.1  christos      1. Use .got.plt in a shared object if it is forced local or not
    246      1.1  christos      dynamic.
    247      1.1  christos      2. Use .got.plt in a non-shared object if pointer equality isn't
    248      1.1  christos      needed.
    249      1.1  christos      3. Use .got.plt in PIE.
    250      1.1  christos      4. Use .got.plt if .got isn't used.
    251      1.1  christos      5. Otherwise use .got so that it can be shared among different
    252      1.1  christos      objects at run-time.
    253      1.1  christos      We only need to relocate .got entry in shared object.  */
    254  1.1.1.2  christos   if (h->got.refcount <= 0
    255  1.1.1.3  christos       || (bfd_link_pic (info)
    256  1.1.1.2  christos 	  && (h->dynindx == -1
    257  1.1.1.2  christos 	      || h->forced_local))
    258  1.1.1.3  christos       || (!bfd_link_pic (info)
    259      1.1  christos 	  && !h->pointer_equality_needed)
    260  1.1.1.3  christos       || bfd_link_pie (info)
    261      1.1  christos       || htab->sgot == NULL)
    262      1.1  christos     {
    263      1.1  christos       /* Use .got.plt.  */
    264      1.1  christos       h->got.offset = (bfd_vma) -1;
    265      1.1  christos     }
    266      1.1  christos   else
    267      1.1  christos     {
    268      1.1  christos       h->got.offset = htab->sgot->size;
    269      1.1  christos       htab->sgot->size += got_entry_size;
    270  1.1.1.3  christos       if (bfd_link_pic (info))
    271      1.1  christos 	htab->srelgot->size += sizeof_reloc;
    272      1.1  christos     }
    273      1.1  christos 
    274      1.1  christos   return TRUE;
    275      1.1  christos }
    276  1.1.1.3  christos 
    277  1.1.1.3  christos /* Similar to _bfd_elf_get_synthetic_symtab, optimized for unsorted PLT
    278  1.1.1.3  christos    entries.  PLT is the PLT section.  PLT_SYM_VAL is a function pointer
    279  1.1.1.3  christos    which returns an array of PLT entry symbol values.  */
    280  1.1.1.3  christos 
    281  1.1.1.3  christos long
    282  1.1.1.3  christos _bfd_elf_ifunc_get_synthetic_symtab
    283  1.1.1.3  christos   (bfd *abfd, long symcount ATTRIBUTE_UNUSED,
    284  1.1.1.3  christos    asymbol **syms ATTRIBUTE_UNUSED, long dynsymcount, asymbol **dynsyms,
    285  1.1.1.3  christos    asymbol **ret, asection *plt,
    286  1.1.1.3  christos    bfd_vma *(*get_plt_sym_val) (bfd *, asymbol **, asection *, asection *))
    287  1.1.1.3  christos {
    288  1.1.1.3  christos   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
    289  1.1.1.3  christos   asection *relplt;
    290  1.1.1.3  christos   asymbol *s;
    291  1.1.1.3  christos   const char *relplt_name;
    292  1.1.1.3  christos   bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
    293  1.1.1.3  christos   arelent *p;
    294  1.1.1.3  christos   long count, i, n;
    295  1.1.1.3  christos   size_t size;
    296  1.1.1.3  christos   Elf_Internal_Shdr *hdr;
    297  1.1.1.3  christos   char *names;
    298  1.1.1.3  christos   bfd_vma *plt_sym_val;
    299  1.1.1.3  christos 
    300  1.1.1.3  christos   *ret = NULL;
    301  1.1.1.3  christos 
    302  1.1.1.3  christos   if (plt == NULL)
    303  1.1.1.3  christos     return 0;
    304  1.1.1.3  christos 
    305  1.1.1.3  christos   if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
    306  1.1.1.3  christos     return 0;
    307  1.1.1.3  christos 
    308  1.1.1.3  christos   if (dynsymcount <= 0)
    309  1.1.1.3  christos     return 0;
    310  1.1.1.3  christos 
    311  1.1.1.3  christos   relplt_name = bed->relplt_name;
    312  1.1.1.3  christos   if (relplt_name == NULL)
    313  1.1.1.3  christos     relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt";
    314  1.1.1.3  christos   relplt = bfd_get_section_by_name (abfd, relplt_name);
    315  1.1.1.3  christos   if (relplt == NULL)
    316  1.1.1.3  christos     return 0;
    317  1.1.1.3  christos 
    318  1.1.1.3  christos   hdr = &elf_section_data (relplt)->this_hdr;
    319  1.1.1.3  christos   if (hdr->sh_link != elf_dynsymtab (abfd)
    320  1.1.1.3  christos       || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA))
    321  1.1.1.3  christos     return 0;
    322  1.1.1.3  christos 
    323  1.1.1.3  christos   slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
    324  1.1.1.3  christos   if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
    325  1.1.1.3  christos     return -1;
    326  1.1.1.3  christos 
    327  1.1.1.3  christos   count = relplt->size / hdr->sh_entsize;
    328  1.1.1.3  christos   size = count * sizeof (asymbol);
    329  1.1.1.3  christos   p = relplt->relocation;
    330  1.1.1.3  christos   for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
    331  1.1.1.3  christos     {
    332  1.1.1.3  christos       size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
    333  1.1.1.3  christos       if (p->addend != 0)
    334  1.1.1.3  christos 	{
    335  1.1.1.3  christos #ifdef BFD64
    336  1.1.1.3  christos 	  size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64);
    337  1.1.1.3  christos #else
    338  1.1.1.3  christos 	  size += sizeof ("+0x") - 1 + 8;
    339  1.1.1.3  christos #endif
    340  1.1.1.3  christos 	}
    341  1.1.1.3  christos     }
    342  1.1.1.3  christos 
    343  1.1.1.3  christos   plt_sym_val = get_plt_sym_val (abfd, dynsyms, plt, relplt);
    344  1.1.1.3  christos   if (plt_sym_val == NULL)
    345  1.1.1.3  christos     return -1;
    346  1.1.1.3  christos 
    347  1.1.1.3  christos   s = *ret = (asymbol *) bfd_malloc (size);
    348  1.1.1.3  christos   if (s == NULL)
    349  1.1.1.3  christos     {
    350  1.1.1.3  christos       free (plt_sym_val);
    351  1.1.1.3  christos       return -1;
    352  1.1.1.3  christos     }
    353  1.1.1.3  christos 
    354  1.1.1.3  christos   names = (char *) (s + count);
    355  1.1.1.3  christos   p = relplt->relocation;
    356  1.1.1.3  christos   n = 0;
    357  1.1.1.3  christos   for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
    358  1.1.1.3  christos     {
    359  1.1.1.3  christos       size_t len;
    360  1.1.1.3  christos       bfd_vma addr;
    361  1.1.1.3  christos 
    362  1.1.1.3  christos       addr = plt_sym_val[i];
    363  1.1.1.3  christos       if (addr == (bfd_vma) -1)
    364  1.1.1.3  christos 	continue;
    365  1.1.1.3  christos 
    366  1.1.1.3  christos       *s = **p->sym_ptr_ptr;
    367  1.1.1.3  christos       /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set.  Since
    368  1.1.1.3  christos 	 we are defining a symbol, ensure one of them is set.  */
    369  1.1.1.3  christos       if ((s->flags & BSF_LOCAL) == 0)
    370  1.1.1.3  christos 	s->flags |= BSF_GLOBAL;
    371  1.1.1.3  christos       s->flags |= BSF_SYNTHETIC;
    372  1.1.1.3  christos       s->section = plt;
    373  1.1.1.3  christos       s->value = addr - plt->vma;
    374  1.1.1.3  christos       s->name = names;
    375  1.1.1.3  christos       s->udata.p = NULL;
    376  1.1.1.3  christos       len = strlen ((*p->sym_ptr_ptr)->name);
    377  1.1.1.3  christos       memcpy (names, (*p->sym_ptr_ptr)->name, len);
    378  1.1.1.3  christos       names += len;
    379  1.1.1.3  christos       if (p->addend != 0)
    380  1.1.1.3  christos 	{
    381  1.1.1.3  christos 	  char buf[30], *a;
    382  1.1.1.3  christos 
    383  1.1.1.3  christos 	  memcpy (names, "+0x", sizeof ("+0x") - 1);
    384  1.1.1.3  christos 	  names += sizeof ("+0x") - 1;
    385  1.1.1.3  christos 	  bfd_sprintf_vma (abfd, buf, p->addend);
    386  1.1.1.3  christos 	  for (a = buf; *a == '0'; ++a)
    387  1.1.1.3  christos 	    ;
    388  1.1.1.3  christos 	  len = strlen (a);
    389  1.1.1.3  christos 	  memcpy (names, a, len);
    390  1.1.1.3  christos 	  names += len;
    391  1.1.1.3  christos 	}
    392  1.1.1.3  christos       memcpy (names, "@plt", sizeof ("@plt"));
    393  1.1.1.3  christos       names += sizeof ("@plt");
    394  1.1.1.3  christos       ++s, ++n;
    395  1.1.1.3  christos     }
    396  1.1.1.3  christos 
    397  1.1.1.3  christos   free (plt_sym_val);
    398  1.1.1.3  christos 
    399  1.1.1.3  christos   return n;
    400  1.1.1.3  christos }
    401