Coverage Report

Created: 2025-06-24 06:45

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