Home | History | Annotate | Line # | Download | only in bfd
elf-s390-common.c revision 1.1.1.6
      1      1.1  christos /* IBM S/390-specific support for ELF 32 and 64 bit functions
      2  1.1.1.6  christos    Copyright (C) 2000-2019 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.1.6  christos /* Return true if .got.plt is supposed to be emitted after .got.  */
     34  1.1.1.6  christos 
     35  1.1.1.6  christos static inline bfd_boolean
     36  1.1.1.6  christos s390_gotplt_after_got_p (struct bfd_link_info *info)
     37  1.1.1.6  christos {
     38  1.1.1.6  christos   struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
     39  1.1.1.6  christos 
     40  1.1.1.6  christos   if (!htab->elf.sgot || !htab->elf.sgotplt)
     41  1.1.1.6  christos     return TRUE;
     42  1.1.1.6  christos 
     43  1.1.1.6  christos   if (htab->elf.sgot->output_section == htab->elf.sgotplt->output_section)
     44  1.1.1.6  christos     {
     45  1.1.1.6  christos       if (htab->elf.sgot->output_offset < htab->elf.sgotplt->output_offset)
     46  1.1.1.6  christos 	return TRUE;
     47  1.1.1.6  christos     }
     48  1.1.1.6  christos   else
     49  1.1.1.6  christos     {
     50  1.1.1.6  christos       if (htab->elf.sgot->output_section->vma
     51  1.1.1.6  christos 	  <= htab->elf.sgotplt->output_section->vma)
     52  1.1.1.6  christos 	return TRUE;
     53  1.1.1.6  christos     }
     54  1.1.1.6  christos   return FALSE;
     55  1.1.1.6  christos }
     56  1.1.1.6  christos 
     57  1.1.1.6  christos /* Return the value of the _GLOBAL_OFFSET_TABLE_ symbol.  */
     58  1.1.1.6  christos 
     59  1.1.1.6  christos static inline bfd_vma
     60  1.1.1.6  christos s390_got_pointer (struct bfd_link_info *info)
     61  1.1.1.6  christos {
     62  1.1.1.6  christos   struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
     63  1.1.1.6  christos   bfd_vma got_pointer;
     64  1.1.1.6  christos 
     65  1.1.1.6  christos   BFD_ASSERT (htab && htab->elf.hgot);
     66  1.1.1.6  christos 
     67  1.1.1.6  christos   got_pointer = (htab->elf.hgot->root.u.def.section->output_section->vma
     68  1.1.1.6  christos 		 + htab->elf.hgot->root.u.def.section->output_offset);
     69  1.1.1.6  christos   /* Our ABI requires the GOT pointer to point at the very beginning
     70  1.1.1.6  christos      of the global offset table.  */
     71  1.1.1.6  christos   BFD_ASSERT (got_pointer
     72  1.1.1.6  christos 	      <= (htab->elf.sgot->output_section->vma
     73  1.1.1.6  christos 		  + htab->elf.sgot->output_offset));
     74  1.1.1.6  christos   BFD_ASSERT (got_pointer
     75  1.1.1.6  christos 	      <= (htab->elf.sgotplt->output_section->vma
     76  1.1.1.6  christos 		  + htab->elf.sgotplt->output_offset));
     77  1.1.1.6  christos 
     78  1.1.1.6  christos   return got_pointer;
     79  1.1.1.6  christos }
     80  1.1.1.6  christos 
     81  1.1.1.6  christos 
     82  1.1.1.6  christos /* Return the offset of the .got versus _GLOBAL_OFFSET_TABLE_.  */
     83  1.1.1.6  christos 
     84  1.1.1.6  christos static inline bfd_vma
     85  1.1.1.6  christos s390_got_offset (struct bfd_link_info *info)
     86  1.1.1.6  christos {
     87  1.1.1.6  christos   struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
     88  1.1.1.6  christos 
     89  1.1.1.6  christos   /* The absolute address of the .got in the target image.  */
     90  1.1.1.6  christos   bfd_vma got_address = (htab->elf.sgot->output_section->vma
     91  1.1.1.6  christos 			 + htab->elf.sgot->output_offset);
     92  1.1.1.6  christos 
     93  1.1.1.6  christos   /* GOT offset must not be negative.  */
     94  1.1.1.6  christos   BFD_ASSERT (s390_got_pointer (info) <= got_address);
     95  1.1.1.6  christos   return got_address - s390_got_pointer (info);
     96  1.1.1.6  christos }
     97  1.1.1.6  christos 
     98  1.1.1.6  christos /* Return the offset of the .got.plt versus _GLOBAL_OFFSET_TABLE_.  */
     99  1.1.1.6  christos 
    100  1.1.1.6  christos static inline bfd_vma
    101  1.1.1.6  christos s390_gotplt_offset (struct bfd_link_info *info)
    102  1.1.1.6  christos {
    103  1.1.1.6  christos   struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
    104  1.1.1.6  christos 
    105  1.1.1.6  christos   /* The absolute address of the .got.plt in the target image.  */
    106  1.1.1.6  christos   bfd_vma gotplt_address = (htab->elf.sgotplt->output_section->vma
    107  1.1.1.6  christos 			    + htab->elf.sgotplt->output_offset);
    108  1.1.1.6  christos 
    109  1.1.1.6  christos   /* GOT offset must not be negative.  */
    110  1.1.1.6  christos   BFD_ASSERT (s390_got_pointer (info) <= gotplt_address);
    111  1.1.1.6  christos   return gotplt_address - s390_got_pointer (info);
    112  1.1.1.6  christos }
    113  1.1.1.6  christos 
    114      1.1  christos /* Create sections needed by STT_GNU_IFUNC symbol.  */
    115      1.1  christos 
    116      1.1  christos static bfd_boolean
    117      1.1  christos s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
    118      1.1  christos {
    119      1.1  christos   flagword flags;
    120      1.1  christos   asection *s;
    121      1.1  christos   const struct elf_backend_data *bed = get_elf_backend_data (abfd);
    122      1.1  christos   struct elf_link_hash_table *htab = elf_hash_table (info);
    123      1.1  christos 
    124      1.1  christos   if (htab->iplt != NULL)
    125      1.1  christos     return TRUE;
    126      1.1  christos 
    127      1.1  christos   flags = bed->dynamic_sec_flags;
    128      1.1  christos 
    129  1.1.1.4  christos   if (bfd_link_pic (info))
    130      1.1  christos     {
    131      1.1  christos       s = bfd_make_section_with_flags (abfd, ".rela.ifunc",
    132      1.1  christos 				       flags | SEC_READONLY);
    133      1.1  christos       if (s == NULL
    134      1.1  christos 	  || ! bfd_set_section_alignment (abfd, s,
    135      1.1  christos 					  bed->s->log_file_align))
    136      1.1  christos 	return FALSE;
    137      1.1  christos       htab->irelifunc = s;
    138      1.1  christos     }
    139      1.1  christos 
    140      1.1  christos   /* Create .iplt, .rel[a].iplt, and .igot.plt.  */
    141      1.1  christos   s = bfd_make_section_with_flags (abfd, ".iplt",
    142      1.1  christos 				   flags | SEC_CODE | SEC_READONLY);
    143      1.1  christos   if (s == NULL
    144      1.1  christos       || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
    145      1.1  christos     return FALSE;
    146      1.1  christos   htab->iplt = s;
    147      1.1  christos 
    148      1.1  christos   s = bfd_make_section_with_flags (abfd, ".rela.iplt", flags | SEC_READONLY);
    149      1.1  christos   if (s == NULL
    150      1.1  christos       || ! bfd_set_section_alignment (abfd, s,
    151      1.1  christos 				      bed->s->log_file_align))
    152      1.1  christos     return FALSE;
    153      1.1  christos   htab->irelplt = s;
    154      1.1  christos 
    155      1.1  christos   s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
    156      1.1  christos   if (s == NULL
    157      1.1  christos       || !bfd_set_section_alignment (abfd, s,
    158      1.1  christos 				     bed->s->log_file_align))
    159      1.1  christos     return FALSE;
    160      1.1  christos   htab->igotplt = s;
    161      1.1  christos 
    162      1.1  christos   return TRUE;
    163      1.1  christos }
    164      1.1  christos 
    165      1.1  christos 
    166      1.1  christos /* Allocate space in .plt, .got and associated reloc sections for
    167      1.1  christos    dynamic relocs against a STT_GNU_IFUNC symbol definition.  */
    168      1.1  christos 
    169      1.1  christos static bfd_boolean
    170      1.1  christos s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
    171  1.1.1.4  christos 				    struct elf_link_hash_entry *h)
    172      1.1  christos {
    173      1.1  christos   struct elf_dyn_relocs *p;
    174      1.1  christos   struct elf_link_hash_table *htab;
    175      1.1  christos   struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h;
    176  1.1.1.4  christos   struct elf_dyn_relocs **head = &eh->dyn_relocs;
    177      1.1  christos 
    178      1.1  christos   htab = elf_hash_table (info);
    179      1.1  christos   eh->ifunc_resolver_address = h->root.u.def.value;
    180      1.1  christos   eh->ifunc_resolver_section = h->root.u.def.section;
    181      1.1  christos 
    182      1.1  christos   /* Support garbage collection against STT_GNU_IFUNC symbols.  */
    183      1.1  christos   if (h->plt.refcount <= 0 && h->got.refcount <= 0)
    184      1.1  christos     {
    185      1.1  christos       /* When building shared library, we need to handle the case
    186  1.1.1.6  christos 	 where it is marked with regular reference, but not non-GOT
    187      1.1  christos 	 reference.  It may happen if we didn't see STT_GNU_IFUNC
    188      1.1  christos 	 symbol at the time when checking relocations.  */
    189  1.1.1.4  christos       if (bfd_link_pic (info)
    190      1.1  christos 	  && !h->non_got_ref
    191      1.1  christos 	  && h->ref_regular)
    192      1.1  christos 	for (p = *head; p != NULL; p = p->next)
    193      1.1  christos 	  if (p->count)
    194      1.1  christos 	    {
    195      1.1  christos 	      h->non_got_ref = 1;
    196      1.1  christos 	      goto keep;
    197      1.1  christos 	    }
    198      1.1  christos 
    199      1.1  christos       h->got = htab->init_got_offset;
    200      1.1  christos       h->plt = htab->init_plt_offset;
    201      1.1  christos       *head = NULL;
    202      1.1  christos       return TRUE;
    203      1.1  christos     }
    204      1.1  christos 
    205      1.1  christos   /* Return and discard space for dynamic relocations against it if
    206      1.1  christos      it is never referenced in a non-shared object.  */
    207      1.1  christos   if (!h->ref_regular)
    208      1.1  christos     {
    209      1.1  christos       if (h->plt.refcount > 0
    210      1.1  christos 	  || h->got.refcount > 0)
    211      1.1  christos 	abort ();
    212      1.1  christos       h->got = htab->init_got_offset;
    213      1.1  christos       h->plt = htab->init_plt_offset;
    214      1.1  christos       *head = NULL;
    215      1.1  christos       return TRUE;
    216      1.1  christos     }
    217      1.1  christos 
    218      1.1  christos keep:
    219      1.1  christos   /* Without checking h->plt.refcount here we allocate a PLT slot.
    220      1.1  christos      When setting plt.refcount in check_relocs it might not have been
    221      1.1  christos      known that this will be an IFUNC symol.  */
    222      1.1  christos   h->plt.offset = htab->iplt->size;
    223      1.1  christos   h->needs_plt = 1;
    224      1.1  christos   htab->iplt->size += PLT_ENTRY_SIZE;
    225      1.1  christos   htab->igotplt->size += GOT_ENTRY_SIZE;
    226      1.1  christos   htab->irelplt->size += RELA_ENTRY_SIZE;
    227      1.1  christos   htab->irelplt->reloc_count++;
    228      1.1  christos 
    229      1.1  christos   /* In order to make pointer equality work with IFUNC symbols defined
    230      1.1  christos      in a non-PIE executable and referenced in a shared lib, we turn
    231      1.1  christos      the symbol into a STT_FUNC symbol and make the symbol value to
    232      1.1  christos      point to the IPLT slot.  That way the referencing shared lib will
    233      1.1  christos      always get the PLT slot address when resolving the respective
    234      1.1  christos      R_390_GLOB_DAT/R_390_64 relocs on that symbol.  */
    235  1.1.1.4  christos   if (bfd_link_pde (info)
    236  1.1.1.4  christos       && h->def_regular
    237  1.1.1.4  christos       && h->ref_dynamic)
    238      1.1  christos     {
    239      1.1  christos       h->root.u.def.section = htab->iplt;
    240      1.1  christos       h->root.u.def.value = h->plt.offset;
    241      1.1  christos       h->size = PLT_ENTRY_SIZE;
    242      1.1  christos       h->type = STT_FUNC;
    243      1.1  christos     }
    244      1.1  christos 
    245  1.1.1.6  christos   if (!bfd_link_pic (info))
    246      1.1  christos     *head = NULL;
    247      1.1  christos 
    248      1.1  christos   /* Finally, allocate space.  */
    249      1.1  christos   p = *head;
    250      1.1  christos   if (p != NULL)
    251      1.1  christos     {
    252      1.1  christos       bfd_size_type count = 0;
    253      1.1  christos       do
    254      1.1  christos 	{
    255      1.1  christos 	  count += p->count;
    256      1.1  christos 	  p = p->next;
    257      1.1  christos 	}
    258      1.1  christos       while (p != NULL);
    259      1.1  christos       htab->irelifunc->size += count * RELA_ENTRY_SIZE;
    260      1.1  christos     }
    261      1.1  christos 
    262      1.1  christos   /* Decide whether the got.iplt slot can be used.  This has to be
    263      1.1  christos      avoided if the values in the GOT slots could differ for pointer
    264      1.1  christos      equality reasons.  */
    265      1.1  christos   if (h->got.refcount <= 0
    266  1.1.1.4  christos       || (bfd_link_pic (info)
    267      1.1  christos 	  && (h->dynindx == -1 || h->forced_local))
    268  1.1.1.4  christos       || bfd_link_pie (info)
    269      1.1  christos       || htab->sgot == NULL)
    270      1.1  christos     {
    271      1.1  christos       /* Use .got.iplt.  */
    272      1.1  christos       h->got.offset = (bfd_vma) -1;
    273      1.1  christos     }
    274      1.1  christos   else
    275      1.1  christos     {
    276      1.1  christos       h->got.offset = htab->sgot->size;
    277      1.1  christos       htab->sgot->size += GOT_ENTRY_SIZE;
    278  1.1.1.4  christos       if (bfd_link_pic (info))
    279      1.1  christos 	htab->srelgot->size += RELA_ENTRY_SIZE;
    280      1.1  christos     }
    281      1.1  christos 
    282      1.1  christos   return TRUE;
    283      1.1  christos }
    284      1.1  christos 
    285      1.1  christos static bfd_boolean
    286      1.1  christos elf_s390_allocate_local_syminfo (bfd *abfd, Elf_Internal_Shdr *symtab_hdr)
    287      1.1  christos {
    288      1.1  christos   bfd_size_type size;
    289      1.1  christos 
    290      1.1  christos   size = symtab_hdr->sh_info;
    291  1.1.1.6  christos   size *= (sizeof (bfd_signed_vma)	 /* local got */
    292  1.1.1.6  christos 	   + sizeof (struct plt_entry)	 /* local plt */
    293  1.1.1.6  christos 	   + sizeof(char));		 /* local tls type */
    294      1.1  christos   elf_local_got_refcounts (abfd) = ((bfd_signed_vma *)
    295      1.1  christos 				    bfd_zalloc (abfd, size));
    296      1.1  christos   if (elf_local_got_refcounts (abfd) == NULL)
    297      1.1  christos     return FALSE;
    298      1.1  christos   elf_s390_local_plt (abfd)
    299      1.1  christos     = (struct plt_entry*)(elf_local_got_refcounts (abfd)
    300      1.1  christos 			  + symtab_hdr->sh_info);
    301      1.1  christos   elf_s390_local_got_tls_type (abfd)
    302      1.1  christos     = (char *) (elf_s390_local_plt (abfd) + symtab_hdr->sh_info);
    303      1.1  christos 
    304      1.1  christos   return TRUE;
    305      1.1  christos }
    306      1.1  christos 
    307  1.1.1.3  christos /* Whether to sort relocs output by ld -r or ld --emit-relocs, by
    308  1.1.1.3  christos    r_offset.  Don't do so for code sections.  We want to keep ordering
    309  1.1.1.3  christos    of GDCALL / PLT32DBL for TLS optimizations as is.  On the other
    310  1.1.1.3  christos    hand, elf-eh-frame.c processing requires .eh_frame relocs to be
    311  1.1.1.3  christos    sorted.  */
    312  1.1.1.3  christos 
    313  1.1.1.3  christos static bfd_boolean
    314  1.1.1.3  christos elf_s390_elf_sort_relocs_p (asection *sec)
    315  1.1.1.3  christos {
    316  1.1.1.3  christos   return (sec->flags & SEC_CODE) == 0;
    317  1.1.1.3  christos }
    318  1.1.1.3  christos 
    319  1.1.1.3  christos /* Merge object attributes from IBFD into OBFD.  Raise an error if
    320  1.1.1.3  christos    there are conflicting attributes.  */
    321  1.1.1.3  christos static bfd_boolean
    322  1.1.1.5  christos elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
    323  1.1.1.3  christos {
    324  1.1.1.5  christos   bfd *obfd = info->output_bfd;
    325  1.1.1.3  christos   obj_attribute *in_attr, *in_attrs;
    326  1.1.1.3  christos   obj_attribute *out_attr, *out_attrs;
    327  1.1.1.3  christos 
    328  1.1.1.3  christos   if (!elf_known_obj_attributes_proc (obfd)[0].i)
    329  1.1.1.3  christos     {
    330  1.1.1.3  christos       /* This is the first object.  Copy the attributes.  */
    331  1.1.1.3  christos       _bfd_elf_copy_obj_attributes (ibfd, obfd);
    332  1.1.1.3  christos 
    333  1.1.1.3  christos       /* Use the Tag_null value to indicate the attributes have been
    334  1.1.1.3  christos 	 initialized.  */
    335  1.1.1.3  christos       elf_known_obj_attributes_proc (obfd)[0].i = 1;
    336  1.1.1.3  christos 
    337  1.1.1.3  christos       return TRUE;
    338  1.1.1.3  christos     }
    339  1.1.1.3  christos 
    340  1.1.1.3  christos   in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
    341  1.1.1.3  christos   out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
    342  1.1.1.3  christos 
    343  1.1.1.3  christos   /* Check for conflicting Tag_GNU_S390_ABI_Vector attributes and
    344  1.1.1.3  christos      merge non-conflicting ones.  */
    345  1.1.1.3  christos   in_attr = &in_attrs[Tag_GNU_S390_ABI_Vector];
    346  1.1.1.3  christos   out_attr = &out_attrs[Tag_GNU_S390_ABI_Vector];
    347  1.1.1.3  christos 
    348  1.1.1.3  christos   if (in_attr->i > 2)
    349  1.1.1.3  christos     _bfd_error_handler
    350  1.1.1.5  christos       /* xgettext:c-format */
    351  1.1.1.6  christos       (_("warning: %pB uses unknown vector ABI %d"), ibfd,
    352  1.1.1.3  christos        in_attr->i);
    353  1.1.1.3  christos   else if (out_attr->i > 2)
    354  1.1.1.3  christos     _bfd_error_handler
    355  1.1.1.5  christos       /* xgettext:c-format */
    356  1.1.1.6  christos       (_("warning: %pB uses unknown vector ABI %d"), obfd,
    357  1.1.1.3  christos        out_attr->i);
    358  1.1.1.3  christos   else if (in_attr->i != out_attr->i)
    359  1.1.1.3  christos     {
    360  1.1.1.3  christos       out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
    361  1.1.1.3  christos 
    362  1.1.1.3  christos       if (in_attr->i && out_attr->i)
    363  1.1.1.3  christos 	{
    364  1.1.1.3  christos 	  const char abi_str[3][9] = { "none", "software", "hardware" };
    365  1.1.1.3  christos 
    366  1.1.1.3  christos 	  _bfd_error_handler
    367  1.1.1.5  christos 	    /* xgettext:c-format */
    368  1.1.1.6  christos 	    (_("warning: %pB uses vector %s ABI, %pB uses %s ABI"),
    369  1.1.1.5  christos 	     ibfd, abi_str[in_attr->i], obfd, abi_str[out_attr->i]);
    370  1.1.1.3  christos 	}
    371  1.1.1.3  christos       if (in_attr->i > out_attr->i)
    372  1.1.1.3  christos 	out_attr->i = in_attr->i;
    373  1.1.1.3  christos     }
    374  1.1.1.3  christos 
    375  1.1.1.3  christos   /* Merge Tag_compatibility attributes and any common GNU ones.  */
    376  1.1.1.5  christos   _bfd_elf_merge_object_attributes (ibfd, info);
    377  1.1.1.3  christos 
    378  1.1.1.3  christos   return TRUE;
    379  1.1.1.3  christos }
    380