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