1# This shell script emits a C file. -*- C -*-
2#   Copyright (C) 2009-2024 Free Software Foundation, Inc.
3#   Contributed by Kalray Inc.
4#
5# This file is part of the GNU Binutils.
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; see the file COPYING3. If not,
19# see <http://www.gnu.org/licenses/>.
20#
21
22# This file is sourced from elf32.em, and defines extra kvx-elf
23# specific routines.
24#
25fragment <<EOF
26
27#include "ldctor.h"
28#include "elf/kvx.h"
29#include "elfxx-kvx.h"
30
31
32static void
33elf${ELFSIZE}_kvx_before_allocation (void)
34{
35EOF
36if test x"${EMULATION_NAME}" != x"elf64kvx_linux"; then
37fragment <<EOF
38  if (bfd_link_pie (&link_info)) {
39          einfo (_("%F:%P: -pie not supported\n"));
40  }
41EOF
42fi
43fragment <<EOF
44
45  /* Call the standard elf routine.  */
46  gld${EMULATION_NAME}_before_allocation ();
47}
48
49
50
51/* Fake input file for stubs.  */
52static lang_input_statement_type *stub_file;
53
54/* Whether we need to call gldarm_layout_sections_again.  */
55static int need_laying_out = 0;
56
57/* Maximum size of a group of input sections that can be handled by
58   one stub section.  A value of +/-1 indicates the bfd back-end
59   should use a suitable default size.  */
60static bfd_signed_vma group_size = -1;
61
62struct hook_stub_info
63{
64  lang_statement_list_type add;
65  asection *input_section;
66};
67
68/* Traverse the linker tree to find the spot where the stub goes.  */
69
70static bool
71hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp)
72{
73  lang_statement_union_type *l;
74  bool ret;
75
76  for (; (l = *lp) != NULL; lp = &l->header.next)
77    {
78      switch (l->header.type)
79          {
80          case lang_constructors_statement_enum:
81            ret = hook_in_stub (info, &constructor_list.head);
82            if (ret)
83              return ret;
84            break;
85
86          case lang_output_section_statement_enum:
87            ret = hook_in_stub (info,
88                  &l->output_section_statement.children.head);
89
90            if (ret)
91              return ret;
92            break;
93
94          case lang_wild_statement_enum:
95            ret = hook_in_stub (info, &l->wild_statement.children.head);
96            if (ret)
97              return ret;
98            break;
99
100          case lang_group_statement_enum:
101            ret = hook_in_stub (info, &l->group_statement.children.head);
102            if (ret)
103              return ret;
104            break;
105
106          case lang_input_section_enum:
107            if (l->input_section.section == info->input_section)
108            {
109                /* We've found our section.  Insert the stub immediately
110                     after its associated input section.  */
111                *(info->add.tail) = l->header.next;
112                l->header.next = info->add.head;
113                return true;
114              }
115
116            break;
117
118          case lang_data_statement_enum:
119          case lang_reloc_statement_enum:
120          case lang_object_symbols_statement_enum:
121          case lang_output_statement_enum:
122          case lang_target_statement_enum:
123          case lang_input_statement_enum:
124          case lang_assignment_statement_enum:
125          case lang_padding_statement_enum:
126          case lang_address_statement_enum:
127          case lang_fill_statement_enum:
128            break;
129
130          default:
131            FAIL ();
132            break;
133          }
134    }
135  return false;
136}
137
138
139/* Call-back for elf${ELFSIZE}_kvx_size_stubs.  */
140
141/* Create a new stub section, and arrange for it to be linked
142   immediately after INPUT_SECTION.  */
143
144static asection *
145elf${ELFSIZE}_kvx_add_stub_section (const char *stub_sec_name,
146                                    asection *input_section)
147{
148  asection *stub_sec;
149  flagword flags;
150  asection *output_section;
151  lang_output_section_statement_type *os;
152  struct hook_stub_info info;
153
154  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
155             | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
156  stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
157                                                             stub_sec_name, flags);
158  if (stub_sec == NULL)
159    goto err_ret;
160
161  bfd_set_section_alignment (stub_sec, 2);
162
163  output_section = input_section->output_section;
164  os = lang_output_section_get (output_section);
165
166  info.input_section = input_section;
167  lang_list_init (&info.add);
168  lang_add_section (&info.add, stub_sec, NULL, NULL, os);
169
170  if (info.add.head == NULL)
171    goto err_ret;
172
173  if (hook_in_stub (&info, &os->children.head))
174    return stub_sec;
175
176 err_ret:
177  einfo ("%X%P: can not make stub section: %E\n");
178  return NULL;
179}
180
181/* Another call-back for elf${ELFSIZE}_kvx_size_stubs.  */
182
183static void
184gldkvx_layout_sections_again (void)
185{
186  /* If we have changed sizes of the stub sections, then we need
187     to recalculate all the section offsets.  This may mean we need to
188     add even more stubs.  */
189  ldelf_map_segments (true);
190  need_laying_out = -1;
191}
192
193static void
194build_section_lists (lang_statement_union_type *statement)
195{
196  if (statement->header.type == lang_input_section_enum)
197    {
198      asection *i = statement->input_section.section;
199
200      if (!((lang_input_statement_type *) i->owner->usrdata)->flags.just_syms
201            && (i->flags & SEC_EXCLUDE) == 0
202            && i->output_section != NULL
203            && i->output_section->owner == link_info.output_bfd)
204          elf${ELFSIZE}_kvx_next_input_section (& link_info, i);
205    }
206}
207
208static void
209gld${EMULATION_NAME}_after_allocation (void)
210{
211  int ret;
212
213  /* bfd_elf32_discard_info just plays with debugging sections,
214     ie. doesn't affect any code, so we can delay resizing the
215     sections.  It's likely we'll resize everything in the process of
216     adding stubs.  */
217  ret = bfd_elf_discard_info (link_info.output_bfd, & link_info);
218  if (ret < 0)
219    {
220      einfo ("%X%P: .eh_frame/.stab edit: %E\n");
221      return;
222    }
223  else if (ret > 0)
224    need_laying_out = 1;
225
226  /* If generating a relocatable output file, then we don't
227     have to examine the relocs.  */
228  if (stub_file != NULL && !bfd_link_relocatable (&link_info))
229    {
230      ret = elf${ELFSIZE}_kvx_setup_section_lists (link_info.output_bfd,
231                                                                   &link_info);
232      if (ret != 0)
233          {
234            if (ret < 0)
235              {
236                einfo ("%X%P: could not compute sections lists for stub generation: %E\n");
237                return;
238              }
239
240            lang_for_each_statement (build_section_lists);
241
242            /* Call into the BFD backend to do the real work.  */
243            if (! elf${ELFSIZE}_kvx_size_stubs (link_info.output_bfd,
244                                                    stub_file->the_bfd,
245                                                    & link_info,
246                                                    group_size,
247                                                    & elf${ELFSIZE}_kvx_add_stub_section,
248                                                    & gldkvx_layout_sections_again))
249              {
250                einfo ("%X%P: cannot size stub section: %E\n");
251                return;
252              }
253          }
254    }
255
256  if (need_laying_out != -1)
257    ldelf_map_segments (need_laying_out);
258}
259
260static void
261gld${EMULATION_NAME}_finish (void)
262{
263  if (!bfd_link_relocatable (&link_info))
264    {
265      /* Now build the linker stubs.  */
266      if (stub_file != NULL
267            && stub_file->the_bfd->sections != NULL)
268          {
269            if (! elf${ELFSIZE}_kvx_build_stubs (& link_info))
270              einfo ("%X%P: can not build stubs: %E\n");
271          }
272    }
273
274  finish_default ();
275}
276
277/* This is a convenient point to tell BFD about target specific flags.
278   After the output has been created, but before inputs are read.  */
279static void
280kvx_elf_create_output_section_statements (void)
281{
282  if (!(bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
283        && elf_object_id (link_info.output_bfd) == KVX_ELF_DATA))
284    return;
285
286  stub_file = lang_add_input_file ("linker stubs",
287                                           lang_input_file_is_fake_enum,
288                                           NULL);
289  stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd);
290  if (stub_file->the_bfd == NULL
291      || ! bfd_set_arch_mach (stub_file->the_bfd,
292                                    bfd_get_arch (link_info.output_bfd),
293                                    bfd_get_mach (link_info.output_bfd)))
294    {
295      einfo ("%X%P: can not create BFD %E\n");
296      return;
297    }
298
299  stub_file->the_bfd->flags |= BFD_LINKER_CREATED;
300  ldlang_add_file (stub_file);
301
302  if (!kvx_elf${ELFSIZE}_init_stub_bfd (&link_info, stub_file->the_bfd))
303    einfo ("%F%P: can not init BFD: %E\n");
304}
305
306
307#define lang_for_each_input_file kvx_lang_for_each_input_file
308
309EOF
310
311LDEMUL_BEFORE_ALLOCATION=elf${ELFSIZE}_kvx_before_allocation
312LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
313LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=kvx_elf_create_output_section_statements
314
315# Call the extra arm-elf function
316LDEMUL_FINISH=gld${EMULATION_NAME}_finish
317