1a1ba9ba4Schristos /* IBM S/390-specific support for ELF 32 and 64 bit functions
2*184b2d41Schristos Copyright (C) 2000-2020 Free Software Foundation, Inc.
3a1ba9ba4Schristos Contributed by Andreas Krebbel.
4a1ba9ba4Schristos
5a1ba9ba4Schristos This file is part of BFD, the Binary File Descriptor library.
6a1ba9ba4Schristos
7a1ba9ba4Schristos This program is free software; you can redistribute it and/or modify
8a1ba9ba4Schristos it under the terms of the GNU General Public License as published by
9a1ba9ba4Schristos the Free Software Foundation; either version 3 of the License, or
10a1ba9ba4Schristos (at your option) any later version.
11a1ba9ba4Schristos
12a1ba9ba4Schristos This program is distributed in the hope that it will be useful,
13a1ba9ba4Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
14a1ba9ba4Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15a1ba9ba4Schristos GNU General Public License for more details.
16a1ba9ba4Schristos
17a1ba9ba4Schristos You should have received a copy of the GNU General Public License
18a1ba9ba4Schristos along with this program; if not, write to the Free Software
19a1ba9ba4Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
20a1ba9ba4Schristos 02110-1301, USA. */
21a1ba9ba4Schristos
22a1ba9ba4Schristos
23a1ba9ba4Schristos /* Return TRUE if H is an IFUNC symbol. Simply checking for the
24a1ba9ba4Schristos symbol type might not be enough since it might get changed to
25a1ba9ba4Schristos STT_FUNC for pointer equality reasons. */
26a1ba9ba4Schristos static inline bfd_boolean
s390_is_ifunc_symbol_p(struct elf_link_hash_entry * h)27a1ba9ba4Schristos s390_is_ifunc_symbol_p (struct elf_link_hash_entry *h)
28a1ba9ba4Schristos {
29a1ba9ba4Schristos struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h;
30a1ba9ba4Schristos return h->type == STT_GNU_IFUNC || eh->ifunc_resolver_address != 0;
31a1ba9ba4Schristos }
32a1ba9ba4Schristos
33051580eeSchristos /* Return true if .got.plt is supposed to be emitted after .got. */
34051580eeSchristos
35051580eeSchristos static inline bfd_boolean
s390_gotplt_after_got_p(struct bfd_link_info * info)36051580eeSchristos s390_gotplt_after_got_p (struct bfd_link_info *info)
37051580eeSchristos {
38051580eeSchristos struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
39051580eeSchristos
40051580eeSchristos if (!htab->elf.sgot || !htab->elf.sgotplt)
41051580eeSchristos return TRUE;
42051580eeSchristos
43051580eeSchristos if (htab->elf.sgot->output_section == htab->elf.sgotplt->output_section)
44051580eeSchristos {
45051580eeSchristos if (htab->elf.sgot->output_offset < htab->elf.sgotplt->output_offset)
46051580eeSchristos return TRUE;
47051580eeSchristos }
48051580eeSchristos else
49051580eeSchristos {
50051580eeSchristos if (htab->elf.sgot->output_section->vma
51051580eeSchristos <= htab->elf.sgotplt->output_section->vma)
52051580eeSchristos return TRUE;
53051580eeSchristos }
54051580eeSchristos return FALSE;
55051580eeSchristos }
56051580eeSchristos
57051580eeSchristos /* Return the value of the _GLOBAL_OFFSET_TABLE_ symbol. */
58051580eeSchristos
59051580eeSchristos static inline bfd_vma
s390_got_pointer(struct bfd_link_info * info)60051580eeSchristos s390_got_pointer (struct bfd_link_info *info)
61051580eeSchristos {
62051580eeSchristos struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
63051580eeSchristos bfd_vma got_pointer;
64051580eeSchristos
65051580eeSchristos BFD_ASSERT (htab && htab->elf.hgot);
66051580eeSchristos
67051580eeSchristos got_pointer = (htab->elf.hgot->root.u.def.section->output_section->vma
68051580eeSchristos + htab->elf.hgot->root.u.def.section->output_offset);
69051580eeSchristos /* Our ABI requires the GOT pointer to point at the very beginning
70051580eeSchristos of the global offset table. */
71051580eeSchristos BFD_ASSERT (got_pointer
72051580eeSchristos <= (htab->elf.sgot->output_section->vma
73051580eeSchristos + htab->elf.sgot->output_offset));
74051580eeSchristos BFD_ASSERT (got_pointer
75051580eeSchristos <= (htab->elf.sgotplt->output_section->vma
76051580eeSchristos + htab->elf.sgotplt->output_offset));
77051580eeSchristos
78051580eeSchristos return got_pointer;
79051580eeSchristos }
80051580eeSchristos
81051580eeSchristos
82051580eeSchristos /* Return the offset of the .got versus _GLOBAL_OFFSET_TABLE_. */
83051580eeSchristos
84051580eeSchristos static inline bfd_vma
s390_got_offset(struct bfd_link_info * info)85051580eeSchristos s390_got_offset (struct bfd_link_info *info)
86051580eeSchristos {
87051580eeSchristos struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
88051580eeSchristos
89051580eeSchristos /* The absolute address of the .got in the target image. */
90051580eeSchristos bfd_vma got_address = (htab->elf.sgot->output_section->vma
91051580eeSchristos + htab->elf.sgot->output_offset);
92051580eeSchristos
93051580eeSchristos /* GOT offset must not be negative. */
94051580eeSchristos BFD_ASSERT (s390_got_pointer (info) <= got_address);
95051580eeSchristos return got_address - s390_got_pointer (info);
96051580eeSchristos }
97051580eeSchristos
98051580eeSchristos /* Return the offset of the .got.plt versus _GLOBAL_OFFSET_TABLE_. */
99051580eeSchristos
100051580eeSchristos static inline bfd_vma
s390_gotplt_offset(struct bfd_link_info * info)101051580eeSchristos s390_gotplt_offset (struct bfd_link_info *info)
102051580eeSchristos {
103051580eeSchristos struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info);
104051580eeSchristos
105051580eeSchristos /* The absolute address of the .got.plt in the target image. */
106051580eeSchristos bfd_vma gotplt_address = (htab->elf.sgotplt->output_section->vma
107051580eeSchristos + htab->elf.sgotplt->output_offset);
108051580eeSchristos
109051580eeSchristos /* GOT offset must not be negative. */
110051580eeSchristos BFD_ASSERT (s390_got_pointer (info) <= gotplt_address);
111051580eeSchristos return gotplt_address - s390_got_pointer (info);
112051580eeSchristos }
113051580eeSchristos
114a1ba9ba4Schristos /* Create sections needed by STT_GNU_IFUNC symbol. */
115a1ba9ba4Schristos
116a1ba9ba4Schristos static bfd_boolean
s390_elf_create_ifunc_sections(bfd * abfd,struct bfd_link_info * info)117a1ba9ba4Schristos s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
118a1ba9ba4Schristos {
119a1ba9ba4Schristos flagword flags;
120a1ba9ba4Schristos asection *s;
121a1ba9ba4Schristos const struct elf_backend_data *bed = get_elf_backend_data (abfd);
122a1ba9ba4Schristos struct elf_link_hash_table *htab = elf_hash_table (info);
123a1ba9ba4Schristos
124a1ba9ba4Schristos if (htab->iplt != NULL)
125a1ba9ba4Schristos return TRUE;
126a1ba9ba4Schristos
127a1ba9ba4Schristos flags = bed->dynamic_sec_flags;
128a1ba9ba4Schristos
129b2396a7bSchristos if (bfd_link_pic (info))
130a1ba9ba4Schristos {
131a1ba9ba4Schristos s = bfd_make_section_with_flags (abfd, ".rela.ifunc",
132a1ba9ba4Schristos flags | SEC_READONLY);
133a1ba9ba4Schristos if (s == NULL
134*184b2d41Schristos || !bfd_set_section_alignment (s, bed->s->log_file_align))
135a1ba9ba4Schristos return FALSE;
136a1ba9ba4Schristos htab->irelifunc = s;
137a1ba9ba4Schristos }
138a1ba9ba4Schristos
139a1ba9ba4Schristos /* Create .iplt, .rel[a].iplt, and .igot.plt. */
140a1ba9ba4Schristos s = bfd_make_section_with_flags (abfd, ".iplt",
141a1ba9ba4Schristos flags | SEC_CODE | SEC_READONLY);
142a1ba9ba4Schristos if (s == NULL
143*184b2d41Schristos || !bfd_set_section_alignment (s, bed->plt_alignment))
144a1ba9ba4Schristos return FALSE;
145a1ba9ba4Schristos htab->iplt = s;
146a1ba9ba4Schristos
147a1ba9ba4Schristos s = bfd_make_section_with_flags (abfd, ".rela.iplt", flags | SEC_READONLY);
148a1ba9ba4Schristos if (s == NULL
149*184b2d41Schristos || !bfd_set_section_alignment (s, bed->s->log_file_align))
150a1ba9ba4Schristos return FALSE;
151a1ba9ba4Schristos htab->irelplt = s;
152a1ba9ba4Schristos
153a1ba9ba4Schristos s = bfd_make_section_with_flags (abfd, ".igot.plt", flags);
154a1ba9ba4Schristos if (s == NULL
155*184b2d41Schristos || !bfd_set_section_alignment (s, bed->s->log_file_align))
156a1ba9ba4Schristos return FALSE;
157a1ba9ba4Schristos htab->igotplt = s;
158a1ba9ba4Schristos
159a1ba9ba4Schristos return TRUE;
160a1ba9ba4Schristos }
161a1ba9ba4Schristos
162a1ba9ba4Schristos
163a1ba9ba4Schristos /* Allocate space in .plt, .got and associated reloc sections for
164a1ba9ba4Schristos dynamic relocs against a STT_GNU_IFUNC symbol definition. */
165a1ba9ba4Schristos
166a1ba9ba4Schristos static bfd_boolean
s390_elf_allocate_ifunc_dyn_relocs(struct bfd_link_info * info,struct elf_link_hash_entry * h)167a1ba9ba4Schristos s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
168b2396a7bSchristos struct elf_link_hash_entry *h)
169a1ba9ba4Schristos {
170a1ba9ba4Schristos struct elf_dyn_relocs *p;
171a1ba9ba4Schristos struct elf_link_hash_table *htab;
172a1ba9ba4Schristos struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h;
173*184b2d41Schristos struct elf_dyn_relocs **head = &h->dyn_relocs;
174a1ba9ba4Schristos
175a1ba9ba4Schristos htab = elf_hash_table (info);
176a1ba9ba4Schristos eh->ifunc_resolver_address = h->root.u.def.value;
177a1ba9ba4Schristos eh->ifunc_resolver_section = h->root.u.def.section;
178a1ba9ba4Schristos
179a1ba9ba4Schristos /* Support garbage collection against STT_GNU_IFUNC symbols. */
180a1ba9ba4Schristos if (h->plt.refcount <= 0 && h->got.refcount <= 0)
181a1ba9ba4Schristos {
182a1ba9ba4Schristos /* When building shared library, we need to handle the case
183a1ba9ba4Schristos where it is marked with regular reference, but not non-GOT
184a1ba9ba4Schristos reference. It may happen if we didn't see STT_GNU_IFUNC
185a1ba9ba4Schristos symbol at the time when checking relocations. */
186b2396a7bSchristos if (bfd_link_pic (info)
187a1ba9ba4Schristos && !h->non_got_ref
188a1ba9ba4Schristos && h->ref_regular)
189a1ba9ba4Schristos for (p = *head; p != NULL; p = p->next)
190a1ba9ba4Schristos if (p->count)
191a1ba9ba4Schristos {
192a1ba9ba4Schristos h->non_got_ref = 1;
193a1ba9ba4Schristos goto keep;
194a1ba9ba4Schristos }
195a1ba9ba4Schristos
196a1ba9ba4Schristos h->got = htab->init_got_offset;
197a1ba9ba4Schristos h->plt = htab->init_plt_offset;
198a1ba9ba4Schristos *head = NULL;
199a1ba9ba4Schristos return TRUE;
200a1ba9ba4Schristos }
201a1ba9ba4Schristos
202a1ba9ba4Schristos /* Return and discard space for dynamic relocations against it if
203a1ba9ba4Schristos it is never referenced in a non-shared object. */
204a1ba9ba4Schristos if (!h->ref_regular)
205a1ba9ba4Schristos {
206a1ba9ba4Schristos if (h->plt.refcount > 0
207a1ba9ba4Schristos || h->got.refcount > 0)
208a1ba9ba4Schristos abort ();
209a1ba9ba4Schristos h->got = htab->init_got_offset;
210a1ba9ba4Schristos h->plt = htab->init_plt_offset;
211a1ba9ba4Schristos *head = NULL;
212a1ba9ba4Schristos return TRUE;
213a1ba9ba4Schristos }
214a1ba9ba4Schristos
215a1ba9ba4Schristos keep:
216a1ba9ba4Schristos /* Without checking h->plt.refcount here we allocate a PLT slot.
217a1ba9ba4Schristos When setting plt.refcount in check_relocs it might not have been
218a1ba9ba4Schristos known that this will be an IFUNC symol. */
219a1ba9ba4Schristos h->plt.offset = htab->iplt->size;
220a1ba9ba4Schristos h->needs_plt = 1;
221a1ba9ba4Schristos htab->iplt->size += PLT_ENTRY_SIZE;
222a1ba9ba4Schristos htab->igotplt->size += GOT_ENTRY_SIZE;
223a1ba9ba4Schristos htab->irelplt->size += RELA_ENTRY_SIZE;
224a1ba9ba4Schristos htab->irelplt->reloc_count++;
225a1ba9ba4Schristos
226a1ba9ba4Schristos /* In order to make pointer equality work with IFUNC symbols defined
227a1ba9ba4Schristos in a non-PIE executable and referenced in a shared lib, we turn
228a1ba9ba4Schristos the symbol into a STT_FUNC symbol and make the symbol value to
229a1ba9ba4Schristos point to the IPLT slot. That way the referencing shared lib will
230a1ba9ba4Schristos always get the PLT slot address when resolving the respective
231a1ba9ba4Schristos R_390_GLOB_DAT/R_390_64 relocs on that symbol. */
232b2396a7bSchristos if (bfd_link_pde (info)
233b2396a7bSchristos && h->def_regular
234b2396a7bSchristos && h->ref_dynamic)
235a1ba9ba4Schristos {
236a1ba9ba4Schristos h->root.u.def.section = htab->iplt;
237a1ba9ba4Schristos h->root.u.def.value = h->plt.offset;
238a1ba9ba4Schristos h->size = PLT_ENTRY_SIZE;
239a1ba9ba4Schristos h->type = STT_FUNC;
240a1ba9ba4Schristos }
241a1ba9ba4Schristos
242051580eeSchristos if (!bfd_link_pic (info))
243a1ba9ba4Schristos *head = NULL;
244a1ba9ba4Schristos
245a1ba9ba4Schristos /* Finally, allocate space. */
246a1ba9ba4Schristos p = *head;
247a1ba9ba4Schristos if (p != NULL)
248a1ba9ba4Schristos {
249a1ba9ba4Schristos bfd_size_type count = 0;
250a1ba9ba4Schristos do
251a1ba9ba4Schristos {
252a1ba9ba4Schristos count += p->count;
253a1ba9ba4Schristos p = p->next;
254a1ba9ba4Schristos }
255a1ba9ba4Schristos while (p != NULL);
256a1ba9ba4Schristos htab->irelifunc->size += count * RELA_ENTRY_SIZE;
257a1ba9ba4Schristos }
258a1ba9ba4Schristos
259a1ba9ba4Schristos /* Decide whether the got.iplt slot can be used. This has to be
260a1ba9ba4Schristos avoided if the values in the GOT slots could differ for pointer
261a1ba9ba4Schristos equality reasons. */
262a1ba9ba4Schristos if (h->got.refcount <= 0
263b2396a7bSchristos || (bfd_link_pic (info)
264a1ba9ba4Schristos && (h->dynindx == -1 || h->forced_local))
265b2396a7bSchristos || bfd_link_pie (info)
266a1ba9ba4Schristos || htab->sgot == NULL)
267a1ba9ba4Schristos {
268a1ba9ba4Schristos /* Use .got.iplt. */
269a1ba9ba4Schristos h->got.offset = (bfd_vma) -1;
270a1ba9ba4Schristos }
271a1ba9ba4Schristos else
272a1ba9ba4Schristos {
273a1ba9ba4Schristos h->got.offset = htab->sgot->size;
274a1ba9ba4Schristos htab->sgot->size += GOT_ENTRY_SIZE;
275b2396a7bSchristos if (bfd_link_pic (info))
276a1ba9ba4Schristos htab->srelgot->size += RELA_ENTRY_SIZE;
277a1ba9ba4Schristos }
278a1ba9ba4Schristos
279a1ba9ba4Schristos return TRUE;
280a1ba9ba4Schristos }
281a1ba9ba4Schristos
282a1ba9ba4Schristos static bfd_boolean
elf_s390_allocate_local_syminfo(bfd * abfd,Elf_Internal_Shdr * symtab_hdr)283a1ba9ba4Schristos elf_s390_allocate_local_syminfo (bfd *abfd, Elf_Internal_Shdr *symtab_hdr)
284a1ba9ba4Schristos {
285a1ba9ba4Schristos bfd_size_type size;
286a1ba9ba4Schristos
287a1ba9ba4Schristos size = symtab_hdr->sh_info;
288a1ba9ba4Schristos size *= (sizeof (bfd_signed_vma) /* local got */
289a1ba9ba4Schristos + sizeof (struct plt_entry) /* local plt */
290a1ba9ba4Schristos + sizeof(char)); /* local tls type */
291a1ba9ba4Schristos elf_local_got_refcounts (abfd) = ((bfd_signed_vma *)
292a1ba9ba4Schristos bfd_zalloc (abfd, size));
293a1ba9ba4Schristos if (elf_local_got_refcounts (abfd) == NULL)
294a1ba9ba4Schristos return FALSE;
295a1ba9ba4Schristos elf_s390_local_plt (abfd)
296a1ba9ba4Schristos = (struct plt_entry*)(elf_local_got_refcounts (abfd)
297a1ba9ba4Schristos + symtab_hdr->sh_info);
298a1ba9ba4Schristos elf_s390_local_got_tls_type (abfd)
299a1ba9ba4Schristos = (char *) (elf_s390_local_plt (abfd) + symtab_hdr->sh_info);
300a1ba9ba4Schristos
301a1ba9ba4Schristos return TRUE;
302a1ba9ba4Schristos }
303a1ba9ba4Schristos
304a1ba9ba4Schristos /* Whether to sort relocs output by ld -r or ld --emit-relocs, by
305a1ba9ba4Schristos r_offset. Don't do so for code sections. We want to keep ordering
306a1ba9ba4Schristos of GDCALL / PLT32DBL for TLS optimizations as is. On the other
307a1ba9ba4Schristos hand, elf-eh-frame.c processing requires .eh_frame relocs to be
308a1ba9ba4Schristos sorted. */
309a1ba9ba4Schristos
310a1ba9ba4Schristos static bfd_boolean
elf_s390_elf_sort_relocs_p(asection * sec)311a1ba9ba4Schristos elf_s390_elf_sort_relocs_p (asection *sec)
312a1ba9ba4Schristos {
313a1ba9ba4Schristos return (sec->flags & SEC_CODE) == 0;
314a1ba9ba4Schristos }
315a1ba9ba4Schristos
316a1ba9ba4Schristos /* Merge object attributes from IBFD into OBFD. Raise an error if
317a1ba9ba4Schristos there are conflicting attributes. */
318a1ba9ba4Schristos static bfd_boolean
elf_s390_merge_obj_attributes(bfd * ibfd,struct bfd_link_info * info)31915d8e94aSchristos elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
320a1ba9ba4Schristos {
32115d8e94aSchristos bfd *obfd = info->output_bfd;
322a1ba9ba4Schristos obj_attribute *in_attr, *in_attrs;
323a1ba9ba4Schristos obj_attribute *out_attr, *out_attrs;
324a1ba9ba4Schristos
325a1ba9ba4Schristos if (!elf_known_obj_attributes_proc (obfd)[0].i)
326a1ba9ba4Schristos {
327a1ba9ba4Schristos /* This is the first object. Copy the attributes. */
328a1ba9ba4Schristos _bfd_elf_copy_obj_attributes (ibfd, obfd);
329a1ba9ba4Schristos
330a1ba9ba4Schristos /* Use the Tag_null value to indicate the attributes have been
331a1ba9ba4Schristos initialized. */
332a1ba9ba4Schristos elf_known_obj_attributes_proc (obfd)[0].i = 1;
333a1ba9ba4Schristos
334a1ba9ba4Schristos return TRUE;
335a1ba9ba4Schristos }
336a1ba9ba4Schristos
337a1ba9ba4Schristos in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
338a1ba9ba4Schristos out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
339a1ba9ba4Schristos
340a1ba9ba4Schristos /* Check for conflicting Tag_GNU_S390_ABI_Vector attributes and
341a1ba9ba4Schristos merge non-conflicting ones. */
342a1ba9ba4Schristos in_attr = &in_attrs[Tag_GNU_S390_ABI_Vector];
343a1ba9ba4Schristos out_attr = &out_attrs[Tag_GNU_S390_ABI_Vector];
344a1ba9ba4Schristos
345a1ba9ba4Schristos if (in_attr->i > 2)
346a1ba9ba4Schristos _bfd_error_handler
34715d8e94aSchristos /* xgettext:c-format */
348051580eeSchristos (_("warning: %pB uses unknown vector ABI %d"), ibfd,
349a1ba9ba4Schristos in_attr->i);
350a1ba9ba4Schristos else if (out_attr->i > 2)
351a1ba9ba4Schristos _bfd_error_handler
35215d8e94aSchristos /* xgettext:c-format */
353051580eeSchristos (_("warning: %pB uses unknown vector ABI %d"), obfd,
354a1ba9ba4Schristos out_attr->i);
355a1ba9ba4Schristos else if (in_attr->i != out_attr->i)
356a1ba9ba4Schristos {
357a1ba9ba4Schristos out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
358a1ba9ba4Schristos
359a1ba9ba4Schristos if (in_attr->i && out_attr->i)
360a1ba9ba4Schristos {
361a1ba9ba4Schristos const char abi_str[3][9] = { "none", "software", "hardware" };
362a1ba9ba4Schristos
363a1ba9ba4Schristos _bfd_error_handler
36415d8e94aSchristos /* xgettext:c-format */
365051580eeSchristos (_("warning: %pB uses vector %s ABI, %pB uses %s ABI"),
36615d8e94aSchristos ibfd, abi_str[in_attr->i], obfd, abi_str[out_attr->i]);
367a1ba9ba4Schristos }
368a1ba9ba4Schristos if (in_attr->i > out_attr->i)
369a1ba9ba4Schristos out_attr->i = in_attr->i;
370a1ba9ba4Schristos }
371a1ba9ba4Schristos
372a1ba9ba4Schristos /* Merge Tag_compatibility attributes and any common GNU ones. */
37315d8e94aSchristos _bfd_elf_merge_object_attributes (ibfd, info);
374a1ba9ba4Schristos
375a1ba9ba4Schristos return TRUE;
376a1ba9ba4Schristos }
377