Replace "if (x) free (x)" with "free (x)", ld
[deliverable/binutils-gdb.git] / ld / emultempl / xtensaelf.em
CommitLineData
e0001a05 1# This shell script emits a C file. -*- C -*-
b3adc24a 2# Copyright (C) 2003-2020 Free Software Foundation, Inc.
e0001a05 3#
f96b4a7b 4# This file is part of the GNU Binutils.
e0001a05
NC
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
f96b4a7b 8# the Free Software Foundation; either version 3 of the License, or
e0001a05
NC
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
f96b4a7b
NC
18# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19# MA 02110-1301, USA.
e0001a05
NC
20#
21
075a2b89 22# This file is sourced from elf.em, and defines extra xtensa-elf
e0001a05
NC
23# specific routines.
24#
92b93329 25fragment <<EOF
e0001a05
NC
26
27#include <xtensa-config.h>
43cd72b9 28#include "../bfd/elf-bfd.h"
43cd72b9
BW
29#include "elf/xtensa.h"
30#include "bfd.h"
e0001a05 31
2caa7ca0
BW
32/* Provide default values for new configuration settings. */
33#ifndef XSHAL_ABI
34#define XSHAL_ABI 0
35#endif
36
0c7a8e5a
AM
37static void xtensa_wild_group_interleave (lang_statement_union_type *);
38static void xtensa_colocate_output_literals (lang_statement_union_type *);
a255b6c7
BW
39static void xtensa_strip_inconsistent_linkonce_sections
40 (lang_statement_list_type *);
e0001a05
NC
41
42
e0001a05
NC
43/* This number is irrelevant until we turn on use_literal_pages */
44static bfd_vma xtensa_page_power = 12; /* 4K pages. */
45
46/* To force a page break between literals and text, change
43cd72b9 47 xtensa_use_literal_pages to "TRUE". */
e0001a05
NC
48static bfd_boolean xtensa_use_literal_pages = FALSE;
49
50#define EXTRA_VALIDATION 0
51
52
53static char *
0c7a8e5a
AM
54elf_xtensa_choose_target (int argc ATTRIBUTE_UNUSED,
55 char **argv ATTRIBUTE_UNUSED)
e0001a05
NC
56{
57 if (XCHAL_HAVE_BE)
58 return "${BIG_OUTPUT_FORMAT}";
59 else
60 return "${LITTLE_OUTPUT_FORMAT}";
61}
62
63
e0001a05 64static void
0c7a8e5a 65elf_xtensa_before_parse (void)
e0001a05
NC
66{
67 /* Just call the default hook.... Tensilica's version of this function
68 does some other work that isn't relevant here. */
69 gld${EMULATION_NAME}_before_parse ();
70}
71
72
7fa3d080
BW
73static void
74remove_section (bfd *abfd, asection *os)
43cd72b9
BW
75{
76 asection **spp;
77 for (spp = &abfd->sections; *spp; spp = &(*spp)->next)
78 if (*spp == os)
79 {
80 *spp = os->next;
81 os->owner->section_count--;
82 break;
83 }
84}
85
86
7fa3d080
BW
87static bfd_boolean
88replace_insn_sec_with_prop_sec (bfd *abfd,
89 const char *insn_sec_name,
90 const char *prop_sec_name,
91 char **error_message)
43cd72b9
BW
92{
93 asection *insn_sec;
94 asection *prop_sec;
95 bfd_byte *prop_contents = NULL;
96 bfd_byte *insn_contents = NULL;
97 unsigned entry_count;
98 unsigned entry;
d4730f92 99 Elf_Internal_Shdr *rel_hdr;
43cd72b9
BW
100 Elf_Internal_Rela *internal_relocs = NULL;
101 unsigned reloc_count;
92b93329 102
43cd72b9
BW
103 *error_message = "";
104 insn_sec = bfd_get_section_by_name (abfd, insn_sec_name);
105 if (insn_sec == NULL)
106 return TRUE;
107 entry_count = insn_sec->size / 8;
108
109 prop_sec = bfd_get_section_by_name (abfd, prop_sec_name);
110 if (prop_sec != NULL && insn_sec != NULL)
111 {
112 *error_message = _("file already has property tables");
113 return FALSE;
114 }
92b93329 115
43cd72b9
BW
116 if (insn_sec->size != 0)
117 {
76e7a751 118 insn_contents = (bfd_byte *) xmalloc (insn_sec->size);
43cd72b9
BW
119 if (! bfd_get_section_contents (abfd, insn_sec, insn_contents,
120 (file_ptr) 0, insn_sec->size))
121 {
122 *error_message = _("failed to read section contents");
123 goto cleanup;
124 }
125 }
126
2caa7ca0 127 /* Create a property table section for it. */
43cd72b9 128 prop_sec_name = strdup (prop_sec_name);
2caa7ca0 129 prop_sec = bfd_make_section_with_flags
fd361982 130 (abfd, prop_sec_name, bfd_section_flags (insn_sec));
43cd72b9 131 if (prop_sec == NULL
fd361982 132 || !bfd_set_section_alignment (prop_sec, 2))
43cd72b9
BW
133 {
134 *error_message = _("could not create new section");
135 goto cleanup;
136 }
92b93329 137
43cd72b9
BW
138 prop_sec->size = entry_count * 12;
139 prop_contents = (bfd_byte *) bfd_zalloc (abfd, prop_sec->size);
140 elf_section_data (prop_sec)->this_hdr.contents = prop_contents;
141
142 /* The entry size and size must be set to allow the linker to compute
143 the number of relocations since it does not use reloc_count. */
d4730f92
BS
144 rel_hdr = _bfd_elf_single_rel_hdr (prop_sec);
145 rel_hdr->sh_entsize = sizeof (Elf32_External_Rela);
146 rel_hdr->sh_size = _bfd_elf_single_rel_hdr (insn_sec)->sh_size;
43cd72b9
BW
147
148 if (prop_contents == NULL && prop_sec->size != 0)
149 {
150 *error_message = _("could not allocate section contents");
151 goto cleanup;
152 }
153
154 /* Read the relocations. */
155 reloc_count = insn_sec->reloc_count;
156 if (reloc_count != 0)
157 {
158 /* If there is already an internal_reloc, then save it so that the
159 read_relocs function freshly allocates a copy. */
160 Elf_Internal_Rela *saved_relocs = elf_section_data (insn_sec)->relocs;
92b93329 161
43cd72b9 162 elf_section_data (insn_sec)->relocs = NULL;
92b93329 163 internal_relocs =
43cd72b9
BW
164 _bfd_elf_link_read_relocs (abfd, insn_sec, NULL, NULL, FALSE);
165 elf_section_data (insn_sec)->relocs = saved_relocs;
92b93329 166
43cd72b9
BW
167 if (internal_relocs == NULL)
168 {
169 *error_message = _("out of memory");
170 goto cleanup;
171 }
172 }
173
174 /* Create a relocation section for the property section. */
175 if (internal_relocs != NULL)
176 {
177 elf_section_data (prop_sec)->relocs = internal_relocs;
178 prop_sec->reloc_count = reloc_count;
179 }
92b93329 180
43cd72b9
BW
181 /* Now copy each insn table entry to the prop table entry with
182 appropriate flags. */
183 for (entry = 0; entry < entry_count; ++entry)
184 {
185 unsigned value;
99ded152 186 unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_NO_TRANSFORM
43cd72b9
BW
187 | XTENSA_PROP_INSN_NO_REORDER);
188 value = bfd_get_32 (abfd, insn_contents + entry * 8 + 0);
189 bfd_put_32 (abfd, value, prop_contents + entry * 12 + 0);
190 value = bfd_get_32 (abfd, insn_contents + entry * 8 + 4);
191 bfd_put_32 (abfd, value, prop_contents + entry * 12 + 4);
192 bfd_put_32 (abfd, flags, prop_contents + entry * 12 + 8);
193 }
194
195 /* Now copy all of the relocations. Change offsets for the
196 instruction table section to offsets in the property table
197 section. */
198 if (internal_relocs)
199 {
200 unsigned i;
43cd72b9
BW
201
202 for (i = 0; i < reloc_count; i++)
203 {
204 Elf_Internal_Rela *rela;
205 unsigned r_offset;
206
207 rela = &internal_relocs[i];
208
92b93329 209 /* If this relocation is to the .xt.insn section,
43cd72b9
BW
210 change the section number and the offset. */
211 r_offset = rela->r_offset;
212 r_offset += 4 * (r_offset / 8);
213 rela->r_offset = r_offset;
214 }
215 }
216
217 remove_section (abfd, insn_sec);
92b93329 218
5e2ab612 219 free (insn_contents);
92b93329 220
43cd72b9
BW
221 return TRUE;
222
223 cleanup:
224 if (prop_sec && prop_sec->owner)
225 remove_section (abfd, prop_sec);
5e2ab612
AM
226 free (insn_contents);
227 free (internal_relocs);
43cd72b9
BW
228
229 return FALSE;
230}
231
232
233#define PROP_SEC_BASE_NAME ".xt.prop"
234#define INSN_SEC_BASE_NAME ".xt.insn"
235#define LINKONCE_SEC_OLD_TEXT_BASE_NAME ".gnu.linkonce.x."
236
237
7fa3d080
BW
238static void
239replace_instruction_table_sections (bfd *abfd, asection *sec)
43cd72b9
BW
240{
241 char *message = "";
242 const char *insn_sec_name = NULL;
243 char *prop_sec_name = NULL;
244 char *owned_prop_sec_name = NULL;
245 const char *sec_name;
92b93329 246
fd361982 247 sec_name = bfd_section_name (sec);
43cd72b9
BW
248 if (strcmp (sec_name, INSN_SEC_BASE_NAME) == 0)
249 {
250 insn_sec_name = INSN_SEC_BASE_NAME;
251 prop_sec_name = PROP_SEC_BASE_NAME;
252 }
0112cd26 253 else if (CONST_STRNEQ (sec_name, LINKONCE_SEC_OLD_TEXT_BASE_NAME))
43cd72b9
BW
254 {
255 insn_sec_name = sec_name;
256 owned_prop_sec_name = (char *) xmalloc (strlen (sec_name) + 20);
257 prop_sec_name = owned_prop_sec_name;
258 strcpy (prop_sec_name, ".gnu.linkonce.prop.t.");
259 strcat (prop_sec_name,
260 sec_name + strlen (LINKONCE_SEC_OLD_TEXT_BASE_NAME));
261 }
262 if (insn_sec_name != NULL)
263 {
264 if (! replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name,
265 &message))
266 {
871b3ab2 267 einfo (_("%P: warning: failed to convert %s table in %pB (%s); subsequent disassembly may be incomplete\n"),
43cd72b9
BW
268 insn_sec_name, abfd, message);
269 }
270 }
5e2ab612 271 free (owned_prop_sec_name);
43cd72b9
BW
272}
273
274
275/* This is called after all input sections have been opened to convert
276 instruction tables (.xt.insn, gnu.linkonce.x.*) tables into property
277 tables (.xt.prop) before any section placement. */
278
279static void
280elf_xtensa_after_open (void)
281{
43cd72b9
BW
282 /* First call the ELF version. */
283 gld${EMULATION_NAME}_after_open ();
92b93329 284
43cd72b9 285 /* Now search the input files looking for instruction table sections. */
2caa7ca0 286 LANG_FOR_EACH_INPUT_STATEMENT (f)
43cd72b9 287 {
2caa7ca0 288 asection *sec = f->the_bfd->sections;
43cd72b9
BW
289 asection *next_sec;
290
291 /* Do not use bfd_map_over_sections here since we are removing
292 sections as we iterate. */
293 while (sec != NULL)
294 {
295 next_sec = sec->next;
2caa7ca0 296 replace_instruction_table_sections (f->the_bfd, sec);
43cd72b9
BW
297 sec = next_sec;
298 }
299 }
300}
301
302
2caa7ca0
BW
303static bfd_boolean
304xt_config_info_unpack_and_check (char *data,
305 bfd_boolean *pmismatch,
306 char **pmsg)
307{
308 char *d, *key;
309 unsigned num;
310
311 *pmismatch = FALSE;
312
313 d = data;
314 while (*d)
315 {
316 key = d;
317 d = strchr (d, '=');
318 if (! d)
319 goto error;
320
321 /* Overwrite the equal sign. */
322 *d++ = 0;
323
324 /* Check if this is a quoted string or a number. */
325 if (*d == '"')
326 {
327 /* No string values are currently checked by LD;
328 just skip over the quotes. */
329 d++;
330 d = strchr (d, '"');
331 if (! d)
332 goto error;
333 /* Overwrite the trailing quote. */
334 *d++ = 0;
335 }
336 else
337 {
338 if (*d == 0)
339 goto error;
340 num = strtoul (d, &d, 0);
341
342 if (! strcmp (key, "ABI"))
343 {
344 if (num != XSHAL_ABI)
345 {
346 *pmismatch = TRUE;
347 *pmsg = "ABI does not match";
348 }
349 }
350 else if (! strcmp (key, "USE_ABSOLUTE_LITERALS"))
351 {
352 if (num != XSHAL_USE_ABSOLUTE_LITERALS)
353 {
354 *pmismatch = TRUE;
355 *pmsg = "incompatible use of the Extended L32R option";
356 }
357 }
358 }
359
360 if (*d++ != '\n')
361 goto error;
362 }
363
364 return TRUE;
365
366 error:
367 return FALSE;
368}
369
370
371#define XTINFO_NAME "Xtensa_Info"
372#define XTINFO_NAMESZ 12
373#define XTINFO_TYPE 1
374
375static void
376check_xtensa_info (bfd *abfd, asection *info_sec)
377{
378 char *data, *errmsg = "";
379 bfd_boolean mismatch;
380
381 data = xmalloc (info_sec->size);
382 if (! bfd_get_section_contents (abfd, info_sec, data, 0, info_sec->size))
df5f2391 383 einfo (_("%F%P: %pB: cannot read contents of section %pA\n"), abfd, info_sec);
2caa7ca0
BW
384
385 if (info_sec->size > 24
386 && info_sec->size >= 24 + bfd_get_32 (abfd, data + 4)
387 && bfd_get_32 (abfd, data + 0) == XTINFO_NAMESZ
388 && bfd_get_32 (abfd, data + 8) == XTINFO_TYPE
389 && strcmp (data + 12, XTINFO_NAME) == 0
390 && xt_config_info_unpack_and_check (data + 12 + XTINFO_NAMESZ,
391 &mismatch, &errmsg))
392 {
393 if (mismatch)
df5f2391 394 einfo (_("%P: %pB: warning: incompatible Xtensa configuration (%s)\n"),
2caa7ca0
BW
395 abfd, errmsg);
396 }
397 else
df5f2391 398 einfo (_("%P: %pB: warning: cannot parse .xtensa.info section\n"), abfd);
2caa7ca0
BW
399
400 free (data);
401}
402
403
e0001a05
NC
404/* This is called after the sections have been attached to output
405 sections, but before any sizes or addresses have been set. */
406
0c7a8e5a
AM
407static void
408elf_xtensa_before_allocation (void)
e0001a05 409{
2caa7ca0
BW
410 asection *info_sec, *first_info_sec;
411 bfd *first_bfd;
e0001a05
NC
412 bfd_boolean is_big_endian = XCHAL_HAVE_BE;
413
414 /* Check that the output endianness matches the Xtensa
415 configuration. The BFD library always includes both big and
416 little endian target vectors for Xtensa, but it only supports the
417 detailed instruction encode/decode operations (such as are
418 required to process relocations) for the selected Xtensa
419 configuration. */
420
f13a99db
AM
421 if (is_big_endian
422 && link_info.output_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
e0001a05
NC
423 {
424 einfo (_("%F%P: little endian output does not match "
425 "Xtensa configuration\n"));
426 }
f13a99db
AM
427 if (!is_big_endian
428 && link_info.output_bfd->xvec->byteorder == BFD_ENDIAN_BIG)
e0001a05
NC
429 {
430 einfo (_("%F%P: big endian output does not match "
431 "Xtensa configuration\n"));
432 }
433
2caa7ca0
BW
434 /* Keep track of the first input .xtensa.info section, and as a fallback,
435 the first input bfd where a .xtensa.info section could be created.
436 After the input .xtensa.info has been checked, the contents of the
437 first one will be replaced with the output .xtensa.info table. */
438 first_info_sec = 0;
439 first_bfd = 0;
e0001a05 440
2caa7ca0
BW
441 LANG_FOR_EACH_INPUT_STATEMENT (f)
442 {
443 /* Check that the endianness for each input file matches the output.
444 The merge_private_bfd_data hook has already reported any mismatches
445 as errors, but those errors are not fatal. At this point, we
446 cannot go any further if there are any mismatches. */
447 if ((is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
448 || (!is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_BIG))
871b3ab2 449 einfo (_("%F%P: cross-endian linking for %pB not supported\n"),
2caa7ca0
BW
450 f->the_bfd);
451
452 if (! first_bfd)
453 first_bfd = f->the_bfd;
454
455 info_sec = bfd_get_section_by_name (f->the_bfd, ".xtensa.info");
456 if (! info_sec)
457 continue;
458
459 if (! first_info_sec)
460 first_info_sec = info_sec;
461
462 /* Unpack the .xtensa.info section and check it against the current
463 Xtensa configuration. */
464 check_xtensa_info (f->the_bfd, info_sec);
465
466 /* Do not include this copy of .xtensa.info in the output. */
467 info_sec->size = 0;
468 info_sec->flags |= SEC_EXCLUDE;
469 }
470
471 /* Reuse the first .xtensa.info input section to hold the output
472 .xtensa.info; or, if none were found, create a new section in the
473 first input bfd (assuming there is one). */
474 info_sec = first_info_sec;
475 if (! info_sec && first_bfd)
476 {
477 info_sec = bfd_make_section_with_flags (first_bfd, ".xtensa.info",
478 SEC_HAS_CONTENTS | SEC_READONLY);
479 if (! info_sec)
480 einfo (_("%F%P: failed to create .xtensa.info section\n"));
481 }
482 if (info_sec)
e0001a05 483 {
2caa7ca0
BW
484 int xtensa_info_size;
485 char *data;
486
487 info_sec->flags &= ~SEC_EXCLUDE;
488 info_sec->flags |= SEC_IN_MEMORY;
489
490 data = xmalloc (100);
491 sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n",
492 XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI);
493 xtensa_info_size = strlen (data) + 1;
494
495 /* Add enough null terminators to pad to a word boundary. */
496 do
497 data[xtensa_info_size++] = 0;
498 while ((xtensa_info_size & 3) != 0);
499
500 info_sec->size = 12 + XTINFO_NAMESZ + xtensa_info_size;
501 info_sec->contents = xmalloc (info_sec->size);
502 bfd_put_32 (info_sec->owner, XTINFO_NAMESZ, info_sec->contents + 0);
503 bfd_put_32 (info_sec->owner, xtensa_info_size, info_sec->contents + 4);
504 bfd_put_32 (info_sec->owner, XTINFO_TYPE, info_sec->contents + 8);
505 memcpy (info_sec->contents + 12, XTINFO_NAME, XTINFO_NAMESZ);
506 memcpy (info_sec->contents + 12 + XTINFO_NAMESZ, data, xtensa_info_size);
507 free (data);
e0001a05
NC
508 }
509
510 /* Enable relaxation by default if the "--no-relax" option was not
511 specified. This is done here instead of in the before_parse hook
512 because there is a check in main() to prohibit use of --relax and
513 -r together and that combination should be allowed for Xtensa. */
28d5f677
NC
514 if (RELAXATION_DISABLED_BY_DEFAULT)
515 ENABLE_RELAXATION;
e0001a05 516
a255b6c7
BW
517 xtensa_strip_inconsistent_linkonce_sections (stat_ptr);
518
e0001a05
NC
519 gld${EMULATION_NAME}_before_allocation ();
520
521 xtensa_wild_group_interleave (stat_ptr->head);
28d5f677
NC
522
523 if (RELAXATION_ENABLED)
e0001a05
NC
524 xtensa_colocate_output_literals (stat_ptr->head);
525
526 /* TBD: We need to force the page alignments to here and only do
527 them as needed for the entire output section. Finally, if this
1049f94e 528 is a relocatable link then we need to add alignment notes so
e0001a05
NC
529 that the literals can be separated later. */
530}
531
532
533typedef struct wildcard_list section_name_list;
534
535typedef struct reloc_deps_e_t reloc_deps_e;
536typedef struct reloc_deps_section_t reloc_deps_section;
537typedef struct reloc_deps_graph_t reloc_deps_graph;
538
539
540struct reloc_deps_e_t
541{
542 asection *src; /* Contains l32rs. */
543 asection *tgt; /* Contains literals. */
544 reloc_deps_e *next;
545};
546
547/* Place these in the userdata field. */
548struct reloc_deps_section_t
549{
550 reloc_deps_e *preds;
551 reloc_deps_e *succs;
552 bfd_boolean is_only_literal;
553};
554
555
556struct reloc_deps_graph_t
557{
558 size_t count;
559 size_t size;
560 asection **sections;
561};
562
563static void xtensa_layout_wild
0c7a8e5a 564 (const reloc_deps_graph *, lang_wild_statement_type *);
e0001a05 565
0c7a8e5a
AM
566typedef void (*deps_callback_t) (asection *, /* src_sec */
567 bfd_vma, /* src_offset */
568 asection *, /* target_sec */
569 bfd_vma, /* target_offset */
570 void *); /* closure */
e0001a05 571
e0001a05 572extern bfd_boolean xtensa_callback_required_dependence
0c7a8e5a 573 (bfd *, asection *, struct bfd_link_info *, deps_callback_t, void *);
7fa3d080 574static void xtensa_ldlang_clear_addresses (lang_statement_union_type *);
e0001a05 575static bfd_boolean ld_local_file_relocations_fit
0c7a8e5a 576 (lang_statement_union_type *, const reloc_deps_graph *);
e0001a05 577static bfd_vma ld_assign_relative_paged_dot
0c7a8e5a
AM
578 (bfd_vma, lang_statement_union_type *, const reloc_deps_graph *,
579 bfd_boolean);
e0001a05 580static bfd_vma ld_xtensa_insert_page_offsets
0c7a8e5a 581 (bfd_vma, lang_statement_union_type *, reloc_deps_graph *, bfd_boolean);
e0001a05 582#if EXTRA_VALIDATION
7fa3d080 583static size_t ld_count_children (lang_statement_union_type *);
e0001a05 584#endif
e0001a05
NC
585
586extern lang_statement_list_type constructor_list;
587
0c7a8e5a
AM
588static reloc_deps_section *
589xtensa_get_section_deps (const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
590 asection *sec)
e0001a05
NC
591{
592 /* We have a separate function for this so that
593 we could in the future keep a completely independent
594 structure that maps a section to its dependence edges.
a48931cc
AM
595 For now, we place these in the sec->userdata field.
596 This doesn't clash with ldlang.c use of userdata for output
597 sections, and during map output for input sections, since the
598 xtensa use is only for input sections and only extant in
599 before_allocation. */
600 reloc_deps_section *sec_deps = bfd_section_userdata (sec);
e0001a05
NC
601 return sec_deps;
602}
603
0c7a8e5a
AM
604static void
605xtensa_set_section_deps (const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
606 asection *sec,
607 reloc_deps_section *deps_section)
e0001a05 608{
a48931cc 609 bfd_set_section_userdata (sec, deps_section);
e0001a05
NC
610}
611
612
613/* This is used to keep a list of all of the sections participating in
614 the graph so we can clean them up quickly. */
615
0c7a8e5a
AM
616static void
617xtensa_append_section_deps (reloc_deps_graph *deps, asection *sec)
e0001a05
NC
618{
619 if (deps->size <= deps->count)
620 {
621 asection **new_sections;
622 size_t i;
623 size_t new_size;
0c7a8e5a 624
e0001a05
NC
625 new_size = deps->size * 2;
626 if (new_size == 0)
627 new_size = 20;
0c7a8e5a
AM
628
629 new_sections = xmalloc (sizeof (asection *) * new_size);
630 memset (new_sections, 0, sizeof (asection *) * new_size);
631 for (i = 0; i < deps->count; i++)
e0001a05
NC
632 {
633 new_sections[i] = deps->sections[i];
634 }
5e2ab612 635 free (deps->sections);
e0001a05
NC
636 deps->sections = new_sections;
637 deps->size = new_size;
638 }
639 deps->sections[deps->count] = sec;
640 deps->count++;
641}
642
643
0c7a8e5a
AM
644static void
645free_reloc_deps_graph (reloc_deps_graph *deps)
e0001a05
NC
646{
647 size_t i;
648 for (i = 0; i < deps->count; i++)
649 {
650 asection *sec = deps->sections[i];
651 reloc_deps_section *sec_deps;
652 sec_deps = xtensa_get_section_deps (deps, sec);
0c7a8e5a 653 if (sec_deps)
e0001a05
NC
654 {
655 reloc_deps_e *next;
656 while (sec_deps->succs != NULL)
657 {
658 next = sec_deps->succs->next;
659 free (sec_deps->succs);
660 sec_deps->succs = next;
661 }
0c7a8e5a 662
e0001a05
NC
663 while (sec_deps->preds != NULL)
664 {
665 next = sec_deps->preds->next;
666 free (sec_deps->preds);
667 sec_deps->preds = next;
668 }
669 free (sec_deps);
670 }
671 xtensa_set_section_deps (deps, sec, NULL);
672 }
5e2ab612 673 free (deps->sections);
e0001a05
NC
674 free (deps);
675}
676
677
0c7a8e5a
AM
678static bfd_boolean
679section_is_source (const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
680 lang_statement_union_type *s)
e0001a05
NC
681{
682 asection *sec;
683 const reloc_deps_section *sec_deps;
684
685 if (s->header.type != lang_input_section_enum)
686 return FALSE;
687 sec = s->input_section.section;
688
689 sec_deps = xtensa_get_section_deps (deps, sec);
0c7a8e5a 690 return sec_deps && sec_deps->succs != NULL;
e0001a05
NC
691}
692
693
0c7a8e5a
AM
694static bfd_boolean
695section_is_target (const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
696 lang_statement_union_type *s)
e0001a05
NC
697{
698 asection *sec;
699 const reloc_deps_section *sec_deps;
700
701 if (s->header.type != lang_input_section_enum)
702 return FALSE;
703 sec = s->input_section.section;
704
705 sec_deps = xtensa_get_section_deps (deps, sec);
0c7a8e5a 706 return sec_deps && sec_deps->preds != NULL;
e0001a05
NC
707}
708
7fa3d080 709
0c7a8e5a
AM
710static bfd_boolean
711section_is_source_or_target (const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
712 lang_statement_union_type *s)
e0001a05
NC
713{
714 return (section_is_source (deps, s)
715 || section_is_target (deps, s));
716}
717
718
719typedef struct xtensa_ld_iter_stack_t xtensa_ld_iter_stack;
720typedef struct xtensa_ld_iter_t xtensa_ld_iter;
721
722struct xtensa_ld_iter_t
723{
724 lang_statement_union_type *parent; /* Parent of the list. */
725 lang_statement_list_type *l; /* List that holds it. */
726 lang_statement_union_type **loc; /* Place in the list. */
727};
728
729struct xtensa_ld_iter_stack_t
730{
731 xtensa_ld_iter iterloc; /* List that hold it. */
0c7a8e5a 732
e0001a05
NC
733 xtensa_ld_iter_stack *next; /* Next in the stack. */
734 xtensa_ld_iter_stack *prev; /* Back pointer for stack. */
735};
736
e0001a05 737
0c7a8e5a
AM
738static void
739ld_xtensa_move_section_after (xtensa_ld_iter *to, xtensa_ld_iter *current)
e0001a05
NC
740{
741 lang_statement_union_type *to_next;
742 lang_statement_union_type *current_next;
743 lang_statement_union_type **e;
744
745#if EXTRA_VALIDATION
746 size_t old_to_count, new_to_count;
747 size_t old_current_count, new_current_count;
748#endif
749
750 if (to == current)
751 return;
0c7a8e5a 752
e0001a05
NC
753#if EXTRA_VALIDATION
754 old_to_count = ld_count_children (to->parent);
755 old_current_count = ld_count_children (current->parent);
756#endif
757
758 to_next = *(to->loc);
759 current_next = (*current->loc)->header.next;
0c7a8e5a 760
e0001a05 761 *(to->loc) = *(current->loc);
0c7a8e5a 762
e0001a05
NC
763 *(current->loc) = current_next;
764 (*(to->loc))->header.next = to_next;
765
766 /* reset "to" list tail */
767 for (e = &to->l->head; *e != NULL; e = &(*e)->header.next)
768 ;
769 to->l->tail = e;
770
771 /* reset "current" list tail */
772 for (e = &current->l->head; *e != NULL; e = &(*e)->header.next)
773 ;
774 current->l->tail = e;
775
776#if EXTRA_VALIDATION
777 new_to_count = ld_count_children (to->parent);
778 new_current_count = ld_count_children (current->parent);
779
0c7a8e5a 780 ASSERT ((old_to_count + old_current_count)
e0001a05
NC
781 == (new_to_count + new_current_count));
782#endif
783}
784
785
786/* Can only be called with lang_statements that have lists. Returns
43cd72b9 787 FALSE if the list is empty. */
e0001a05 788
0c7a8e5a
AM
789static bfd_boolean
790iter_stack_empty (xtensa_ld_iter_stack **stack_p)
e0001a05 791{
0c7a8e5a 792 return *stack_p == NULL;
e0001a05
NC
793}
794
795
796static bfd_boolean
0c7a8e5a
AM
797iter_stack_push (xtensa_ld_iter_stack **stack_p,
798 lang_statement_union_type *parent)
e0001a05
NC
799{
800 xtensa_ld_iter_stack *stack;
801 lang_statement_list_type *l = NULL;
802
0c7a8e5a 803 switch (parent->header.type)
e0001a05
NC
804 {
805 case lang_output_section_statement_enum:
806 l = &parent->output_section_statement.children;
807 break;
808 case lang_wild_statement_enum:
809 l = &parent->wild_statement.children;
810 break;
811 case lang_group_statement_enum:
812 l = &parent->group_statement.children;
813 break;
814 default:
815 ASSERT (0);
816 return FALSE;
817 }
818
819 /* Empty. do not push. */
0c7a8e5a 820 if (l->tail == &l->head)
e0001a05
NC
821 return FALSE;
822
0c7a8e5a 823 stack = xmalloc (sizeof (xtensa_ld_iter_stack));
e0001a05
NC
824 memset (stack, 0, sizeof (xtensa_ld_iter_stack));
825 stack->iterloc.parent = parent;
826 stack->iterloc.l = l;
827 stack->iterloc.loc = &l->head;
828
829 stack->next = *stack_p;
830 stack->prev = NULL;
0c7a8e5a 831 if (*stack_p != NULL)
e0001a05
NC
832 (*stack_p)->prev = stack;
833 *stack_p = stack;
834 return TRUE;
835}
836
837
0c7a8e5a
AM
838static void
839iter_stack_pop (xtensa_ld_iter_stack **stack_p)
e0001a05
NC
840{
841 xtensa_ld_iter_stack *stack;
842
843 stack = *stack_p;
844
0c7a8e5a 845 if (stack == NULL)
e0001a05
NC
846 {
847 ASSERT (stack != NULL);
848 return;
849 }
850
0c7a8e5a 851 if (stack->next != NULL)
e0001a05
NC
852 stack->next->prev = NULL;
853
854 *stack_p = stack->next;
855 free (stack);
856}
857
858
859/* This MUST be called if, during iteration, the user changes the
860 underlying structure. It will check for a NULL current and advance
861 accordingly. */
862
863static void
0c7a8e5a 864iter_stack_update (xtensa_ld_iter_stack **stack_p)
e0001a05
NC
865{
866 if (!iter_stack_empty (stack_p)
0c7a8e5a 867 && (*(*stack_p)->iterloc.loc) == NULL)
e0001a05
NC
868 {
869 iter_stack_pop (stack_p);
870
871 while (!iter_stack_empty (stack_p)
872 && ((*(*stack_p)->iterloc.loc)->header.next == NULL))
873 {
874 iter_stack_pop (stack_p);
875 }
876 if (!iter_stack_empty (stack_p))
877 (*stack_p)->iterloc.loc = &(*(*stack_p)->iterloc.loc)->header.next;
878 }
879}
880
881
0c7a8e5a
AM
882static void
883iter_stack_next (xtensa_ld_iter_stack **stack_p)
e0001a05
NC
884{
885 xtensa_ld_iter_stack *stack;
886 lang_statement_union_type *current;
887 stack = *stack_p;
888
889 current = *stack->iterloc.loc;
890 /* If we are on the first element. */
0c7a8e5a 891 if (current != NULL)
e0001a05 892 {
0c7a8e5a 893 switch (current->header.type)
e0001a05
NC
894 {
895 case lang_output_section_statement_enum:
896 case lang_wild_statement_enum:
897 case lang_group_statement_enum:
898 /* If the list if not empty, we are done. */
899 if (iter_stack_push (stack_p, *stack->iterloc.loc))
900 return;
901 /* Otherwise increment the pointer as normal. */
902 break;
903 default:
904 break;
905 }
906 }
907
908 while (!iter_stack_empty (stack_p)
909 && ((*(*stack_p)->iterloc.loc)->header.next == NULL))
910 {
911 iter_stack_pop (stack_p);
912 }
913 if (!iter_stack_empty (stack_p))
914 (*stack_p)->iterloc.loc = &(*(*stack_p)->iterloc.loc)->header.next;
915}
916
917
918static lang_statement_union_type *
0c7a8e5a 919iter_stack_current (xtensa_ld_iter_stack **stack_p)
e0001a05
NC
920{
921 return *((*stack_p)->iterloc.loc);
922}
923
924
925/* The iter stack is a preorder. */
926
0c7a8e5a
AM
927static void
928iter_stack_create (xtensa_ld_iter_stack **stack_p,
929 lang_statement_union_type *parent)
e0001a05
NC
930{
931 iter_stack_push (stack_p, parent);
932}
933
934
0c7a8e5a 935static void
7fa3d080 936iter_stack_copy_current (xtensa_ld_iter_stack **stack_p, xtensa_ld_iter *front)
e0001a05
NC
937{
938 *front = (*stack_p)->iterloc;
939}
940
941
0c7a8e5a
AM
942static void
943xtensa_colocate_literals (reloc_deps_graph *deps,
944 lang_statement_union_type *statement)
e0001a05
NC
945{
946 /* Keep a stack of pointers to control iteration through the contours. */
947 xtensa_ld_iter_stack *stack = NULL;
948 xtensa_ld_iter_stack **stack_p = &stack;
949
950 xtensa_ld_iter front; /* Location where new insertion should occur. */
951 xtensa_ld_iter *front_p = NULL;
952
953 xtensa_ld_iter current; /* Location we are checking. */
954 xtensa_ld_iter *current_p = NULL;
955 bfd_boolean in_literals = FALSE;
956
957 if (deps->count == 0)
958 return;
959
e0001a05
NC
960 iter_stack_create (stack_p, statement);
961
0c7a8e5a 962 while (!iter_stack_empty (stack_p))
e0001a05
NC
963 {
964 bfd_boolean skip_increment = FALSE;
965 lang_statement_union_type *l = iter_stack_current (stack_p);
0c7a8e5a
AM
966
967 switch (l->header.type)
e0001a05
NC
968 {
969 case lang_assignment_statement_enum:
970 /* Any assignment statement should block reordering across it. */
971 front_p = NULL;
972 in_literals = FALSE;
973 break;
974
975 case lang_input_section_enum:
976 if (front_p == NULL)
977 {
978 in_literals = (section_is_target (deps, l)
979 && !section_is_source (deps, l));
0c7a8e5a 980 if (in_literals)
e0001a05
NC
981 {
982 front_p = &front;
983 iter_stack_copy_current (stack_p, front_p);
984 }
0c7a8e5a 985 }
e0001a05
NC
986 else
987 {
988 bfd_boolean is_target;
989 current_p = &current;
990 iter_stack_copy_current (stack_p, current_p);
991 is_target = (section_is_target (deps, l)
992 && !section_is_source (deps, l));
993
994 if (in_literals)
995 {
996 iter_stack_copy_current (stack_p, front_p);
997 if (!is_target)
998 in_literals = FALSE;
999 }
1000 else
1001 {
0c7a8e5a 1002 if (is_target)
e0001a05
NC
1003 {
1004 /* Try to insert in place. */
1005 ld_xtensa_move_section_after (front_p, current_p);
0c7a8e5a 1006 ld_assign_relative_paged_dot (0x100000,
e0001a05
NC
1007 statement,
1008 deps,
1009 xtensa_use_literal_pages);
0c7a8e5a 1010
e0001a05
NC
1011 /* We use this code because it's already written. */
1012 if (!ld_local_file_relocations_fit (statement, deps))
1013 {
1014 /* Move it back. */
1015 ld_xtensa_move_section_after (current_p, front_p);
1016 /* Reset the literal placement. */
1017 iter_stack_copy_current (stack_p, front_p);
1018 }
0c7a8e5a 1019 else
e0001a05
NC
1020 {
1021 /* Move front pointer up by one. */
1022 front_p->loc = &(*front_p->loc)->header.next;
1023
1024 /* Do not increment the current pointer. */
1025 skip_increment = TRUE;
1026 }
1027 }
1028 }
1029 }
1030 break;
1031 default:
1032 break;
1033 }
1034
1035 if (!skip_increment)
1036 iter_stack_next (stack_p);
1037 else
1038 /* Be careful to update the stack_p if it now is a null. */
1039 iter_stack_update (stack_p);
1040 }
0c7a8e5a 1041
e0001a05
NC
1042 lang_for_each_statement_worker (xtensa_ldlang_clear_addresses, statement);
1043}
1044
1045
0c7a8e5a
AM
1046static void
1047xtensa_move_dependencies_to_front (reloc_deps_graph *deps,
1048 lang_wild_statement_type *w)
e0001a05
NC
1049{
1050 /* Keep a front pointer and a current pointer. */
1051 lang_statement_union_type **front;
1052 lang_statement_union_type **current;
1053
1054 /* Walk to the end of the targets. */
1055 for (front = &w->children.head;
1056 (*front != NULL) && section_is_source_or_target (deps, *front);
1057 front = &(*front)->header.next)
1058 ;
1059
1060 if (*front == NULL)
1061 return;
1062
1063 current = &(*front)->header.next;
0c7a8e5a 1064 while (*current != NULL)
e0001a05
NC
1065 {
1066 if (section_is_source_or_target (deps, *current))
1067 {
1068 /* Insert in place. */
1069 xtensa_ld_iter front_iter;
1070 xtensa_ld_iter current_iter;
1071
1072 front_iter.parent = (lang_statement_union_type *) w;
1073 front_iter.l = &w->children;
1074 front_iter.loc = front;
1075
1076 current_iter.parent = (lang_statement_union_type *) w;
1077 current_iter.l = &w->children;
1078 current_iter.loc = current;
1079
1080 ld_xtensa_move_section_after (&front_iter, &current_iter);
1081 front = &(*front)->header.next;
1082 }
1083 else
1084 {
1085 current = &(*current)->header.next;
1086 }
1087 }
1088}
1089
1090
1091static bfd_boolean
7fa3d080 1092deps_has_sec_edge (const reloc_deps_graph *deps, asection *src, asection *tgt)
e0001a05
NC
1093{
1094 const reloc_deps_section *sec_deps;
1095 const reloc_deps_e *sec_deps_e;
1096
1097 sec_deps = xtensa_get_section_deps (deps, src);
1098 if (sec_deps == NULL)
1099 return FALSE;
0c7a8e5a 1100
e0001a05 1101 for (sec_deps_e = sec_deps->succs;
0c7a8e5a 1102 sec_deps_e != NULL;
e0001a05
NC
1103 sec_deps_e = sec_deps_e->next)
1104 {
1105 ASSERT (sec_deps_e->src == src);
0c7a8e5a 1106 if (sec_deps_e->tgt == tgt)
e0001a05
NC
1107 return TRUE;
1108 }
1109 return FALSE;
1110}
1111
1112
1113static bfd_boolean
0c7a8e5a
AM
1114deps_has_edge (const reloc_deps_graph *deps,
1115 lang_statement_union_type *src,
1116 lang_statement_union_type *tgt)
e0001a05
NC
1117{
1118 if (!section_is_source (deps, src))
1119 return FALSE;
1120 if (!section_is_target (deps, tgt))
1121 return FALSE;
1122
1123 if (src->header.type != lang_input_section_enum)
1124 return FALSE;
1125 if (tgt->header.type != lang_input_section_enum)
1126 return FALSE;
0c7a8e5a 1127
e0001a05
NC
1128 return deps_has_sec_edge (deps, src->input_section.section,
1129 tgt->input_section.section);
1130}
1131
1132
1133static void
7fa3d080 1134add_deps_edge (reloc_deps_graph *deps, asection *src_sec, asection *tgt_sec)
e0001a05
NC
1135{
1136 reloc_deps_section *src_sec_deps;
1137 reloc_deps_section *tgt_sec_deps;
1138
1139 reloc_deps_e *src_edge;
1140 reloc_deps_e *tgt_edge;
1141
1142 if (deps_has_sec_edge (deps, src_sec, tgt_sec))
1143 return;
0c7a8e5a 1144
e0001a05
NC
1145 src_sec_deps = xtensa_get_section_deps (deps, src_sec);
1146 if (src_sec_deps == NULL)
1147 {
1148 /* Add a section. */
0c7a8e5a 1149 src_sec_deps = xmalloc (sizeof (reloc_deps_section));
e0001a05
NC
1150 memset (src_sec_deps, 0, sizeof (reloc_deps_section));
1151 src_sec_deps->is_only_literal = 0;
1152 src_sec_deps->preds = NULL;
1153 src_sec_deps->succs = NULL;
1154 xtensa_set_section_deps (deps, src_sec, src_sec_deps);
1155 xtensa_append_section_deps (deps, src_sec);
1156 }
1157
1158 tgt_sec_deps = xtensa_get_section_deps (deps, tgt_sec);
1159 if (tgt_sec_deps == NULL)
1160 {
1161 /* Add a section. */
0c7a8e5a 1162 tgt_sec_deps = xmalloc (sizeof (reloc_deps_section));
e0001a05
NC
1163 memset (tgt_sec_deps, 0, sizeof (reloc_deps_section));
1164 tgt_sec_deps->is_only_literal = 0;
1165 tgt_sec_deps->preds = NULL;
1166 tgt_sec_deps->succs = NULL;
1167 xtensa_set_section_deps (deps, tgt_sec, tgt_sec_deps);
1168 xtensa_append_section_deps (deps, tgt_sec);
1169 }
1170
1171 /* Add the edges. */
0c7a8e5a 1172 src_edge = xmalloc (sizeof (reloc_deps_e));
e0001a05
NC
1173 memset (src_edge, 0, sizeof (reloc_deps_e));
1174 src_edge->src = src_sec;
1175 src_edge->tgt = tgt_sec;
1176 src_edge->next = src_sec_deps->succs;
1177 src_sec_deps->succs = src_edge;
1178
0c7a8e5a 1179 tgt_edge = xmalloc (sizeof (reloc_deps_e));
e0001a05
NC
1180 memset (tgt_edge, 0, sizeof (reloc_deps_e));
1181 tgt_edge->src = src_sec;
1182 tgt_edge->tgt = tgt_sec;
1183 tgt_edge->next = tgt_sec_deps->preds;
1184 tgt_sec_deps->preds = tgt_edge;
1185}
1186
1187
0c7a8e5a
AM
1188static void
1189build_deps_graph_callback (asection *src_sec,
1190 bfd_vma src_offset ATTRIBUTE_UNUSED,
1191 asection *target_sec,
1192 bfd_vma target_offset ATTRIBUTE_UNUSED,
1193 void *closure)
e0001a05 1194{
0c7a8e5a 1195 reloc_deps_graph *deps = closure;
e0001a05
NC
1196
1197 /* If the target is defined. */
1198 if (target_sec != NULL)
1199 add_deps_edge (deps, src_sec, target_sec);
1200}
1201
1202
0c7a8e5a
AM
1203static reloc_deps_graph *
1204ld_build_required_section_dependence (lang_statement_union_type *s)
e0001a05
NC
1205{
1206 reloc_deps_graph *deps;
1207 xtensa_ld_iter_stack *stack = NULL;
1208
0c7a8e5a 1209 deps = xmalloc (sizeof (reloc_deps_graph));
e0001a05
NC
1210 deps->sections = NULL;
1211 deps->count = 0;
1212 deps->size = 0;
0c7a8e5a 1213
e0001a05
NC
1214 for (iter_stack_create (&stack, s);
1215 !iter_stack_empty (&stack);
0c7a8e5a 1216 iter_stack_next (&stack))
e0001a05
NC
1217 {
1218 lang_statement_union_type *l = iter_stack_current (&stack);
1219
abf874aa 1220 if (l == NULL && link_info.non_contiguous_regions)
53215f21
CL
1221 einfo (_("%F%P: Relaxation not supported with "
1222 "--enable-non-contiguous-regions.\n"));
abf874aa 1223
e0001a05
NC
1224 if (l->header.type == lang_input_section_enum)
1225 {
1226 lang_input_section_type *input;
1227 input = &l->input_section;
7b986e99 1228 xtensa_callback_required_dependence (input->section->owner,
e0001a05
NC
1229 input->section,
1230 &link_info,
1231 /* Use the same closure. */
1232 build_deps_graph_callback,
0c7a8e5a 1233 deps);
e0001a05
NC
1234 }
1235 }
1236 return deps;
1237}
1238
1239
1240#if EXTRA_VALIDATION
0c7a8e5a
AM
1241static size_t
1242ld_count_children (lang_statement_union_type *s)
e0001a05
NC
1243{
1244 size_t count = 0;
1245 xtensa_ld_iter_stack *stack = NULL;
1246 for (iter_stack_create (&stack, s);
1247 !iter_stack_empty (&stack);
0c7a8e5a 1248 iter_stack_next (&stack))
e0001a05
NC
1249 {
1250 lang_statement_union_type *l = iter_stack_current (&stack);
1251 ASSERT (l != NULL);
1252 count++;
1253 }
1254 return count;
1255}
1256#endif /* EXTRA_VALIDATION */
1257
1258
a255b6c7
BW
1259/* Check if a particular section is included in the link. This will only
1260 be true for one instance of a particular linkonce section. */
1261
1262static bfd_boolean input_section_found = FALSE;
1263static asection *input_section_target = NULL;
1264
1265static void
1266input_section_linked_worker (lang_statement_union_type *statement)
1267{
1268 if ((statement->header.type == lang_input_section_enum
1269 && (statement->input_section.section == input_section_target)))
1270 input_section_found = TRUE;
1271}
1272
1273static bfd_boolean
1274input_section_linked (asection *sec)
1275{
1276 input_section_found = FALSE;
1277 input_section_target = sec;
1278 lang_for_each_statement_worker (input_section_linked_worker, stat_ptr->head);
1279 return input_section_found;
1280}
1281
1282
a77dc2cc 1283/* Strip out any linkonce property tables or XCC exception tables where the
a255b6c7
BW
1284 associated linkonce text is from a different object file. Normally,
1285 a matching set of linkonce sections is taken from the same object file,
1286 but sometimes the files are compiled differently so that some of the
1287 linkonce sections are not present in all files. Stripping the
1288 inconsistent sections like this is not completely robust -- a much
1289 better solution is to use comdat groups. */
1290
1291static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
1292
1293static bfd_boolean
1294is_inconsistent_linkonce_section (asection *sec)
1295{
1296 bfd *abfd = sec->owner;
fd361982 1297 const char *sec_name = bfd_section_name (sec);
a77dc2cc 1298 const char *name;
a255b6c7 1299
fd361982 1300 if ((bfd_section_flags (sec) & SEC_LINK_ONCE) == 0
a255b6c7
BW
1301 || strncmp (sec_name, ".gnu.linkonce.", linkonce_len) != 0)
1302 return FALSE;
1303
a77dc2cc
BW
1304 /* Check if this is an Xtensa property section or an exception table
1305 for Tensilica's XCC compiler. */
1306 name = sec_name + linkonce_len;
1307 if (CONST_STRNEQ (name, "prop."))
e7d17e71 1308 name = strchr (name + 5, '.') ? strchr (name + 5, '.') + 1 : name + 5;
a77dc2cc
BW
1309 else if (name[1] == '.'
1310 && (name[0] == 'p' || name[0] == 'e' || name[0] == 'h'))
1311 name += 2;
1312 else
1313 name = 0;
644143c8
BW
1314
1315 if (name)
a255b6c7 1316 {
644143c8 1317 char *dep_sec_name = xmalloc (strlen (sec_name) + 1);
a255b6c7
BW
1318 asection *dep_sec;
1319
1320 /* Get the associated linkonce text section and check if it is
1321 included in the link. If not, this section is inconsistent
1322 and should be stripped. */
644143c8
BW
1323 strcpy (dep_sec_name, ".gnu.linkonce.t.");
1324 strcat (dep_sec_name, name);
a255b6c7
BW
1325 dep_sec = bfd_get_section_by_name (abfd, dep_sec_name);
1326 if (dep_sec == NULL || ! input_section_linked (dep_sec))
1327 {
1328 free (dep_sec_name);
1329 return TRUE;
1330 }
1331 free (dep_sec_name);
1332 }
1333
1334 return FALSE;
1335}
1336
1337
1338static void
1339xtensa_strip_inconsistent_linkonce_sections (lang_statement_list_type *slist)
1340{
1341 lang_statement_union_type **s_p = &slist->head;
1342 while (*s_p)
1343 {
1344 lang_statement_union_type *s = *s_p;
1345 lang_statement_union_type *s_next = (*s_p)->header.next;
1346
1347 switch (s->header.type)
1348 {
1349 case lang_input_section_enum:
1350 if (is_inconsistent_linkonce_section (s->input_section.section))
1351 {
b2f28975 1352 s->input_section.section->output_section = bfd_abs_section_ptr;
a255b6c7
BW
1353 *s_p = s_next;
1354 continue;
1355 }
1356 break;
1357
1358 case lang_constructors_statement_enum:
1359 xtensa_strip_inconsistent_linkonce_sections (&constructor_list);
1360 break;
1361
1362 case lang_output_section_statement_enum:
1363 if (s->output_section_statement.children.head)
1364 xtensa_strip_inconsistent_linkonce_sections
1365 (&s->output_section_statement.children);
1366 break;
1367
1368 case lang_wild_statement_enum:
1369 xtensa_strip_inconsistent_linkonce_sections
1370 (&s->wild_statement.children);
1371 break;
1372
1373 case lang_group_statement_enum:
1374 xtensa_strip_inconsistent_linkonce_sections
1375 (&s->group_statement.children);
1376 break;
1377
1378 case lang_data_statement_enum:
1379 case lang_reloc_statement_enum:
1380 case lang_object_symbols_statement_enum:
1381 case lang_output_statement_enum:
1382 case lang_target_statement_enum:
1383 case lang_input_statement_enum:
1384 case lang_assignment_statement_enum:
1385 case lang_padding_statement_enum:
1386 case lang_address_statement_enum:
1387 case lang_fill_statement_enum:
1388 break;
1389
1390 default:
1391 FAIL ();
1392 break;
1393 }
1394
1395 s_p = &(*s_p)->header.next;
1396 }
1397
1398 /* Reset the tail of the list, in case the last entry was removed. */
1399 if (s_p != slist->tail)
1400 slist->tail = s_p;
1401}
1402
1403
0c7a8e5a
AM
1404static void
1405xtensa_wild_group_interleave_callback (lang_statement_union_type *statement)
e0001a05
NC
1406{
1407 lang_wild_statement_type *w;
1408 reloc_deps_graph *deps;
1409 if (statement->header.type == lang_wild_statement_enum)
1410 {
1411#if EXTRA_VALIDATION
1412 size_t old_child_count;
1413 size_t new_child_count;
1414#endif
1415 bfd_boolean no_reorder;
1416
1417 w = &statement->wild_statement;
1418
1419 no_reorder = FALSE;
1420
1421 /* If it has 0 or 1 section bound, then do not reorder. */
1422 if (w->children.head == NULL
1423 || (w->children.head->header.type == lang_input_section_enum
1424 && w->children.head->header.next == NULL))
1425 no_reorder = TRUE;
1426
1427 if (w->filenames_sorted)
1428 no_reorder = TRUE;
1429
1430 /* Check for sorting in a section list wildcard spec as well. */
1431 if (!no_reorder)
1432 {
1433 struct wildcard_list *l;
1434 for (l = w->section_list; l != NULL; l = l->next)
1435 {
73d5923e 1436 if (l->spec.sorted == by_name)
e0001a05
NC
1437 {
1438 no_reorder = TRUE;
1439 break;
1440 }
1441 }
0c7a8e5a 1442 }
e0001a05
NC
1443
1444 /* Special case until the NOREORDER linker directive is supported:
0c7a8e5a 1445 *(.init) output sections and *(.fini) specs may NOT be reordered. */
e0001a05
NC
1446
1447 /* Check for sorting in a section list wildcard spec as well. */
0c7a8e5a 1448 if (!no_reorder)
e0001a05
NC
1449 {
1450 struct wildcard_list *l;
1451 for (l = w->section_list; l != NULL; l = l->next)
1452 {
1453 if (l->spec.name
1454 && ((strcmp (".init", l->spec.name) == 0)
1455 || (strcmp (".fini", l->spec.name) == 0)))
1456 {
1457 no_reorder = TRUE;
1458 break;
1459 }
1460 }
1461 }
1462
1463#if EXTRA_VALIDATION
1464 old_child_count = ld_count_children (statement);
1465#endif
1466
1467 /* It is now officially a target. Build the graph of source
0c7a8e5a 1468 section -> target section (kept as a list of edges). */
e0001a05
NC
1469 deps = ld_build_required_section_dependence (statement);
1470
1471 /* If this wildcard does not reorder.... */
1472 if (!no_reorder && deps->count != 0)
1473 {
1474 /* First check for reverse dependences. Fix if possible. */
1475 xtensa_layout_wild (deps, w);
1476
1477 xtensa_move_dependencies_to_front (deps, w);
1478#if EXTRA_VALIDATION
1479 new_child_count = ld_count_children (statement);
1480 ASSERT (new_child_count == old_child_count);
1481#endif
1482
1483 xtensa_colocate_literals (deps, statement);
1484
1485#if EXTRA_VALIDATION
1486 new_child_count = ld_count_children (statement);
1487 ASSERT (new_child_count == old_child_count);
1488#endif
1489 }
1490
1491 /* Clean up. */
1492 free_reloc_deps_graph (deps);
1493 }
1494}
1495
1496
0c7a8e5a
AM
1497static void
1498xtensa_wild_group_interleave (lang_statement_union_type *s)
e0001a05
NC
1499{
1500 lang_for_each_statement_worker (xtensa_wild_group_interleave_callback, s);
1501}
1502
1503
0c7a8e5a 1504static void
7fa3d080 1505xtensa_layout_wild (const reloc_deps_graph *deps, lang_wild_statement_type *w)
e0001a05
NC
1506{
1507 /* If it does not fit initially, we need to do this step. Move all
1508 of the wild literal sections to a new list, then move each of
1509 them back in just before the first section they depend on. */
1510 lang_statement_union_type **s_p;
1511#if EXTRA_VALIDATION
1512 size_t old_count, new_count;
1513 size_t ct1, ct2;
1514#endif
0c7a8e5a 1515
e0001a05
NC
1516 lang_wild_statement_type literal_wild;
1517 literal_wild.header.next = NULL;
1518 literal_wild.header.type = lang_wild_statement_enum;
1519 literal_wild.filename = NULL;
1520 literal_wild.filenames_sorted = FALSE;
1521 literal_wild.section_list = NULL;
1522 literal_wild.keep_sections = FALSE;
1523 literal_wild.children.head = NULL;
1524 literal_wild.children.tail = &literal_wild.children.head;
1525
1526#if EXTRA_VALIDATION
1527 old_count = ld_count_children ((lang_statement_union_type*) w);
1528#endif
1529
1530 s_p = &w->children.head;
1531 while (*s_p != NULL)
1532 {
1533 lang_statement_union_type *l = *s_p;
1534 if (l->header.type == lang_input_section_enum)
1535 {
1536 if (section_is_target (deps, l)
0c7a8e5a 1537 && ! section_is_source (deps, l))
e0001a05
NC
1538 {
1539 /* Detach. */
1540 *s_p = l->header.next;
1541 if (*s_p == NULL)
1542 w->children.tail = s_p;
1543 l->header.next = NULL;
1544
1545 /* Append. */
1546 *literal_wild.children.tail = l;
1547 literal_wild.children.tail = &l->header.next;
1548 continue;
0c7a8e5a 1549 }
e0001a05
NC
1550 }
1551 s_p = &(*s_p)->header.next;
1552 }
1553
1554#if EXTRA_VALIDATION
1555 ct1 = ld_count_children ((lang_statement_union_type*) w);
1556 ct2 = ld_count_children ((lang_statement_union_type*) &literal_wild);
0c7a8e5a 1557
e0001a05
NC
1558 ASSERT (old_count == (ct1 + ct2));
1559#endif
0c7a8e5a 1560
e0001a05
NC
1561 /* Now place them back in front of their dependent sections. */
1562
1563 while (literal_wild.children.head != NULL)
1564 {
1565 lang_statement_union_type *lit = literal_wild.children.head;
1566 bfd_boolean placed = FALSE;
1567
1568#if EXTRA_VALIDATION
1569 ASSERT (ct2 > 0);
1570 ct2--;
1571#endif
1572
1573 /* Detach. */
1574 literal_wild.children.head = lit->header.next;
0c7a8e5a 1575 if (literal_wild.children.head == NULL)
e0001a05
NC
1576 literal_wild.children.tail = &literal_wild.children.head;
1577 lit->header.next = NULL;
1578
1579 /* Find a spot to place it. */
0c7a8e5a 1580 for (s_p = &w->children.head; *s_p != NULL; s_p = &(*s_p)->header.next)
e0001a05
NC
1581 {
1582 lang_statement_union_type *src = *s_p;
1583 if (deps_has_edge (deps, src, lit))
1584 {
1585 /* Place it here. */
1586 lit->header.next = *s_p;
1587 *s_p = lit;
1588 placed = TRUE;
1589 break;
1590 }
1591 }
0c7a8e5a 1592
e0001a05
NC
1593 if (!placed)
1594 {
1595 /* Put it at the end. */
1596 *w->children.tail = lit;
1597 w->children.tail = &lit->header.next;
1598 }
1599 }
1600
1601#if EXTRA_VALIDATION
1602 new_count = ld_count_children ((lang_statement_union_type*) w);
1603 ASSERT (new_count == old_count);
1604#endif
1605}
1606
1607
0c7a8e5a
AM
1608static void
1609xtensa_colocate_output_literals_callback (lang_statement_union_type *statement)
e0001a05 1610{
e0001a05
NC
1611 reloc_deps_graph *deps;
1612 if (statement->header.type == lang_output_section_statement_enum)
1613 {
1614 /* Now, we walk over the contours of the output section statement.
1615
1616 First we build the literal section dependences as before.
1617
1618 At the first uniquely_literal section, we mark it as a good
1619 spot to place other literals. Continue walking (and counting
1620 sizes) until we find the next literal section. If this
1621 section can be moved to the first one, then we move it. If
1622 we every find a modification of ".", start over. If we find
1623 a labeling of the current location, start over. Finally, at
1624 the end, if we require page alignment, add page alignments. */
1625
1626#if EXTRA_VALIDATION
1627 size_t old_child_count;
1628 size_t new_child_count;
1629#endif
1630 bfd_boolean no_reorder = FALSE;
1631
e0001a05
NC
1632#if EXTRA_VALIDATION
1633 old_child_count = ld_count_children (statement);
1634#endif
1635
1636 /* It is now officially a target. Build the graph of source
0c7a8e5a 1637 section -> target section (kept as a list of edges). */
e0001a05
NC
1638
1639 deps = ld_build_required_section_dependence (statement);
1640
1641 /* If this wildcard does not reorder.... */
1642 if (!no_reorder)
1643 {
1644 /* First check for reverse dependences. Fix if possible. */
1645 xtensa_colocate_literals (deps, statement);
1646
1647#if EXTRA_VALIDATION
1648 new_child_count = ld_count_children (statement);
1649 ASSERT (new_child_count == old_child_count);
1650#endif
1651 }
1652
1653 /* Insert align/offset assignment statement. */
1654 if (xtensa_use_literal_pages)
1655 {
0c7a8e5a 1656 ld_xtensa_insert_page_offsets (0, statement, deps,
e0001a05
NC
1657 xtensa_use_literal_pages);
1658 lang_for_each_statement_worker (xtensa_ldlang_clear_addresses,
1659 statement);
1660 }
1661
1662 /* Clean up. */
1663 free_reloc_deps_graph (deps);
1664 }
1665}
1666
1667
0c7a8e5a
AM
1668static void
1669xtensa_colocate_output_literals (lang_statement_union_type *s)
e0001a05
NC
1670{
1671 lang_for_each_statement_worker (xtensa_colocate_output_literals_callback, s);
1672}
1673
1674
0c7a8e5a
AM
1675static void
1676xtensa_ldlang_clear_addresses (lang_statement_union_type *statement)
e0001a05
NC
1677{
1678 switch (statement->header.type)
1679 {
0c7a8e5a 1680 case lang_input_section_enum:
e0001a05
NC
1681 {
1682 asection *bfd_section = statement->input_section.section;
1683 bfd_section->output_offset = 0;
1684 }
1685 break;
1686 default:
1687 break;
1688 }
1689}
1690
1691
0c7a8e5a
AM
1692static bfd_vma
1693ld_assign_relative_paged_dot (bfd_vma dot,
1694 lang_statement_union_type *s,
1695 const reloc_deps_graph *deps ATTRIBUTE_UNUSED,
1696 bfd_boolean lit_align)
e0001a05
NC
1697{
1698 /* Walk through all of the input statements in this wild statement
1699 assign dot to all of them. */
0c7a8e5a 1700
e0001a05
NC
1701 xtensa_ld_iter_stack *stack = NULL;
1702 xtensa_ld_iter_stack **stack_p = &stack;
1703
1704 bfd_boolean first_section = FALSE;
1705 bfd_boolean in_literals = FALSE;
1706
1707 for (iter_stack_create (stack_p, s);
1708 !iter_stack_empty (stack_p);
0c7a8e5a 1709 iter_stack_next (stack_p))
e0001a05
NC
1710 {
1711 lang_statement_union_type *l = iter_stack_current (stack_p);
0c7a8e5a
AM
1712
1713 switch (l->header.type)
e0001a05
NC
1714 {
1715 case lang_input_section_enum:
1716 {
1717 asection *section = l->input_section.section;
1718 size_t align_pow = section->alignment_power;
1719 bfd_boolean do_xtensa_alignment = FALSE;
0c7a8e5a 1720
e0001a05
NC
1721 if (lit_align)
1722 {
1723 bfd_boolean sec_is_target = section_is_target (deps, l);
1724 bfd_boolean sec_is_source = section_is_source (deps, l);
1725
eea6121a 1726 if (section->size != 0
e0001a05
NC
1727 && (first_section
1728 || (in_literals && !sec_is_target)
1729 || (!in_literals && sec_is_target)))
1730 {
1731 do_xtensa_alignment = TRUE;
1732 }
1733 first_section = FALSE;
eea6121a 1734 if (section->size != 0)
e0001a05
NC
1735 in_literals = (sec_is_target && !sec_is_source);
1736 }
1737
1738 if (do_xtensa_alignment && xtensa_page_power != 0)
1739 dot += (1 << xtensa_page_power);
1740
1741 dot = align_power (dot, align_pow);
1742 section->output_offset = dot;
eea6121a 1743 dot += section->size;
e0001a05
NC
1744 }
1745 break;
1746 case lang_fill_statement_enum:
1747 dot += l->fill_statement.size;
1748 break;
1749 case lang_padding_statement_enum:
1750 dot += l->padding_statement.size;
1751 break;
1752 default:
1753 break;
1754 }
1755 }
1756 return dot;
1757}
1758
1759
0c7a8e5a
AM
1760static bfd_boolean
1761ld_local_file_relocations_fit (lang_statement_union_type *statement,
1762 const reloc_deps_graph *deps ATTRIBUTE_UNUSED)
e0001a05
NC
1763{
1764 /* Walk over all of the dependencies that we identified and make
1765 sure that IF the source and target are here (addr != 0):
1766 1) target addr < source addr
0c7a8e5a 1767 2) (roundup(source + source_size, 4) - rounddown(target, 4))
e0001a05
NC
1768 < (256K - (1 << bad align))
1769 Need a worst-case proof.... */
0c7a8e5a 1770
e0001a05
NC
1771 xtensa_ld_iter_stack *stack = NULL;
1772 xtensa_ld_iter_stack **stack_p = &stack;
1773 size_t max_align_power = 0;
1774 size_t align_penalty = 256;
1775 reloc_deps_e *e;
1776 size_t i;
1777
1778 /* Find the worst-case alignment requirement for this set of statements. */
1779 for (iter_stack_create (stack_p, statement);
1780 !iter_stack_empty (stack_p);
0c7a8e5a 1781 iter_stack_next (stack_p))
e0001a05
NC
1782 {
1783 lang_statement_union_type *l = iter_stack_current (stack_p);
0c7a8e5a 1784 if (l->header.type == lang_input_section_enum)
e0001a05
NC
1785 {
1786 lang_input_section_type *input = &l->input_section;
1787 asection *section = input->section;
1788 if (section->alignment_power > max_align_power)
1789 max_align_power = section->alignment_power;
1790 }
1791 }
1792
1793 /* Now check that everything fits. */
1794 for (i = 0; i < deps->count; i++)
1795 {
1796 asection *sec = deps->sections[i];
0c7a8e5a 1797 const reloc_deps_section *deps_section =
e0001a05
NC
1798 xtensa_get_section_deps (deps, sec);
1799 if (deps_section)
1800 {
1801 /* We choose to walk through the successors. */
1802 for (e = deps_section->succs; e != NULL; e = e->next)
1803 {
0c7a8e5a 1804 if (e->src != e->tgt
e0001a05
NC
1805 && e->src->output_section == e->tgt->output_section
1806 && e->src->output_offset != 0
1807 && e->tgt->output_offset != 0)
1808 {
0c7a8e5a 1809 bfd_vma l32r_addr =
eea6121a 1810 align_power (e->src->output_offset + e->src->size, 2);
0c7a8e5a 1811 bfd_vma target_addr = e->tgt->output_offset & ~3;
e0001a05
NC
1812 if (l32r_addr < target_addr)
1813 {
e922bcab 1814 fflush (stdout);
e0001a05
NC
1815 fprintf (stderr, "Warning: "
1816 "l32r target section before l32r\n");
e922bcab 1817 fflush (stderr);
e0001a05
NC
1818 return FALSE;
1819 }
1820
0c7a8e5a 1821 if (l32r_addr - target_addr > 256 * 1024 - align_penalty)
e0001a05
NC
1822 return FALSE;
1823 }
1824 }
1825 }
1826 }
1827
1828 return TRUE;
1829}
1830
1831
0c7a8e5a
AM
1832static bfd_vma
1833ld_xtensa_insert_page_offsets (bfd_vma dot,
1834 lang_statement_union_type *s,
1835 reloc_deps_graph *deps,
1836 bfd_boolean lit_align)
e0001a05
NC
1837{
1838 xtensa_ld_iter_stack *stack = NULL;
1839 xtensa_ld_iter_stack **stack_p = &stack;
1840
1841 bfd_boolean first_section = FALSE;
1842 bfd_boolean in_literals = FALSE;
0c7a8e5a 1843
e0001a05
NC
1844 if (!lit_align)
1845 return FALSE;
1846
1847 for (iter_stack_create (stack_p, s);
1848 !iter_stack_empty (stack_p);
0c7a8e5a 1849 iter_stack_next (stack_p))
e0001a05
NC
1850 {
1851 lang_statement_union_type *l = iter_stack_current (stack_p);
1852
0c7a8e5a
AM
1853 switch (l->header.type)
1854 {
e0001a05
NC
1855 case lang_input_section_enum:
1856 {
1857 asection *section = l->input_section.section;
1858 bfd_boolean do_xtensa_alignment = FALSE;
0c7a8e5a 1859
e0001a05
NC
1860 if (lit_align)
1861 {
eea6121a 1862 if (section->size != 0
e0001a05
NC
1863 && (first_section
1864 || (in_literals && !section_is_target (deps, l))
1865 || (!in_literals && section_is_target (deps, l))))
1866 {
1867 do_xtensa_alignment = TRUE;
1868 }
1869 first_section = FALSE;
eea6121a 1870 if (section->size != 0)
e0001a05
NC
1871 {
1872 in_literals = (section_is_target (deps, l)
1873 && !section_is_source (deps, l));
1874 }
1875 }
1876
1877 if (do_xtensa_alignment && xtensa_page_power != 0)
1878 {
1879 /* Create an expression that increments the current address,
1880 i.e., "dot", by (1 << xtensa_align_power). */
1881 etree_type *name_op = exp_nameop (NAME, ".");
1882 etree_type *addend_op = exp_intop (1 << xtensa_page_power);
1883 etree_type *add_op = exp_binop ('+', name_op, addend_op);
eb8476a6 1884 etree_type *assign_op = exp_assign (".", add_op, FALSE);
e0001a05
NC
1885
1886 lang_assignment_statement_type *assign_stmt;
1887 lang_statement_union_type *assign_union;
1888 lang_statement_list_type tmplist;
0c7a8e5a 1889
e0001a05
NC
1890 /* There is hidden state in "lang_add_assignment". It
1891 appends the new assignment statement to the stat_ptr
1892 list. Thus, we swap it before and after the call. */
1893
bde18da4
AM
1894 lang_list_init (&tmplist);
1895 push_stat_ptr (&tmplist);
e0001a05
NC
1896 /* Warning: side effect; statement appended to stat_ptr. */
1897 assign_stmt = lang_add_assignment (assign_op);
1898 assign_union = (lang_statement_union_type *) assign_stmt;
bde18da4 1899 pop_stat_ptr ();
e0001a05
NC
1900
1901 assign_union->header.next = l;
1902 *(*stack_p)->iterloc.loc = assign_union;
1903 iter_stack_next (stack_p);
0c7a8e5a
AM
1904 }
1905 }
1906 break;
1907 default:
1908 break;
1909 }
e0001a05
NC
1910 }
1911 return dot;
1912}
1913
1914EOF
1915
43cd72b9 1916# Define some shell vars to insert bits of code into the standard ELF
e0001a05
NC
1917# parse_args and list_options functions.
1918#
1919PARSE_AND_LIST_PROLOGUE='
43cd72b9 1920#define OPTION_OPT_SIZEOPT (300)
28d5f677 1921#define OPTION_LITERAL_MOVEMENT (OPTION_OPT_SIZEOPT + 1)
43cd72b9
BW
1922#define OPTION_NO_LITERAL_MOVEMENT (OPTION_LITERAL_MOVEMENT + 1)
1923extern int elf32xtensa_size_opt;
1924extern int elf32xtensa_no_literal_movement;
e0001a05
NC
1925'
1926
1927PARSE_AND_LIST_LONGOPTS='
43cd72b9 1928 { "size-opt", no_argument, NULL, OPTION_OPT_SIZEOPT},
43cd72b9
BW
1929 { "literal-movement", no_argument, NULL, OPTION_LITERAL_MOVEMENT},
1930 { "no-literal-movement", no_argument, NULL, OPTION_NO_LITERAL_MOVEMENT},
e0001a05
NC
1931'
1932
1933PARSE_AND_LIST_OPTIONS='
442996ee
AM
1934 fprintf (file, _("\
1935 --size-opt When relaxing longcalls, prefer size\n\
1936 optimization over branch target alignment\n"));
e0001a05
NC
1937'
1938
1939PARSE_AND_LIST_ARGS_CASES='
43cd72b9
BW
1940 case OPTION_OPT_SIZEOPT:
1941 elf32xtensa_size_opt = 1;
1942 break;
43cd72b9
BW
1943 case OPTION_LITERAL_MOVEMENT:
1944 elf32xtensa_no_literal_movement = 0;
1945 break;
1946 case OPTION_NO_LITERAL_MOVEMENT:
1947 elf32xtensa_no_literal_movement = 1;
1948 break;
e0001a05
NC
1949'
1950
1951# Replace some of the standard ELF functions with our own versions.
1952#
1953LDEMUL_BEFORE_PARSE=elf_xtensa_before_parse
43cd72b9 1954LDEMUL_AFTER_OPEN=elf_xtensa_after_open
e0001a05 1955LDEMUL_CHOOSE_TARGET=elf_xtensa_choose_target
e0001a05 1956LDEMUL_BEFORE_ALLOCATION=elf_xtensa_before_allocation
This page took 0.828012 seconds and 4 git commands to generate.