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