1# This shell script emits a C file. -*- C -*-
2#   Copyright (C) 1991-2014 Free Software Foundation, Inc.
3#
4# This file is part of the 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 elf32.em, and defines extra hppa-elf
23# specific routines.
24#
25fragment <<EOF
26
27#include "ldctor.h"
28#include "elf32-hppa.h"
29
30
31/* Fake input file for stubs.  */
32static lang_input_statement_type *stub_file;
33
34/* Type of import/export stubs to build.  For a single sub-space model,
35   we can build smaller import stubs and there is no need for export
36   stubs.  */
37static int multi_subspace = 0;
38
39/* Whether we need to call hppa_layout_sections_again.  */
40static int need_laying_out = 0;
41
42/* Maximum size of a group of input sections that can be handled by
43   one stub section.  A value of +/-1 indicates the bfd back-end
44   should use a suitable default size.  */
45static bfd_signed_vma group_size = 1;
46
47/* Stops the linker merging .text sections on a relocatable link,
48   and adds millicode library to the list of input files.  */
49
50static void
51hppaelf_after_parse (void)
52{
53  if (link_info.relocatable)
54    lang_add_unique (".text");
55
56  /* Enable this once we split millicode stuff from libgcc:
57     lang_add_input_file ("milli",
58     			  lang_input_file_is_l_enum,
59			  NULL);
60  */
61
62  after_parse_default ();
63}
64
65/* This is called before the input files are opened.  We create a new
66   fake input file to hold the stub sections.  */
67
68static void
69hppaelf_create_output_section_statements (void)
70{
71  if (!(bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
72	&& (elf_object_id (link_info.output_bfd) == HPPA32_ELF_DATA
73	    || elf_object_id (link_info.output_bfd) == HPPA64_ELF_DATA)))
74    return;
75
76  stub_file = lang_add_input_file ("linker stubs",
77				   lang_input_file_is_fake_enum,
78				   NULL);
79  stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd);
80  if (stub_file->the_bfd == NULL
81      || ! bfd_set_arch_mach (stub_file->the_bfd,
82			      bfd_get_arch (link_info.output_bfd),
83			      bfd_get_mach (link_info.output_bfd)))
84    {
85      einfo ("%X%P: can not create BFD %E\n");
86      return;
87    }
88
89  stub_file->the_bfd->flags |= BFD_LINKER_CREATED;
90  ldlang_add_file (stub_file);
91}
92
93
94struct hook_stub_info
95{
96  lang_statement_list_type add;
97  asection *input_section;
98};
99
100/* Traverse the linker tree to find the spot where the stub goes.  */
101
102static bfd_boolean
103hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp)
104{
105  lang_statement_union_type *l;
106  bfd_boolean ret;
107
108  for (; (l = *lp) != NULL; lp = &l->header.next)
109    {
110      switch (l->header.type)
111	{
112	case lang_constructors_statement_enum:
113	  ret = hook_in_stub (info, &constructor_list.head);
114	  if (ret)
115	    return ret;
116	  break;
117
118	case lang_output_section_statement_enum:
119	  ret = hook_in_stub (info,
120			      &l->output_section_statement.children.head);
121	  if (ret)
122	    return ret;
123	  break;
124
125	case lang_wild_statement_enum:
126	  ret = hook_in_stub (info, &l->wild_statement.children.head);
127	  if (ret)
128	    return ret;
129	  break;
130
131	case lang_group_statement_enum:
132	  ret = hook_in_stub (info, &l->group_statement.children.head);
133	  if (ret)
134	    return ret;
135	  break;
136
137	case lang_input_section_enum:
138	  if (l->input_section.section == info->input_section)
139	    {
140	      /* We've found our section.  Insert the stub immediately
141		 before its associated input section.  */
142	      *lp = info->add.head;
143	      *(info->add.tail) = l;
144	      return TRUE;
145	    }
146	  break;
147
148	case lang_data_statement_enum:
149	case lang_reloc_statement_enum:
150	case lang_object_symbols_statement_enum:
151	case lang_output_statement_enum:
152	case lang_target_statement_enum:
153	case lang_input_statement_enum:
154	case lang_assignment_statement_enum:
155	case lang_padding_statement_enum:
156	case lang_address_statement_enum:
157	case lang_fill_statement_enum:
158	  break;
159
160	default:
161	  FAIL ();
162	  break;
163	}
164    }
165  return FALSE;
166}
167
168
169/* Call-back for elf32_hppa_size_stubs.  */
170
171/* Create a new stub section, and arrange for it to be linked
172   immediately before INPUT_SECTION.  */
173
174static asection *
175hppaelf_add_stub_section (const char *stub_sec_name, asection *input_section)
176{
177  asection *stub_sec;
178  flagword flags;
179  asection *output_section;
180  lang_output_section_statement_type *os;
181  struct hook_stub_info info;
182
183  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
184	   | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
185  stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
186						 stub_sec_name, flags);
187  if (stub_sec == NULL)
188    goto err_ret;
189
190  output_section = input_section->output_section;
191  os = lang_output_section_get (output_section);
192
193  info.input_section = input_section;
194  lang_list_init (&info.add);
195  lang_add_section (&info.add, stub_sec, NULL, os);
196
197  if (info.add.head == NULL)
198    goto err_ret;
199
200  if (hook_in_stub (&info, &os->children.head))
201    return stub_sec;
202
203 err_ret:
204  einfo ("%X%P: can not make stub section: %E\n");
205  return NULL;
206}
207
208
209/* Another call-back for elf32_hppa_size_stubs.  */
210
211static void
212hppaelf_layout_sections_again (void)
213{
214  /* If we have changed sizes of the stub sections, then we need
215     to recalculate all the section offsets.  This may mean we need to
216     add even more stubs.  */
217  gld${EMULATION_NAME}_map_segments (TRUE);
218  need_laying_out = -1;
219}
220
221
222static void
223build_section_lists (lang_statement_union_type *statement)
224{
225  if (statement->header.type == lang_input_section_enum)
226    {
227      asection *i = statement->input_section.section;
228
229      if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
230	  && (i->flags & SEC_EXCLUDE) == 0
231	  && i->output_section != NULL
232	  && i->output_section->owner == link_info.output_bfd)
233	{
234	  elf32_hppa_next_input_section (&link_info, i);
235	}
236    }
237}
238
239
240/* For the PA we use this opportunity to size and build linker stubs.  */
241
242static void
243gld${EMULATION_NAME}_after_allocation (void)
244{
245  int ret;
246
247  /* bfd_elf_discard_info just plays with data and debugging sections,
248     ie. doesn't affect code size, so we can delay resizing the
249     sections.  It's likely we'll resize everything in the process of
250     adding stubs.  */
251  ret = bfd_elf_discard_info (link_info.output_bfd, &link_info);
252  if (ret < 0)
253    {
254      einfo ("%X%P: .eh_frame/.stab edit: %E\n");
255      return;
256    }
257  else if (ret > 0)
258    need_laying_out = 1;
259
260  /* If generating a relocatable output file, then we don't
261     have to examine the relocs.  */
262  if (stub_file != NULL && !link_info.relocatable)
263    {
264      ret = elf32_hppa_setup_section_lists (link_info.output_bfd, &link_info);
265      if (ret != 0)
266	{
267	  if (ret < 0)
268	    {
269	      einfo ("%X%P: can not size stub section: %E\n");
270	      return;
271	    }
272
273	  lang_for_each_statement (build_section_lists);
274
275	  /* Call into the BFD backend to do the real work.  */
276	  if (! elf32_hppa_size_stubs (link_info.output_bfd,
277				       stub_file->the_bfd,
278				       &link_info,
279				       multi_subspace,
280				       group_size,
281				       &hppaelf_add_stub_section,
282				       &hppaelf_layout_sections_again))
283	    {
284	      einfo ("%X%P: can not size stub section: %E\n");
285	      return;
286	    }
287	}
288    }
289
290  if (need_laying_out != -1)
291    gld${EMULATION_NAME}_map_segments (need_laying_out);
292
293  if (! link_info.relocatable)
294    {
295      /* Set the global data pointer.  */
296      if (! elf32_hppa_set_gp (link_info.output_bfd, &link_info))
297	{
298	  einfo ("%X%P: can not set gp\n");
299	  return;
300	}
301
302      /* Now build the linker stubs.  */
303      if (stub_file != NULL && stub_file->the_bfd->sections != NULL)
304	{
305	  if (! elf32_hppa_build_stubs (&link_info))
306	    einfo ("%X%P: can not build stubs: %E\n");
307	}
308    }
309}
310
311
312/* Avoid processing the fake stub_file in vercheck, stat_needed and
313   check_needed routines.  */
314
315static void (*real_func) (lang_input_statement_type *);
316
317static void hppa_for_each_input_file_wrapper (lang_input_statement_type *l)
318{
319  if (l != stub_file)
320    (*real_func) (l);
321}
322
323static void
324hppa_lang_for_each_input_file (void (*func) (lang_input_statement_type *))
325{
326  real_func = func;
327  lang_for_each_input_file (&hppa_for_each_input_file_wrapper);
328}
329
330#define lang_for_each_input_file hppa_lang_for_each_input_file
331
332EOF
333
334# Define some shell vars to insert bits of code into the standard elf
335# parse_args and list_options functions.
336#
337PARSE_AND_LIST_PROLOGUE='
338#define OPTION_MULTI_SUBSPACE		301
339#define OPTION_STUBGROUP_SIZE		(OPTION_MULTI_SUBSPACE + 1)
340'
341
342PARSE_AND_LIST_LONGOPTS='
343  { "multi-subspace", no_argument, NULL, OPTION_MULTI_SUBSPACE },
344  { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE },
345'
346
347PARSE_AND_LIST_OPTIONS='
348  fprintf (file, _("\
349  --multi-subspace            Generate import and export stubs to support\n\
350                                multiple sub-space shared libraries\n"
351		   ));
352  fprintf (file, _("\
353  --stub-group-size=N         Maximum size of a group of input sections that\n\
354                                can be handled by one stub section.  A negative\n\
355                                value locates all stubs before their branches\n\
356                                (with a group size of -N), while a positive\n\
357                                value allows two groups of input sections, one\n\
358                                before, and one after each stub section.\n\
359                                Values of +/-1 indicate the linker should\n\
360                                choose suitable defaults.\n"
361		   ));
362'
363
364PARSE_AND_LIST_ARGS_CASES='
365    case OPTION_MULTI_SUBSPACE:
366      multi_subspace = 1;
367      break;
368
369    case OPTION_STUBGROUP_SIZE:
370      {
371	const char *end;
372        group_size = bfd_scan_vma (optarg, &end, 0);
373        if (*end)
374	  einfo (_("%P%F: invalid number `%s'\''\n"), optarg);
375      }
376      break;
377'
378
379# Put these extra hppaelf routines in ld_${EMULATION_NAME}_emulation
380#
381LDEMUL_AFTER_PARSE=hppaelf_after_parse
382LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
383LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=hppaelf_create_output_section_statements
384