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