Home | History | Annotate | Line # | Download | only in bfd
elf-ifunc.c revision 1.6
      1  1.1  christos /* ELF STT_GNU_IFUNC support.
      2  1.6  christos    Copyright (C) 2009-2016 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.6  christos   if (bfd_link_pic (info))
     57  1.1  christos     {
     58  1.6  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  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.6  christos 				    bfd_boolean *readonly_dynrelocs_against_ifunc_p,
    114  1.1  christos 				    unsigned int plt_entry_size,
    115  1.1  christos 				    unsigned int plt_header_size,
    116  1.6  christos 				    unsigned int got_entry_size,
    117  1.6  christos 				    bfd_boolean avoid_plt)
    118  1.1  christos {
    119  1.1  christos   asection *plt, *gotplt, *relplt;
    120  1.1  christos   struct elf_dyn_relocs *p;
    121  1.1  christos   unsigned int sizeof_reloc;
    122  1.1  christos   const struct elf_backend_data *bed;
    123  1.1  christos   struct elf_link_hash_table *htab;
    124  1.6  christos   bfd_boolean readonly_dynrelocs_against_ifunc;
    125  1.6  christos   /* If AVOID_PLT is TRUE, don't use PLT if possible.  */
    126  1.6  christos   bfd_boolean use_plt = !avoid_plt || h->plt.refcount > 0;
    127  1.6  christos   bfd_boolean need_dynreloc = !use_plt || bfd_link_pic (info);
    128  1.6  christos 
    129  1.6  christos   /* When a PIC object references a STT_GNU_IFUNC symbol defined
    130  1.6  christos      in executable or it isn't referenced via PLT, the address of
    131  1.6  christos      the resolved function may be used.  But in non-PIC executable,
    132  1.6  christos      the address of its .plt slot may be used.  Pointer equality may
    133  1.6  christos      not work correctly.  PIE or non-PLT reference should be used if
    134  1.6  christos      pointer equality is required here.  */
    135  1.6  christos   if (!need_dynreloc
    136  1.1  christos       && (h->dynindx != -1
    137  1.1  christos 	  || info->export_dynamic)
    138  1.1  christos       && h->pointer_equality_needed)
    139  1.1  christos     {
    140  1.1  christos       info->callbacks->einfo
    141  1.1  christos 	(_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
    142  1.1  christos 	   "equality in `%B' can not be used when making an "
    143  1.1  christos 	   "executable; recompile with -fPIE and relink with -pie\n"),
    144  1.1  christos 	 h->root.root.string,
    145  1.1  christos 	 h->root.u.def.section->owner);
    146  1.1  christos       bfd_set_error (bfd_error_bad_value);
    147  1.1  christos       return FALSE;
    148  1.1  christos     }
    149  1.1  christos 
    150  1.1  christos   htab = elf_hash_table (info);
    151  1.1  christos 
    152  1.6  christos   /* When the symbol is marked with regular reference, if PLT isn't used
    153  1.6  christos      or we are building a PIC object, we must keep dynamic relocation
    154  1.6  christos      if there is non-GOT reference and use PLT if there is PC-relative
    155  1.6  christos      reference.  */
    156  1.6  christos   if (need_dynreloc && h->ref_regular)
    157  1.6  christos     {
    158  1.6  christos       bfd_boolean keep = FALSE;
    159  1.6  christos       for (p = *head; p != NULL; p = p->next)
    160  1.6  christos 	if (p->count)
    161  1.6  christos 	  {
    162  1.6  christos 	    h->non_got_ref = 1;
    163  1.6  christos 	    /* Need dynamic relocations for non-GOT reference.  */
    164  1.6  christos 	    keep = TRUE;
    165  1.6  christos 	    if (p->pc_count)
    166  1.6  christos 	      {
    167  1.6  christos 		/* Must use PLT for PC-relative reference.  */
    168  1.6  christos 		use_plt = TRUE;
    169  1.6  christos 		need_dynreloc = bfd_link_pic (info);
    170  1.6  christos 		break;
    171  1.6  christos 	      }
    172  1.6  christos 	  }
    173  1.6  christos       if (keep)
    174  1.6  christos 	goto keep;
    175  1.6  christos     }
    176  1.1  christos 
    177  1.1  christos   /* Support garbage collection against STT_GNU_IFUNC symbols.  */
    178  1.1  christos   if (h->plt.refcount <= 0 && h->got.refcount <= 0)
    179  1.1  christos     {
    180  1.1  christos       h->got = htab->init_got_offset;
    181  1.1  christos       h->plt = htab->init_plt_offset;
    182  1.1  christos       *head = NULL;
    183  1.1  christos       return TRUE;
    184  1.1  christos     }
    185  1.1  christos 
    186  1.1  christos   /* Return and discard space for dynamic relocations against it if
    187  1.6  christos      it is never referenced.  */
    188  1.1  christos   if (!h->ref_regular)
    189  1.1  christos     {
    190  1.1  christos       if (h->plt.refcount > 0
    191  1.1  christos 	  || h->got.refcount > 0)
    192  1.1  christos 	abort ();
    193  1.1  christos       h->got = htab->init_got_offset;
    194  1.1  christos       h->plt = htab->init_plt_offset;
    195  1.1  christos       *head = NULL;
    196  1.1  christos       return TRUE;
    197  1.1  christos     }
    198  1.1  christos 
    199  1.1  christos keep:
    200  1.1  christos   bed = get_elf_backend_data (info->output_bfd);
    201  1.1  christos   if (bed->rela_plts_and_copies_p)
    202  1.1  christos     sizeof_reloc = bed->s->sizeof_rela;
    203  1.1  christos   else
    204  1.1  christos     sizeof_reloc = bed->s->sizeof_rel;
    205  1.1  christos 
    206  1.1  christos   /* When building a static executable, use .iplt, .igot.plt and
    207  1.1  christos      .rel[a].iplt sections for STT_GNU_IFUNC symbols.  */
    208  1.1  christos   if (htab->splt != NULL)
    209  1.1  christos     {
    210  1.1  christos       plt = htab->splt;
    211  1.1  christos       gotplt = htab->sgotplt;
    212  1.1  christos       relplt = htab->srelplt;
    213  1.1  christos 
    214  1.6  christos       /* If this is the first .plt entry and PLT is used, make room for
    215  1.6  christos 	 the special first entry.  */
    216  1.6  christos       if (plt->size == 0 && use_plt)
    217  1.1  christos 	plt->size += plt_header_size;
    218  1.1  christos     }
    219  1.1  christos   else
    220  1.1  christos     {
    221  1.1  christos       plt = htab->iplt;
    222  1.1  christos       gotplt = htab->igotplt;
    223  1.1  christos       relplt = htab->irelplt;
    224  1.1  christos     }
    225  1.1  christos 
    226  1.6  christos   if (use_plt)
    227  1.6  christos     {
    228  1.6  christos       /* Don't update value of STT_GNU_IFUNC symbol to PLT.  We need
    229  1.6  christos 	 the original value for R_*_IRELATIVE.  */
    230  1.6  christos       h->plt.offset = plt->size;
    231  1.6  christos 
    232  1.6  christos       /* Make room for this entry in the .plt/.iplt section.  */
    233  1.6  christos       plt->size += plt_entry_size;
    234  1.6  christos 
    235  1.6  christos       /* We also need to make an entry in the .got.plt/.got.iplt section,
    236  1.6  christos 	 which will be placed in the .got section by the linker script.  */
    237  1.6  christos       gotplt->size += got_entry_size;
    238  1.6  christos     }
    239  1.1  christos 
    240  1.1  christos   /* We also need to make an entry in the .rel[a].plt/.rel[a].iplt
    241  1.6  christos      section for GOTPLT relocation if PLT is used.  */
    242  1.6  christos   if (use_plt)
    243  1.6  christos     {
    244  1.6  christos       relplt->size += sizeof_reloc;
    245  1.6  christos       relplt->reloc_count++;
    246  1.6  christos     }
    247  1.1  christos 
    248  1.1  christos   /* We need dynamic relocation for STT_GNU_IFUNC symbol only when
    249  1.6  christos      there is a non-GOT reference in a PIC object or PLT isn't used.  */
    250  1.6  christos   if (!need_dynreloc || !h->non_got_ref)
    251  1.1  christos     *head = NULL;
    252  1.1  christos 
    253  1.6  christos   readonly_dynrelocs_against_ifunc = FALSE;
    254  1.6  christos 
    255  1.1  christos   /* Finally, allocate space.  */
    256  1.1  christos   p = *head;
    257  1.1  christos   if (p != NULL)
    258  1.1  christos     {
    259  1.1  christos       bfd_size_type count = 0;
    260  1.1  christos       do
    261  1.1  christos 	{
    262  1.6  christos 	  if (!readonly_dynrelocs_against_ifunc)
    263  1.6  christos 	    {
    264  1.6  christos 	      asection *s = p->sec->output_section;
    265  1.6  christos 	      if (s != NULL && (s->flags & SEC_READONLY) != 0)
    266  1.6  christos 		readonly_dynrelocs_against_ifunc = TRUE;
    267  1.6  christos 	    }
    268  1.1  christos 	  count += p->count;
    269  1.1  christos 	  p = p->next;
    270  1.1  christos 	}
    271  1.1  christos       while (p != NULL);
    272  1.6  christos 
    273  1.6  christos       /* Dynamic relocations are stored in
    274  1.6  christos 	 1. .rel[a].ifunc section in PIC object.
    275  1.6  christos 	 2. .rel[a].got section in dynamic executable.
    276  1.6  christos 	 3. .rel[a].iplt section in static executable.  */
    277  1.6  christos       if (bfd_link_pic (info))
    278  1.6  christos 	htab->irelifunc->size += count * sizeof_reloc;
    279  1.6  christos       else if (htab->splt != NULL)
    280  1.6  christos 	htab->srelgot->size += count * sizeof_reloc;
    281  1.6  christos       else
    282  1.6  christos 	{
    283  1.6  christos 	  relplt->size += count * sizeof_reloc;
    284  1.6  christos 	  relplt->reloc_count += count;
    285  1.6  christos 	}
    286  1.1  christos     }
    287  1.1  christos 
    288  1.6  christos   if (readonly_dynrelocs_against_ifunc_p)
    289  1.6  christos     *readonly_dynrelocs_against_ifunc_p = readonly_dynrelocs_against_ifunc;
    290  1.6  christos 
    291  1.1  christos   /* For STT_GNU_IFUNC symbol, .got.plt has the real function address
    292  1.1  christos      and .got has the PLT entry adddress.  We will load the GOT entry
    293  1.1  christos      with the PLT entry in finish_dynamic_symbol if it is used.  For
    294  1.6  christos      branch, it uses .got.plt.  For symbol value, if PLT is used,
    295  1.6  christos      1. Use .got.plt in a PIC object if it is forced local or not
    296  1.1  christos      dynamic.
    297  1.6  christos      2. Use .got.plt in a non-PIC object if pointer equality isn't
    298  1.1  christos      needed.
    299  1.1  christos      3. Use .got.plt in PIE.
    300  1.1  christos      4. Use .got.plt if .got isn't used.
    301  1.1  christos      5. Otherwise use .got so that it can be shared among different
    302  1.1  christos      objects at run-time.
    303  1.6  christos      If PLT isn't used, always use .got for symbol value.
    304  1.6  christos      We only need to relocate .got entry in PIC object or in dynamic
    305  1.6  christos      executable without PLT.  */
    306  1.6  christos   if (use_plt
    307  1.6  christos       && (h->got.refcount <= 0
    308  1.6  christos 	  || (bfd_link_pic (info)
    309  1.6  christos 	      && (h->dynindx == -1
    310  1.6  christos 		  || h->forced_local))
    311  1.6  christos 	  || (!bfd_link_pic (info)
    312  1.6  christos 	      && !h->pointer_equality_needed)
    313  1.6  christos 	  || bfd_link_pie (info)
    314  1.6  christos 	  || htab->sgot == NULL))
    315  1.1  christos     {
    316  1.1  christos       /* Use .got.plt.  */
    317  1.1  christos       h->got.offset = (bfd_vma) -1;
    318  1.1  christos     }
    319  1.1  christos   else
    320  1.1  christos     {
    321  1.6  christos       if (!use_plt)
    322  1.6  christos 	{
    323  1.6  christos 	  /* PLT isn't used.  */
    324  1.6  christos 	  h->plt.offset = (bfd_vma) -1;
    325  1.6  christos 	}
    326  1.6  christos       if (h->got.refcount <= 0)
    327  1.6  christos 	{
    328  1.6  christos 	  /* GOT isn't need when there are only relocations for static
    329  1.6  christos 	     pointers.  */
    330  1.6  christos 	  h->got.offset = (bfd_vma) -1;
    331  1.6  christos 	}
    332  1.6  christos       else
    333  1.6  christos 	{
    334  1.6  christos 	  h->got.offset = htab->sgot->size;
    335  1.6  christos 	  htab->sgot->size += got_entry_size;
    336  1.6  christos 	  /* Need to relocate the GOT entry in a PIC object or PLT isn't
    337  1.6  christos 	     used.  Otherwise, the GOT entry will be filled with the PLT
    338  1.6  christos 	     entry and dynamic GOT relocation isn't needed.  */
    339  1.6  christos 	  if (need_dynreloc)
    340  1.6  christos 	    {
    341  1.6  christos 	      /* For non-static executable, dynamic GOT relocation is in
    342  1.6  christos 		 .rel[a].got section, but for static executable, it is
    343  1.6  christos 		 in .rel[a].iplt section.  */
    344  1.6  christos 	      if (htab->splt != NULL)
    345  1.6  christos 		htab->srelgot->size += sizeof_reloc;
    346  1.6  christos 	      else
    347  1.6  christos 		{
    348  1.6  christos 		  relplt->size += sizeof_reloc;
    349  1.6  christos 		  relplt->reloc_count++;
    350  1.6  christos 		}
    351  1.6  christos 	    }
    352  1.6  christos 	}
    353  1.1  christos     }
    354  1.1  christos 
    355  1.1  christos   return TRUE;
    356  1.1  christos }
    357  1.3  christos 
    358  1.3  christos /* Similar to _bfd_elf_get_synthetic_symtab, optimized for unsorted PLT
    359  1.3  christos    entries.  PLT is the PLT section.  PLT_SYM_VAL is a function pointer
    360  1.3  christos    which returns an array of PLT entry symbol values.  */
    361  1.3  christos 
    362  1.3  christos long
    363  1.3  christos _bfd_elf_ifunc_get_synthetic_symtab
    364  1.3  christos   (bfd *abfd, long symcount ATTRIBUTE_UNUSED,
    365  1.3  christos    asymbol **syms ATTRIBUTE_UNUSED, long dynsymcount, asymbol **dynsyms,
    366  1.3  christos    asymbol **ret, asection *plt,
    367  1.3  christos    bfd_vma *(*get_plt_sym_val) (bfd *, asymbol **, asection *, asection *))
    368  1.3  christos {
    369  1.3  christos   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
    370  1.3  christos   asection *relplt;
    371  1.3  christos   asymbol *s;
    372  1.3  christos   const char *relplt_name;
    373  1.3  christos   bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
    374  1.3  christos   arelent *p;
    375  1.3  christos   long count, i, n;
    376  1.3  christos   size_t size;
    377  1.3  christos   Elf_Internal_Shdr *hdr;
    378  1.3  christos   char *names;
    379  1.3  christos   bfd_vma *plt_sym_val;
    380  1.3  christos 
    381  1.3  christos   *ret = NULL;
    382  1.3  christos 
    383  1.3  christos   if (plt == NULL)
    384  1.3  christos     return 0;
    385  1.3  christos 
    386  1.3  christos   if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
    387  1.3  christos     return 0;
    388  1.3  christos 
    389  1.3  christos   if (dynsymcount <= 0)
    390  1.3  christos     return 0;
    391  1.3  christos 
    392  1.3  christos   relplt_name = bed->relplt_name;
    393  1.3  christos   if (relplt_name == NULL)
    394  1.3  christos     relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt";
    395  1.3  christos   relplt = bfd_get_section_by_name (abfd, relplt_name);
    396  1.3  christos   if (relplt == NULL)
    397  1.3  christos     return 0;
    398  1.3  christos 
    399  1.3  christos   hdr = &elf_section_data (relplt)->this_hdr;
    400  1.3  christos   if (hdr->sh_link != elf_dynsymtab (abfd)
    401  1.3  christos       || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA))
    402  1.3  christos     return 0;
    403  1.3  christos 
    404  1.3  christos   slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
    405  1.3  christos   if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
    406  1.3  christos     return -1;
    407  1.3  christos 
    408  1.3  christos   count = relplt->size / hdr->sh_entsize;
    409  1.3  christos   size = count * sizeof (asymbol);
    410  1.3  christos   p = relplt->relocation;
    411  1.3  christos   for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
    412  1.3  christos     {
    413  1.3  christos       size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
    414  1.3  christos       if (p->addend != 0)
    415  1.3  christos 	{
    416  1.3  christos #ifdef BFD64
    417  1.3  christos 	  size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64);
    418  1.3  christos #else
    419  1.3  christos 	  size += sizeof ("+0x") - 1 + 8;
    420  1.3  christos #endif
    421  1.3  christos 	}
    422  1.3  christos     }
    423  1.3  christos 
    424  1.3  christos   plt_sym_val = get_plt_sym_val (abfd, dynsyms, plt, relplt);
    425  1.3  christos   if (plt_sym_val == NULL)
    426  1.3  christos     return -1;
    427  1.3  christos 
    428  1.3  christos   s = *ret = (asymbol *) bfd_malloc (size);
    429  1.3  christos   if (s == NULL)
    430  1.3  christos     {
    431  1.3  christos       free (plt_sym_val);
    432  1.3  christos       return -1;
    433  1.3  christos     }
    434  1.3  christos 
    435  1.3  christos   names = (char *) (s + count);
    436  1.3  christos   p = relplt->relocation;
    437  1.3  christos   n = 0;
    438  1.3  christos   for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
    439  1.3  christos     {
    440  1.3  christos       size_t len;
    441  1.3  christos       bfd_vma addr;
    442  1.3  christos 
    443  1.3  christos       addr = plt_sym_val[i];
    444  1.3  christos       if (addr == (bfd_vma) -1)
    445  1.3  christos 	continue;
    446  1.3  christos 
    447  1.3  christos       *s = **p->sym_ptr_ptr;
    448  1.3  christos       /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set.  Since
    449  1.3  christos 	 we are defining a symbol, ensure one of them is set.  */
    450  1.3  christos       if ((s->flags & BSF_LOCAL) == 0)
    451  1.3  christos 	s->flags |= BSF_GLOBAL;
    452  1.3  christos       s->flags |= BSF_SYNTHETIC;
    453  1.3  christos       s->section = plt;
    454  1.3  christos       s->value = addr - plt->vma;
    455  1.3  christos       s->name = names;
    456  1.3  christos       s->udata.p = NULL;
    457  1.3  christos       len = strlen ((*p->sym_ptr_ptr)->name);
    458  1.3  christos       memcpy (names, (*p->sym_ptr_ptr)->name, len);
    459  1.3  christos       names += len;
    460  1.3  christos       if (p->addend != 0)
    461  1.3  christos 	{
    462  1.3  christos 	  char buf[30], *a;
    463  1.3  christos 
    464  1.3  christos 	  memcpy (names, "+0x", sizeof ("+0x") - 1);
    465  1.3  christos 	  names += sizeof ("+0x") - 1;
    466  1.3  christos 	  bfd_sprintf_vma (abfd, buf, p->addend);
    467  1.3  christos 	  for (a = buf; *a == '0'; ++a)
    468  1.3  christos 	    ;
    469  1.3  christos 	  len = strlen (a);
    470  1.3  christos 	  memcpy (names, a, len);
    471  1.3  christos 	  names += len;
    472  1.3  christos 	}
    473  1.3  christos       memcpy (names, "@plt", sizeof ("@plt"));
    474  1.3  christos       names += sizeof ("@plt");
    475  1.3  christos       ++s, ++n;
    476  1.3  christos     }
    477  1.3  christos 
    478  1.3  christos   free (plt_sym_val);
    479  1.3  christos 
    480  1.3  christos   return n;
    481  1.3  christos }
    482