1# This shell script emits a C file. -*- C -*-
2#   Copyright (C) 2013-2024 Free Software Foundation, Inc.
3#
4# This file is part of GNU Binutils.
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19# MA 02110-1301, USA.
20#
21
22# This file is sourced from elf.em, and defines extra metagelf
23# specific routines. Taken from hppaelf.em.
24#
25fragment <<EOF
26
27#include "ldctor.h"
28#include "elf32-metag.h"
29
30
31/* Fake input file for stubs.  */
32static lang_input_statement_type *stub_file;
33
34/* Whether we need to call metag_layout_sections_again.  */
35static int need_laying_out = 0;
36
37/* Maximum size of a group of input sections that can be handled by
38   one stub section.  A value of +/-1 indicates the bfd back-end
39   should use a suitable default size.  */
40static bfd_signed_vma group_size = 1;
41
42/* This is called before the input files are opened.  We create a new
43   fake input file to hold the stub sections.  */
44
45static void
46metagelf_create_output_section_statements (void)
47{
48  extern const bfd_target metag_elf32_vec;
49
50  if (link_info.output_bfd->xvec != &metag_elf32_vec)
51    return;
52
53  stub_file = lang_add_input_file ("linker stubs",
54                                           lang_input_file_is_fake_enum,
55                                           NULL);
56  stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd);
57  if (stub_file->the_bfd == NULL
58      || ! bfd_set_arch_mach (stub_file->the_bfd,
59                                    bfd_get_arch (link_info.output_bfd),
60                                    bfd_get_mach (link_info.output_bfd)))
61    {
62      einfo (_("%F%P: can not create BFD: %E\n"));
63      return;
64    }
65
66  stub_file->the_bfd->flags |= BFD_LINKER_CREATED;
67  ldlang_add_file (stub_file);
68}
69
70
71struct hook_stub_info
72{
73  lang_statement_list_type add;
74  asection *input_section;
75};
76
77/* Traverse the linker tree to find the spot where the stub goes.  */
78
79static bool
80hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp)
81{
82  lang_statement_union_type *l;
83  bool ret;
84
85  for (; (l = *lp) != NULL; lp = &l->header.next)
86    {
87      switch (l->header.type)
88          {
89          case lang_constructors_statement_enum:
90            ret = hook_in_stub (info, &constructor_list.head);
91            if (ret)
92              return ret;
93            break;
94
95          case lang_output_section_statement_enum:
96            ret = hook_in_stub (info,
97                                    &l->output_section_statement.children.head);
98            if (ret)
99              return ret;
100            break;
101
102          case lang_wild_statement_enum:
103            ret = hook_in_stub (info, &l->wild_statement.children.head);
104            if (ret)
105              return ret;
106            break;
107
108          case lang_group_statement_enum:
109            ret = hook_in_stub (info, &l->group_statement.children.head);
110            if (ret)
111              return ret;
112            break;
113
114          case lang_input_section_enum:
115            if (l->input_section.section == info->input_section)
116              {
117                /* We've found our section.  Insert the stub immediately
118                     before its associated input section.  */
119                *lp = info->add.head;
120                *(info->add.tail) = l;
121                return true;
122              }
123            break;
124
125          case lang_data_statement_enum:
126          case lang_reloc_statement_enum:
127          case lang_object_symbols_statement_enum:
128          case lang_output_statement_enum:
129          case lang_target_statement_enum:
130          case lang_input_statement_enum:
131          case lang_assignment_statement_enum:
132          case lang_padding_statement_enum:
133          case lang_address_statement_enum:
134          case lang_fill_statement_enum:
135            break;
136
137          default:
138            FAIL ();
139            break;
140          }
141    }
142  return false;
143}
144
145
146/* Call-back for elf_metag_size_stubs.  */
147
148/* Create a new stub section, and arrange for it to be linked
149   immediately before INPUT_SECTION.  */
150
151static asection *
152metagelf_add_stub_section (const char *stub_sec_name, asection *input_section)
153{
154  asection *stub_sec;
155  flagword flags;
156  asection *output_section;
157  lang_output_section_statement_type *os;
158  struct hook_stub_info info;
159
160  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
161             | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
162  stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
163                                                             stub_sec_name, flags);
164  if (stub_sec == NULL)
165    goto err_ret;
166
167  output_section = input_section->output_section;
168  os = lang_output_section_get (output_section);
169
170  info.input_section = input_section;
171  lang_list_init (&info.add);
172  lang_add_section (&info.add, stub_sec, NULL, NULL, os);
173
174  if (info.add.head == NULL)
175    goto err_ret;
176
177  if (hook_in_stub (&info, &os->children.head))
178    return stub_sec;
179
180 err_ret:
181  einfo (_("%X%P: can not make stub section: %E\n"));
182  return NULL;
183}
184
185
186/* Another call-back for elf_metag_size_stubs.  */
187
188static void
189metagelf_layout_sections_again (void)
190{
191  /* If we have changed sizes of the stub sections, then we need
192     to recalculate all the section offsets.  This may mean we need to
193     add even more stubs.  */
194  ldelf_map_segments (true);
195  need_laying_out = -1;
196}
197
198
199static void
200build_section_lists (lang_statement_union_type *statement)
201{
202  if (statement->header.type == lang_input_section_enum)
203    {
204      asection *i = statement->input_section.section;
205
206      if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
207            && (i->flags & SEC_EXCLUDE) == 0
208            && i->output_section != NULL
209            && i->output_section->owner == link_info.output_bfd)
210          {
211            elf_metag_next_input_section (&link_info, i);
212          }
213    }
214}
215
216
217/* For Meta we use this opportunity to build linker stubs.  */
218
219static void
220gld${EMULATION_NAME}_after_allocation (void)
221{
222  int ret;
223
224  /* bfd_elf_discard_info just plays with data and debugging sections,
225     ie. doesn't affect code size, so we can delay resizing the
226     sections.  It's likely we'll resize everything in the process of
227     adding stubs.  */
228  ret = bfd_elf_discard_info (link_info.output_bfd, &link_info);
229  if (ret < 0)
230    {
231      einfo (_("%X%P: .eh_frame/.stab edit: %E\n"));
232      return;
233    }
234  else if (ret > 0)
235    need_laying_out = 1;
236
237  /* If generating a relocatable output file, then we don't
238     have to examine the relocs.  */
239  if (stub_file != NULL && !bfd_link_relocatable (&link_info))
240    {
241      ret = elf_metag_setup_section_lists (link_info.output_bfd, &link_info);
242      if (ret != 0)
243          {
244            if (ret < 0)
245              {
246                einfo (_("%X%P: can not size stub section: %E\n"));
247                return;
248              }
249
250            lang_for_each_statement (build_section_lists);
251
252            /* Call into the BFD backend to do the real work.  */
253            if (! elf_metag_size_stubs (link_info.output_bfd,
254                                              stub_file->the_bfd,
255                                              &link_info,
256                                              group_size,
257                                              &metagelf_add_stub_section,
258                                              &metagelf_layout_sections_again))
259              {
260                einfo (_("%X%P: can not size stub section: %E\n"));
261                return;
262              }
263          }
264    }
265
266  if (need_laying_out != -1)
267    ldelf_map_segments (need_laying_out);
268
269  if (!bfd_link_relocatable (&link_info))
270    {
271      /* Now build the linker stubs.  */
272      if (stub_file != NULL && stub_file->the_bfd->sections != NULL)
273          {
274            if (! elf_metag_build_stubs (&link_info))
275              einfo (_("%X%P: can not build stubs: %E\n"));
276          }
277    }
278}
279
280EOF
281
282# Define some shell vars to insert bits of code into the standard elf
283# parse_args and list_options functions.
284#
285PARSE_AND_LIST_PROLOGUE='
286#define OPTION_STUBGROUP_SIZE           301
287'
288
289PARSE_AND_LIST_LONGOPTS='
290  { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE },
291'
292
293PARSE_AND_LIST_OPTIONS='
294  fprintf (file, _("\
295  --stub-group-size=N         Maximum size of a group of input sections that\n\
296                                can be handled by one stub section.  A negative\n\
297                                value locates all stubs before their branches\n\
298                                (with a group size of -N), while a positive\n\
299                                value allows two groups of input sections, one\n\
300                                before, and one after each stub section.\n\
301                                Values of +/-1 indicate the linker should\n\
302                                choose suitable defaults.\n"
303                       ));
304'
305
306PARSE_AND_LIST_ARGS_CASES='
307    case OPTION_STUBGROUP_SIZE:
308      {
309          const char *end;
310          group_size = bfd_scan_vma (optarg, &end, 0);
311          if (*end)
312            einfo (_("%F%P: invalid number `%s'\''\n"), optarg);
313      }
314      break;
315'
316
317# Put these extra metagelf routines in ld_${EMULATION_NAME}_emulation
318#
319LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
320LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=metagelf_create_output_section_statements
321