Home | History | Annotate | Line # | Download | only in bfd
      1       1.1  christos /* ELF STT_GNU_IFUNC support.
      2  1.1.1.11  christos    Copyright (C) 2009-2026 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.1.8  christos bool
     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.1.11  christos   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.1.8  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.1.4  christos       /* We need to create .rel[a].ifunc for PIC 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.1.7  christos 	  || !bfd_set_section_alignment (s, bed->s->log_file_align))
     66   1.1.1.8  christos 	return false;
     67       1.1  christos       htab->irelifunc = s;
     68       1.1  christos     }
     69       1.1  christos   else
     70       1.1  christos     {
     71       1.1  christos       /* We need to create .iplt, .rel[a].iplt, .igot and .igot.plt
     72       1.1  christos 	 for static executables.   */
     73       1.1  christos       s = bfd_make_section_with_flags (abfd, ".iplt", pltflags);
     74       1.1  christos       if (s == NULL
     75   1.1.1.7  christos 	  || !bfd_set_section_alignment (s, bed->plt_alignment))
     76   1.1.1.8  christos 	return false;
     77       1.1  christos       htab->iplt = s;
     78       1.1  christos 
     79       1.1  christos       s = bfd_make_section_with_flags (abfd,
     80       1.1  christos 				       (bed->rela_plts_and_copies_p
     81       1.1  christos 					? ".rela.iplt" : ".rel.iplt"),
     82       1.1  christos 				       flags | SEC_READONLY);
     83       1.1  christos       if (s == NULL
     84   1.1.1.7  christos 	  || !bfd_set_section_alignment (s, bed->s->log_file_align))
     85   1.1.1.8  christos 	return false;
     86       1.1  christos       htab->irelplt = s;
     87       1.1  christos 
     88       1.1  christos       /* We don't need the .igot section if we have the .igot.plt
     89       1.1  christos 	 section.  */
     90       1.1  christos       if (bed->want_got_plt)
     91       1.1  christos 	s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
     92       1.1  christos       else
     93       1.1  christos 	s = bfd_make_section_with_flags (abfd, ".igot", flags);
     94       1.1  christos       if (s == NULL
     95   1.1.1.7  christos 	  || !bfd_set_section_alignment (s, bed->s->log_file_align))
     96   1.1.1.8  christos 	return false;
     97       1.1  christos       htab->igotplt = s;
     98       1.1  christos     }
     99       1.1  christos 
    100   1.1.1.8  christos   return true;
    101       1.1  christos }
    102       1.1  christos 
    103       1.1  christos /* Allocate space in .plt, .got and associated reloc sections for
    104       1.1  christos    dynamic relocs against a STT_GNU_IFUNC symbol definition.  */
    105       1.1  christos 
    106   1.1.1.8  christos bool
    107       1.1  christos _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
    108       1.1  christos 				    struct elf_link_hash_entry *h,
    109       1.1  christos 				    struct elf_dyn_relocs **head,
    110       1.1  christos 				    unsigned int plt_entry_size,
    111   1.1.1.3  christos 				    unsigned int plt_header_size,
    112   1.1.1.4  christos 				    unsigned int got_entry_size,
    113   1.1.1.8  christos 				    bool avoid_plt)
    114       1.1  christos {
    115       1.1  christos   asection *plt, *gotplt, *relplt;
    116       1.1  christos   struct elf_dyn_relocs *p;
    117       1.1  christos   unsigned int sizeof_reloc;
    118  1.1.1.11  christos   elf_backend_data *bed;
    119       1.1  christos   struct elf_link_hash_table *htab;
    120   1.1.1.4  christos   /* If AVOID_PLT is TRUE, don't use PLT if possible.  */
    121   1.1.1.8  christos   bool use_plt = !avoid_plt || h->plt.refcount > 0;
    122   1.1.1.8  christos   bool need_dynreloc = !use_plt || bfd_link_pic (info);
    123   1.1.1.4  christos 
    124   1.1.1.4  christos   /* When a PIC object references a STT_GNU_IFUNC symbol defined
    125   1.1.1.4  christos      in executable or it isn't referenced via PLT, the address of
    126   1.1.1.4  christos      the resolved function may be used.  But in non-PIC executable,
    127   1.1.1.4  christos      the address of its .plt slot may be used.  Pointer equality may
    128   1.1.1.4  christos      not work correctly.  PIE or non-PLT reference should be used if
    129   1.1.1.6  christos      pointer equality is required here.
    130   1.1.1.6  christos 
    131   1.1.1.6  christos      If STT_GNU_IFUNC symbol is defined in position-dependent executable,
    132   1.1.1.6  christos      backend should change it to the normal function and set its address
    133   1.1.1.6  christos      to its PLT entry which should be resolved by R_*_IRELATIVE at
    134   1.1.1.6  christos      run-time.  All external references should be resolved to its PLT in
    135   1.1.1.6  christos      executable.  */
    136   1.1.1.4  christos   if (!need_dynreloc
    137   1.1.1.6  christos       && !(bfd_link_pde (info) && h->def_regular)
    138       1.1  christos       && (h->dynindx != -1
    139       1.1  christos 	  || info->export_dynamic)
    140       1.1  christos       && h->pointer_equality_needed)
    141       1.1  christos     {
    142  1.1.1.10  christos       info->callbacks->fatal
    143   1.1.1.5  christos 	/* xgettext:c-format */
    144  1.1.1.10  christos 	(_("%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
    145   1.1.1.6  christos 	   "equality in `%pB' can not be used when making an "
    146       1.1  christos 	   "executable; recompile with -fPIE and relink with -pie\n"),
    147       1.1  christos 	 h->root.root.string,
    148       1.1  christos 	 h->root.u.def.section->owner);
    149       1.1  christos       bfd_set_error (bfd_error_bad_value);
    150   1.1.1.8  christos       return false;
    151       1.1  christos     }
    152       1.1  christos 
    153       1.1  christos   htab = elf_hash_table (info);
    154       1.1  christos 
    155   1.1.1.4  christos   /* When the symbol is marked with regular reference, if PLT isn't used
    156   1.1.1.4  christos      or we are building a PIC object, we must keep dynamic relocation
    157   1.1.1.4  christos      if there is non-GOT reference and use PLT if there is PC-relative
    158   1.1.1.4  christos      reference.  */
    159   1.1.1.4  christos   if (need_dynreloc && h->ref_regular)
    160   1.1.1.4  christos     {
    161   1.1.1.8  christos       bool keep = false;
    162   1.1.1.4  christos       for (p = *head; p != NULL; p = p->next)
    163   1.1.1.4  christos 	if (p->count)
    164   1.1.1.4  christos 	  {
    165   1.1.1.4  christos 	    h->non_got_ref = 1;
    166   1.1.1.4  christos 	    /* Need dynamic relocations for non-GOT reference.  */
    167   1.1.1.8  christos 	    keep = true;
    168   1.1.1.4  christos 	    if (p->pc_count)
    169   1.1.1.4  christos 	      {
    170   1.1.1.4  christos 		/* Must use PLT for PC-relative reference.  */
    171   1.1.1.8  christos 		use_plt = true;
    172   1.1.1.4  christos 		need_dynreloc = bfd_link_pic (info);
    173   1.1.1.4  christos 		break;
    174   1.1.1.4  christos 	      }
    175   1.1.1.4  christos 	  }
    176   1.1.1.4  christos       if (keep)
    177   1.1.1.4  christos 	goto keep;
    178   1.1.1.4  christos     }
    179   1.1.1.3  christos 
    180       1.1  christos   /* Support garbage collection against STT_GNU_IFUNC symbols.  */
    181       1.1  christos   if (h->plt.refcount <= 0 && h->got.refcount <= 0)
    182       1.1  christos     {
    183   1.1.1.2  christos       h->got = htab->init_got_offset;
    184   1.1.1.2  christos       h->plt = htab->init_plt_offset;
    185   1.1.1.2  christos       *head = NULL;
    186   1.1.1.8  christos       return true;
    187       1.1  christos     }
    188       1.1  christos 
    189       1.1  christos   /* Return and discard space for dynamic relocations against it if
    190   1.1.1.4  christos      it is never referenced.  */
    191       1.1  christos   if (!h->ref_regular)
    192       1.1  christos     {
    193       1.1  christos       if (h->plt.refcount > 0
    194       1.1  christos 	  || h->got.refcount > 0)
    195       1.1  christos 	abort ();
    196       1.1  christos       h->got = htab->init_got_offset;
    197       1.1  christos       h->plt = htab->init_plt_offset;
    198       1.1  christos       *head = NULL;
    199   1.1.1.8  christos       return true;
    200       1.1  christos     }
    201       1.1  christos 
    202   1.1.1.8  christos  keep:
    203       1.1  christos   bed = get_elf_backend_data (info->output_bfd);
    204       1.1  christos   if (bed->rela_plts_and_copies_p)
    205       1.1  christos     sizeof_reloc = bed->s->sizeof_rela;
    206       1.1  christos   else
    207       1.1  christos     sizeof_reloc = bed->s->sizeof_rel;
    208       1.1  christos 
    209       1.1  christos   /* When building a static executable, use .iplt, .igot.plt and
    210       1.1  christos      .rel[a].iplt sections for STT_GNU_IFUNC symbols.  */
    211       1.1  christos   if (htab->splt != NULL)
    212       1.1  christos     {
    213       1.1  christos       plt = htab->splt;
    214       1.1  christos       gotplt = htab->sgotplt;
    215       1.1  christos       relplt = htab->srelplt;
    216       1.1  christos 
    217   1.1.1.4  christos       /* If this is the first .plt entry and PLT is used, make room for
    218   1.1.1.4  christos 	 the special first entry.  */
    219   1.1.1.4  christos       if (plt->size == 0 && use_plt)
    220   1.1.1.3  christos 	plt->size += plt_header_size;
    221       1.1  christos     }
    222       1.1  christos   else
    223       1.1  christos     {
    224       1.1  christos       plt = htab->iplt;
    225       1.1  christos       gotplt = htab->igotplt;
    226       1.1  christos       relplt = htab->irelplt;
    227       1.1  christos     }
    228       1.1  christos 
    229   1.1.1.4  christos   if (use_plt)
    230   1.1.1.4  christos     {
    231   1.1.1.4  christos       /* Don't update value of STT_GNU_IFUNC symbol to PLT.  We need
    232   1.1.1.4  christos 	 the original value for R_*_IRELATIVE.  */
    233   1.1.1.4  christos       h->plt.offset = plt->size;
    234   1.1.1.4  christos 
    235   1.1.1.4  christos       /* Make room for this entry in the .plt/.iplt section.  */
    236   1.1.1.4  christos       plt->size += plt_entry_size;
    237   1.1.1.4  christos 
    238   1.1.1.4  christos       /* We also need to make an entry in the .got.plt/.got.iplt section,
    239   1.1.1.4  christos 	 which will be placed in the .got section by the linker script.  */
    240   1.1.1.4  christos       gotplt->size += got_entry_size;
    241   1.1.1.4  christos     }
    242       1.1  christos 
    243       1.1  christos   /* We also need to make an entry in the .rel[a].plt/.rel[a].iplt
    244   1.1.1.4  christos      section for GOTPLT relocation if PLT is used.  */
    245   1.1.1.4  christos   if (use_plt)
    246   1.1.1.4  christos     {
    247   1.1.1.4  christos       relplt->size += sizeof_reloc;
    248   1.1.1.4  christos       relplt->reloc_count++;
    249   1.1.1.4  christos     }
    250       1.1  christos 
    251       1.1  christos   /* We need dynamic relocation for STT_GNU_IFUNC symbol only when
    252   1.1.1.4  christos      there is a non-GOT reference in a PIC object or PLT isn't used.  */
    253   1.1.1.4  christos   if (!need_dynreloc || !h->non_got_ref)
    254       1.1  christos     *head = NULL;
    255       1.1  christos 
    256       1.1  christos   /* Finally, allocate space.  */
    257   1.1.1.2  christos   p = *head;
    258   1.1.1.2  christos   if (p != NULL)
    259   1.1.1.2  christos     {
    260   1.1.1.2  christos       bfd_size_type count = 0;
    261   1.1.1.2  christos       do
    262   1.1.1.2  christos 	{
    263   1.1.1.2  christos 	  count += p->count;
    264   1.1.1.2  christos 	  p = p->next;
    265   1.1.1.2  christos 	}
    266   1.1.1.2  christos       while (p != NULL);
    267   1.1.1.4  christos 
    268   1.1.1.8  christos       htab->ifunc_resolvers = count != 0;
    269   1.1.1.8  christos 
    270   1.1.1.4  christos       /* Dynamic relocations are stored in
    271   1.1.1.4  christos 	 1. .rel[a].ifunc section in PIC object.
    272   1.1.1.4  christos 	 2. .rel[a].got section in dynamic executable.
    273   1.1.1.4  christos 	 3. .rel[a].iplt section in static executable.  */
    274   1.1.1.4  christos       if (bfd_link_pic (info))
    275   1.1.1.4  christos 	htab->irelifunc->size += count * sizeof_reloc;
    276   1.1.1.4  christos       else if (htab->splt != NULL)
    277   1.1.1.4  christos 	htab->srelgot->size += count * sizeof_reloc;
    278   1.1.1.4  christos       else
    279   1.1.1.4  christos 	{
    280   1.1.1.4  christos 	  relplt->size += count * sizeof_reloc;
    281   1.1.1.4  christos 	  relplt->reloc_count += count;
    282   1.1.1.4  christos 	}
    283   1.1.1.2  christos     }
    284       1.1  christos 
    285   1.1.1.2  christos   /* For STT_GNU_IFUNC symbol, .got.plt has the real function address
    286       1.1  christos      and .got has the PLT entry adddress.  We will load the GOT entry
    287       1.1  christos      with the PLT entry in finish_dynamic_symbol if it is used.  For
    288   1.1.1.4  christos      branch, it uses .got.plt.  For symbol value, if PLT is used,
    289   1.1.1.4  christos      1. Use .got.plt in a PIC object if it is forced local or not
    290       1.1  christos      dynamic.
    291   1.1.1.4  christos      2. Use .got.plt in a non-PIC object if pointer equality isn't
    292       1.1  christos      needed.
    293       1.1  christos      3. Use .got.plt in PIE.
    294       1.1  christos      4. Use .got.plt if .got isn't used.
    295       1.1  christos      5. Otherwise use .got so that it can be shared among different
    296       1.1  christos      objects at run-time.
    297   1.1.1.4  christos      If PLT isn't used, always use .got for symbol value.
    298   1.1.1.4  christos      We only need to relocate .got entry in PIC object or in dynamic
    299   1.1.1.4  christos      executable without PLT.  */
    300   1.1.1.4  christos   if (use_plt
    301   1.1.1.4  christos       && (h->got.refcount <= 0
    302   1.1.1.4  christos 	  || (bfd_link_pic (info)
    303   1.1.1.4  christos 	      && (h->dynindx == -1
    304   1.1.1.4  christos 		  || h->forced_local))
    305   1.1.1.4  christos 	  || (!bfd_link_pic (info)
    306   1.1.1.4  christos 	      && !h->pointer_equality_needed)
    307   1.1.1.4  christos 	  || bfd_link_pie (info)
    308   1.1.1.4  christos 	  || htab->sgot == NULL))
    309       1.1  christos     {
    310       1.1  christos       /* Use .got.plt.  */
    311       1.1  christos       h->got.offset = (bfd_vma) -1;
    312       1.1  christos     }
    313       1.1  christos   else
    314       1.1  christos     {
    315   1.1.1.4  christos       if (!use_plt)
    316   1.1.1.4  christos 	{
    317   1.1.1.4  christos 	  /* PLT isn't used.  */
    318   1.1.1.4  christos 	  h->plt.offset = (bfd_vma) -1;
    319   1.1.1.4  christos 	}
    320   1.1.1.4  christos       if (h->got.refcount <= 0)
    321   1.1.1.4  christos 	{
    322   1.1.1.4  christos 	  /* GOT isn't need when there are only relocations for static
    323   1.1.1.4  christos 	     pointers.  */
    324   1.1.1.4  christos 	  h->got.offset = (bfd_vma) -1;
    325   1.1.1.4  christos 	}
    326   1.1.1.4  christos       else
    327   1.1.1.4  christos 	{
    328   1.1.1.4  christos 	  h->got.offset = htab->sgot->size;
    329   1.1.1.4  christos 	  htab->sgot->size += got_entry_size;
    330   1.1.1.4  christos 	  /* Need to relocate the GOT entry in a PIC object or PLT isn't
    331   1.1.1.4  christos 	     used.  Otherwise, the GOT entry will be filled with the PLT
    332   1.1.1.4  christos 	     entry and dynamic GOT relocation isn't needed.  */
    333   1.1.1.4  christos 	  if (need_dynreloc)
    334   1.1.1.4  christos 	    {
    335   1.1.1.4  christos 	      /* For non-static executable, dynamic GOT relocation is in
    336   1.1.1.4  christos 		 .rel[a].got section, but for static executable, it is
    337   1.1.1.4  christos 		 in .rel[a].iplt section.  */
    338   1.1.1.4  christos 	      if (htab->splt != NULL)
    339   1.1.1.4  christos 		htab->srelgot->size += sizeof_reloc;
    340   1.1.1.4  christos 	      else
    341   1.1.1.4  christos 		{
    342   1.1.1.4  christos 		  relplt->size += sizeof_reloc;
    343   1.1.1.4  christos 		  relplt->reloc_count++;
    344   1.1.1.4  christos 		}
    345   1.1.1.4  christos 	    }
    346   1.1.1.4  christos 	}
    347       1.1  christos     }
    348       1.1  christos 
    349   1.1.1.8  christos   return true;
    350       1.1  christos }
    351