Home | History | Annotate | Line # | Download | only in bfd
elf-s390-common.c revision 1.1.1.5
      1      1.1  christos /* IBM S/390-specific support for ELF 32 and 64 bit functions
      2  1.1.1.5  christos    Copyright (C) 2000-2017 Free Software Foundation, Inc.
      3      1.1  christos    Contributed by Andreas Krebbel.
      4      1.1  christos 
      5      1.1  christos    This file is part of BFD, the Binary File Descriptor library.
      6      1.1  christos 
      7      1.1  christos    This program is free software; you can redistribute it and/or modify
      8      1.1  christos    it under the terms of the GNU General Public License as published by
      9      1.1  christos    the Free Software Foundation; either version 3 of the License, or
     10      1.1  christos    (at your option) any later version.
     11      1.1  christos 
     12      1.1  christos    This program is distributed in the hope that it will be useful,
     13      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15      1.1  christos    GNU General Public License for more details.
     16      1.1  christos 
     17      1.1  christos    You should have received a copy of the GNU General Public License
     18      1.1  christos    along with this program; if not, write to the Free Software
     19      1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
     20      1.1  christos    02110-1301, USA.  */
     21      1.1  christos 
     22      1.1  christos 
     23      1.1  christos /* Return TRUE if H is an IFUNC symbol.  Simply checking for the
     24      1.1  christos    symbol type might not be enough since it might get changed to
     25      1.1  christos    STT_FUNC for pointer equality reasons.  */
     26      1.1  christos static inline bfd_boolean
     27      1.1  christos s390_is_ifunc_symbol_p (struct elf_link_hash_entry *h)
     28      1.1  christos {
     29      1.1  christos   struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h;
     30      1.1  christos   return h->type == STT_GNU_IFUNC || eh->ifunc_resolver_address != 0;
     31      1.1  christos }
     32      1.1  christos 
     33      1.1  christos /* Create sections needed by STT_GNU_IFUNC symbol.  */
     34      1.1  christos 
     35      1.1  christos static bfd_boolean
     36      1.1  christos s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
     37      1.1  christos {
     38      1.1  christos   flagword flags;
     39      1.1  christos   asection *s;
     40      1.1  christos   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
     41      1.1  christos   struct elf_link_hash_table *htab = elf_hash_table (info);
     42      1.1  christos 
     43      1.1  christos   if (htab->iplt != NULL)
     44      1.1  christos     return TRUE;
     45      1.1  christos 
     46      1.1  christos   flags = bed->dynamic_sec_flags;
     47      1.1  christos 
     48  1.1.1.4  christos   if (bfd_link_pic (info))
     49      1.1  christos     {
     50      1.1  christos       s = bfd_make_section_with_flags (abfd, ".rela.ifunc",
     51      1.1  christos 				       flags | SEC_READONLY);
     52      1.1  christos       if (s == NULL
     53      1.1  christos 	  || ! bfd_set_section_alignment (abfd, s,
     54      1.1  christos 					  bed->s->log_file_align))
     55      1.1  christos 	return FALSE;
     56      1.1  christos       htab->irelifunc = s;
     57      1.1  christos     }
     58      1.1  christos 
     59      1.1  christos   /* Create .iplt, .rel[a].iplt, and .igot.plt.  */
     60      1.1  christos   s = bfd_make_section_with_flags (abfd, ".iplt",
     61      1.1  christos 				   flags | SEC_CODE | SEC_READONLY);
     62      1.1  christos   if (s == NULL
     63      1.1  christos       || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
     64      1.1  christos     return FALSE;
     65      1.1  christos   htab->iplt = s;
     66      1.1  christos 
     67      1.1  christos   s = bfd_make_section_with_flags (abfd, ".rela.iplt", flags | SEC_READONLY);
     68      1.1  christos   if (s == NULL
     69      1.1  christos       || ! bfd_set_section_alignment (abfd, s,
     70      1.1  christos 				      bed->s->log_file_align))
     71      1.1  christos     return FALSE;
     72      1.1  christos   htab->irelplt = s;
     73      1.1  christos 
     74      1.1  christos   s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
     75      1.1  christos   if (s == NULL
     76      1.1  christos       || !bfd_set_section_alignment (abfd, s,
     77      1.1  christos 				     bed->s->log_file_align))
     78      1.1  christos     return FALSE;
     79      1.1  christos   htab->igotplt = s;
     80      1.1  christos 
     81      1.1  christos   return TRUE;
     82      1.1  christos }
     83      1.1  christos 
     84      1.1  christos 
     85      1.1  christos /* Allocate space in .plt, .got and associated reloc sections for
     86      1.1  christos    dynamic relocs against a STT_GNU_IFUNC symbol definition.  */
     87      1.1  christos 
     88      1.1  christos static bfd_boolean
     89      1.1  christos s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
     90  1.1.1.4  christos 				    struct elf_link_hash_entry *h)
     91      1.1  christos {
     92      1.1  christos   struct elf_dyn_relocs *p;
     93      1.1  christos   struct elf_link_hash_table *htab;
     94      1.1  christos   struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h;
     95  1.1.1.4  christos   struct elf_dyn_relocs **head = &eh->dyn_relocs;
     96      1.1  christos 
     97      1.1  christos   htab = elf_hash_table (info);
     98      1.1  christos   eh->ifunc_resolver_address = h->root.u.def.value;
     99      1.1  christos   eh->ifunc_resolver_section = h->root.u.def.section;
    100      1.1  christos 
    101      1.1  christos   /* Support garbage collection against STT_GNU_IFUNC symbols.  */
    102      1.1  christos   if (h->plt.refcount <= 0 && h->got.refcount <= 0)
    103      1.1  christos     {
    104      1.1  christos       /* When building shared library, we need to handle the case
    105      1.1  christos          where it is marked with regular reference, but not non-GOT
    106      1.1  christos 	 reference.  It may happen if we didn't see STT_GNU_IFUNC
    107      1.1  christos 	 symbol at the time when checking relocations.  */
    108  1.1.1.4  christos       if (bfd_link_pic (info)
    109      1.1  christos 	  && !h->non_got_ref
    110      1.1  christos 	  && h->ref_regular)
    111      1.1  christos 	for (p = *head; p != NULL; p = p->next)
    112      1.1  christos 	  if (p->count)
    113      1.1  christos 	    {
    114      1.1  christos 	      h->non_got_ref = 1;
    115      1.1  christos 	      goto keep;
    116      1.1  christos 	    }
    117      1.1  christos 
    118      1.1  christos       h->got = htab->init_got_offset;
    119      1.1  christos       h->plt = htab->init_plt_offset;
    120      1.1  christos       *head = NULL;
    121      1.1  christos       return TRUE;
    122      1.1  christos     }
    123      1.1  christos 
    124      1.1  christos   /* Return and discard space for dynamic relocations against it if
    125      1.1  christos      it is never referenced in a non-shared object.  */
    126      1.1  christos   if (!h->ref_regular)
    127      1.1  christos     {
    128      1.1  christos       if (h->plt.refcount > 0
    129      1.1  christos 	  || h->got.refcount > 0)
    130      1.1  christos 	abort ();
    131      1.1  christos       h->got = htab->init_got_offset;
    132      1.1  christos       h->plt = htab->init_plt_offset;
    133      1.1  christos       *head = NULL;
    134      1.1  christos       return TRUE;
    135      1.1  christos     }
    136      1.1  christos 
    137      1.1  christos keep:
    138      1.1  christos   /* Without checking h->plt.refcount here we allocate a PLT slot.
    139      1.1  christos      When setting plt.refcount in check_relocs it might not have been
    140      1.1  christos      known that this will be an IFUNC symol.  */
    141      1.1  christos   h->plt.offset = htab->iplt->size;
    142      1.1  christos   h->needs_plt = 1;
    143      1.1  christos   htab->iplt->size += PLT_ENTRY_SIZE;
    144      1.1  christos   htab->igotplt->size += GOT_ENTRY_SIZE;
    145      1.1  christos   htab->irelplt->size += RELA_ENTRY_SIZE;
    146      1.1  christos   htab->irelplt->reloc_count++;
    147      1.1  christos 
    148      1.1  christos   /* In order to make pointer equality work with IFUNC symbols defined
    149      1.1  christos      in a non-PIE executable and referenced in a shared lib, we turn
    150      1.1  christos      the symbol into a STT_FUNC symbol and make the symbol value to
    151      1.1  christos      point to the IPLT slot.  That way the referencing shared lib will
    152      1.1  christos      always get the PLT slot address when resolving the respective
    153      1.1  christos      R_390_GLOB_DAT/R_390_64 relocs on that symbol.  */
    154  1.1.1.4  christos   if (bfd_link_pde (info)
    155  1.1.1.4  christos       && h->def_regular
    156  1.1.1.4  christos       && h->ref_dynamic)
    157      1.1  christos     {
    158      1.1  christos       h->root.u.def.section = htab->iplt;
    159      1.1  christos       h->root.u.def.value = h->plt.offset;
    160      1.1  christos       h->size = PLT_ENTRY_SIZE;
    161      1.1  christos       h->type = STT_FUNC;
    162      1.1  christos     }
    163      1.1  christos 
    164      1.1  christos   /* We need dynamic relocation for STT_GNU_IFUNC symbol only when
    165      1.1  christos      there is a non-GOT reference in a shared object.  */
    166  1.1.1.4  christos   if (!bfd_link_pic (info) || !h->non_got_ref)
    167      1.1  christos     *head = NULL;
    168      1.1  christos 
    169      1.1  christos   /* Finally, allocate space.  */
    170      1.1  christos   p = *head;
    171      1.1  christos   if (p != NULL)
    172      1.1  christos     {
    173      1.1  christos       bfd_size_type count = 0;
    174      1.1  christos       do
    175      1.1  christos 	{
    176      1.1  christos 	  count += p->count;
    177      1.1  christos 	  p = p->next;
    178      1.1  christos 	}
    179      1.1  christos       while (p != NULL);
    180      1.1  christos       htab->irelifunc->size += count * RELA_ENTRY_SIZE;
    181      1.1  christos     }
    182      1.1  christos 
    183      1.1  christos   /* Decide whether the got.iplt slot can be used.  This has to be
    184      1.1  christos      avoided if the values in the GOT slots could differ for pointer
    185      1.1  christos      equality reasons.  */
    186      1.1  christos   if (h->got.refcount <= 0
    187  1.1.1.4  christos       || (bfd_link_pic (info)
    188      1.1  christos 	  && (h->dynindx == -1 || h->forced_local))
    189  1.1.1.4  christos       || bfd_link_pie (info)
    190      1.1  christos       || htab->sgot == NULL)
    191      1.1  christos     {
    192      1.1  christos       /* Use .got.iplt.  */
    193      1.1  christos       h->got.offset = (bfd_vma) -1;
    194      1.1  christos     }
    195      1.1  christos   else
    196      1.1  christos     {
    197      1.1  christos       h->got.offset = htab->sgot->size;
    198      1.1  christos       htab->sgot->size += GOT_ENTRY_SIZE;
    199  1.1.1.4  christos       if (bfd_link_pic (info))
    200      1.1  christos 	htab->srelgot->size += RELA_ENTRY_SIZE;
    201      1.1  christos     }
    202      1.1  christos 
    203      1.1  christos   return TRUE;
    204      1.1  christos }
    205      1.1  christos 
    206      1.1  christos static bfd_boolean
    207      1.1  christos elf_s390_allocate_local_syminfo (bfd *abfd, Elf_Internal_Shdr *symtab_hdr)
    208      1.1  christos {
    209      1.1  christos   bfd_size_type size;
    210      1.1  christos 
    211      1.1  christos   size = symtab_hdr->sh_info;
    212      1.1  christos   size *= (sizeof (bfd_signed_vma)       /* local got */
    213      1.1  christos 	   + sizeof (struct plt_entry)   /* local plt */
    214      1.1  christos 	   + sizeof(char));              /* local tls type */
    215      1.1  christos   elf_local_got_refcounts (abfd) = ((bfd_signed_vma *)
    216      1.1  christos 				    bfd_zalloc (abfd, size));
    217      1.1  christos   if (elf_local_got_refcounts (abfd) == NULL)
    218      1.1  christos     return FALSE;
    219      1.1  christos   elf_s390_local_plt (abfd)
    220      1.1  christos     = (struct plt_entry*)(elf_local_got_refcounts (abfd)
    221      1.1  christos 			  + symtab_hdr->sh_info);
    222      1.1  christos   elf_s390_local_got_tls_type (abfd)
    223      1.1  christos     = (char *) (elf_s390_local_plt (abfd) + symtab_hdr->sh_info);
    224      1.1  christos 
    225      1.1  christos   return TRUE;
    226      1.1  christos }
    227      1.1  christos 
    228      1.1  christos /* Pick ELFOSABI_GNU if IFUNC symbols are used.  */
    229      1.1  christos 
    230      1.1  christos static bfd_boolean
    231      1.1  christos elf_s390_add_symbol_hook (bfd *abfd,
    232      1.1  christos 			  struct bfd_link_info *info,
    233      1.1  christos 			  Elf_Internal_Sym *sym,
    234      1.1  christos 			  const char **namep ATTRIBUTE_UNUSED,
    235      1.1  christos 			  flagword *flagsp ATTRIBUTE_UNUSED,
    236      1.1  christos 			  asection **secp ATTRIBUTE_UNUSED,
    237      1.1  christos 			  bfd_vma *valp ATTRIBUTE_UNUSED)
    238      1.1  christos {
    239  1.1.1.4  christos   if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
    240  1.1.1.2  christos       && (abfd->flags & DYNAMIC) == 0
    241  1.1.1.2  christos       && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
    242  1.1.1.4  christos     elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
    243      1.1  christos 
    244      1.1  christos   return TRUE;
    245      1.1  christos }
    246  1.1.1.3  christos 
    247  1.1.1.3  christos /* Whether to sort relocs output by ld -r or ld --emit-relocs, by
    248  1.1.1.3  christos    r_offset.  Don't do so for code sections.  We want to keep ordering
    249  1.1.1.3  christos    of GDCALL / PLT32DBL for TLS optimizations as is.  On the other
    250  1.1.1.3  christos    hand, elf-eh-frame.c processing requires .eh_frame relocs to be
    251  1.1.1.3  christos    sorted.  */
    252  1.1.1.3  christos 
    253  1.1.1.3  christos static bfd_boolean
    254  1.1.1.3  christos elf_s390_elf_sort_relocs_p (asection *sec)
    255  1.1.1.3  christos {
    256  1.1.1.3  christos   return (sec->flags & SEC_CODE) == 0;
    257  1.1.1.3  christos }
    258  1.1.1.3  christos 
    259  1.1.1.3  christos /* Merge object attributes from IBFD into OBFD.  Raise an error if
    260  1.1.1.3  christos    there are conflicting attributes.  */
    261  1.1.1.3  christos static bfd_boolean
    262  1.1.1.5  christos elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
    263  1.1.1.3  christos {
    264  1.1.1.5  christos   bfd *obfd = info->output_bfd;
    265  1.1.1.3  christos   obj_attribute *in_attr, *in_attrs;
    266  1.1.1.3  christos   obj_attribute *out_attr, *out_attrs;
    267  1.1.1.3  christos 
    268  1.1.1.3  christos   if (!elf_known_obj_attributes_proc (obfd)[0].i)
    269  1.1.1.3  christos     {
    270  1.1.1.3  christos       /* This is the first object.  Copy the attributes.  */
    271  1.1.1.3  christos       _bfd_elf_copy_obj_attributes (ibfd, obfd);
    272  1.1.1.3  christos 
    273  1.1.1.3  christos       /* Use the Tag_null value to indicate the attributes have been
    274  1.1.1.3  christos 	 initialized.  */
    275  1.1.1.3  christos       elf_known_obj_attributes_proc (obfd)[0].i = 1;
    276  1.1.1.3  christos 
    277  1.1.1.3  christos       return TRUE;
    278  1.1.1.3  christos     }
    279  1.1.1.3  christos 
    280  1.1.1.3  christos   in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
    281  1.1.1.3  christos   out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
    282  1.1.1.3  christos 
    283  1.1.1.3  christos   /* Check for conflicting Tag_GNU_S390_ABI_Vector attributes and
    284  1.1.1.3  christos      merge non-conflicting ones.  */
    285  1.1.1.3  christos   in_attr = &in_attrs[Tag_GNU_S390_ABI_Vector];
    286  1.1.1.3  christos   out_attr = &out_attrs[Tag_GNU_S390_ABI_Vector];
    287  1.1.1.3  christos 
    288  1.1.1.3  christos   if (in_attr->i > 2)
    289  1.1.1.3  christos     _bfd_error_handler
    290  1.1.1.5  christos       /* xgettext:c-format */
    291  1.1.1.3  christos       (_("Warning: %B uses unknown vector ABI %d"), ibfd,
    292  1.1.1.3  christos        in_attr->i);
    293  1.1.1.3  christos   else if (out_attr->i > 2)
    294  1.1.1.3  christos     _bfd_error_handler
    295  1.1.1.5  christos       /* xgettext:c-format */
    296  1.1.1.3  christos       (_("Warning: %B uses unknown vector ABI %d"), obfd,
    297  1.1.1.3  christos        out_attr->i);
    298  1.1.1.3  christos   else if (in_attr->i != out_attr->i)
    299  1.1.1.3  christos     {
    300  1.1.1.3  christos       out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
    301  1.1.1.3  christos 
    302  1.1.1.3  christos       if (in_attr->i && out_attr->i)
    303  1.1.1.3  christos 	{
    304  1.1.1.3  christos 	  const char abi_str[3][9] = { "none", "software", "hardware" };
    305  1.1.1.3  christos 
    306  1.1.1.3  christos 	  _bfd_error_handler
    307  1.1.1.5  christos 	    /* xgettext:c-format */
    308  1.1.1.3  christos 	    (_("Warning: %B uses vector %s ABI, %B uses %s ABI"),
    309  1.1.1.5  christos 	     ibfd, abi_str[in_attr->i], obfd, abi_str[out_attr->i]);
    310  1.1.1.3  christos 	}
    311  1.1.1.3  christos       if (in_attr->i > out_attr->i)
    312  1.1.1.3  christos 	out_attr->i = in_attr->i;
    313  1.1.1.3  christos     }
    314  1.1.1.3  christos 
    315  1.1.1.3  christos   /* Merge Tag_compatibility attributes and any common GNU ones.  */
    316  1.1.1.5  christos   _bfd_elf_merge_object_attributes (ibfd, info);
    317  1.1.1.3  christos 
    318  1.1.1.3  christos   return TRUE;
    319  1.1.1.3  christos }
    320