X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Femultempl%2Fxtensaelf.em;h=1aca7b77ace84c21a3ef9259a15ad3bfe386fca4;hb=74e10d1742f1b8312359c59a2af06c9e661252b3;hp=386bf8a32e477bfe5712765a34b1235b857cf258;hpb=43cd72b9aa3a95b0345587974c14b6d237f79a5f;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/emultempl/xtensaelf.em b/ld/emultempl/xtensaelf.em index 386bf8a32e..1aca7b77ac 100644 --- a/ld/emultempl/xtensaelf.em +++ b/ld/emultempl/xtensaelf.em @@ -1,12 +1,11 @@ # This shell script emits a C file. -*- C -*- -# Copyright 2003, 2004 -# Free Software Foundation, Inc. +# Copyright (C) 2003-2020 Free Software Foundation, Inc. # -# This file is part of GLD, the Gnu Linker. +# This file is part of the GNU Binutils. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, @@ -16,31 +15,31 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. # -# This file is sourced from elf32.em, and defines extra xtensa-elf +# This file is sourced from elf.em, and defines extra xtensa-elf # specific routines. # -cat >>e${EMULATION_NAME}.c < #include "../bfd/elf-bfd.h" -#include "../bfd/libbfd.h" #include "elf/xtensa.h" #include "bfd.h" +/* Provide default values for new configuration settings. */ +#ifndef XSHAL_ABI +#define XSHAL_ABI 0 +#endif + static void xtensa_wild_group_interleave (lang_statement_union_type *); static void xtensa_colocate_output_literals (lang_statement_union_type *); -static void remove_section (bfd *, asection *); -static bfd_boolean replace_insn_sec_with_prop_sec (bfd *, const char *, - const char *, char **); -static void replace_instruction_table_sections (bfd *, asection *); +static void xtensa_strip_inconsistent_linkonce_sections + (lang_statement_list_type *); -/* Flag for the emulation-specific "--no-relax" option. */ -static bfd_boolean disable_relaxation = FALSE; - /* This number is irrelevant until we turn on use_literal_pages */ static bfd_vma xtensa_page_power = 12; /* 4K pages. */ @@ -62,17 +61,6 @@ elf_xtensa_choose_target (int argc ATTRIBUTE_UNUSED, } -static bfd_boolean -elf_xtensa_place_orphan (lang_input_statement_type *file, asection *s) -{ - /* Early exit for relocatable links. */ - if (link_info.relocatable) - return FALSE; - - return gld${EMULATION_NAME}_place_orphan (file, s); -} - - static void elf_xtensa_before_parse (void) { @@ -82,10 +70,8 @@ elf_xtensa_before_parse (void) } -void -remove_section (abfd, os) - bfd *abfd; - asection *os; +static void +remove_section (bfd *abfd, asection *os) { asection **spp; for (spp = &abfd->sections; *spp; spp = &(*spp)->next) @@ -98,13 +84,11 @@ remove_section (abfd, os) } -bfd_boolean -replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, - error_message) - bfd *abfd; - const char *insn_sec_name; - const char *prop_sec_name; - char **error_message; +static bfd_boolean +replace_insn_sec_with_prop_sec (bfd *abfd, + const char *insn_sec_name, + const char *prop_sec_name, + char **error_message) { asection *insn_sec; asection *prop_sec; @@ -112,10 +96,10 @@ replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, bfd_byte *insn_contents = NULL; unsigned entry_count; unsigned entry; - Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Shdr *rel_hdr; Elf_Internal_Rela *internal_relocs = NULL; unsigned reloc_count; - + *error_message = ""; insn_sec = bfd_get_section_by_name (abfd, insn_sec_name); if (insn_sec == NULL) @@ -128,15 +112,10 @@ replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, *error_message = _("file already has property tables"); return FALSE; } - + if (insn_sec->size != 0) { - insn_contents = (bfd_byte *) bfd_malloc (insn_sec->size); - if (insn_contents == NULL) - { - *error_message = _("out of memory"); - goto cleanup; - } + insn_contents = (bfd_byte *) xmalloc (insn_sec->size); if (! bfd_get_section_contents (abfd, insn_sec, insn_contents, (file_ptr) 0, insn_sec->size)) { @@ -145,35 +124,26 @@ replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, } } - /* Create a Property table section and relocation section for it. */ + /* Create a property table section for it. */ prop_sec_name = strdup (prop_sec_name); - prop_sec = bfd_make_section (abfd, prop_sec_name); + prop_sec = bfd_make_section_with_flags + (abfd, prop_sec_name, bfd_section_flags (insn_sec)); if (prop_sec == NULL - || ! bfd_set_section_flags (abfd, prop_sec, - bfd_get_section_flags (abfd, insn_sec)) - || ! bfd_set_section_alignment (abfd, prop_sec, 2)) + || !bfd_set_section_alignment (prop_sec, 2)) { *error_message = _("could not create new section"); goto cleanup; } - - if (! bfd_set_section_flags (abfd, prop_sec, - bfd_get_section_flags (abfd, insn_sec)) - || ! bfd_set_section_alignment (abfd, prop_sec, 2)) - { - *error_message = _("could not set new section properties"); - goto cleanup; - } + prop_sec->size = entry_count * 12; prop_contents = (bfd_byte *) bfd_zalloc (abfd, prop_sec->size); elf_section_data (prop_sec)->this_hdr.contents = prop_contents; /* The entry size and size must be set to allow the linker to compute the number of relocations since it does not use reloc_count. */ - elf_section_data (prop_sec)->rel_hdr.sh_entsize = - sizeof (Elf32_External_Rela); - elf_section_data (prop_sec)->rel_hdr.sh_size = - elf_section_data (insn_sec)->rel_hdr.sh_size; + rel_hdr = _bfd_elf_single_rel_hdr (prop_sec); + rel_hdr->sh_entsize = sizeof (Elf32_External_Rela); + rel_hdr->sh_size = _bfd_elf_single_rel_hdr (insn_sec)->sh_size; if (prop_contents == NULL && prop_sec->size != 0) { @@ -188,12 +158,12 @@ replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, /* If there is already an internal_reloc, then save it so that the read_relocs function freshly allocates a copy. */ Elf_Internal_Rela *saved_relocs = elf_section_data (insn_sec)->relocs; - + elf_section_data (insn_sec)->relocs = NULL; - internal_relocs = + internal_relocs = _bfd_elf_link_read_relocs (abfd, insn_sec, NULL, NULL, FALSE); elf_section_data (insn_sec)->relocs = saved_relocs; - + if (internal_relocs == NULL) { *error_message = _("out of memory"); @@ -207,13 +177,13 @@ replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, elf_section_data (prop_sec)->relocs = internal_relocs; prop_sec->reloc_count = reloc_count; } - + /* Now copy each insn table entry to the prop table entry with appropriate flags. */ for (entry = 0; entry < entry_count; ++entry) { unsigned value; - unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_INSN_NO_TRANSFORM + unsigned flags = (XTENSA_PROP_INSN | XTENSA_PROP_NO_TRANSFORM | XTENSA_PROP_INSN_NO_REORDER); value = bfd_get_32 (abfd, insn_contents + entry * 8 + 0); bfd_put_32 (abfd, value, prop_contents + entry * 12 + 0); @@ -228,7 +198,6 @@ replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, if (internal_relocs) { unsigned i; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; for (i = 0; i < reloc_count; i++) { @@ -237,7 +206,7 @@ replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, rela = &internal_relocs[i]; - /* If this relocation is to the .xt.insn section, + /* If this relocation is to the .xt.insn section, change the section number and the offset. */ r_offset = rela->r_offset; r_offset += 4 * (r_offset / 8); @@ -246,10 +215,10 @@ replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, } remove_section (abfd, insn_sec); - + if (insn_contents) free (insn_contents); - + return TRUE; cleanup: @@ -269,25 +238,22 @@ replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, #define LINKONCE_SEC_OLD_TEXT_BASE_NAME ".gnu.linkonce.x." -void -replace_instruction_table_sections (abfd, sec) - bfd *abfd; - asection *sec; +static void +replace_instruction_table_sections (bfd *abfd, asection *sec) { char *message = ""; const char *insn_sec_name = NULL; char *prop_sec_name = NULL; char *owned_prop_sec_name = NULL; const char *sec_name; - - sec_name = bfd_get_section_name (abfd, sec); + + sec_name = bfd_section_name (sec); if (strcmp (sec_name, INSN_SEC_BASE_NAME) == 0) { insn_sec_name = INSN_SEC_BASE_NAME; prop_sec_name = PROP_SEC_BASE_NAME; } - else if (strncmp (sec_name, LINKONCE_SEC_OLD_TEXT_BASE_NAME, - strlen (LINKONCE_SEC_OLD_TEXT_BASE_NAME)) == 0) + else if (CONST_STRNEQ (sec_name, LINKONCE_SEC_OLD_TEXT_BASE_NAME)) { insn_sec_name = sec_name; owned_prop_sec_name = (char *) xmalloc (strlen (sec_name) + 20); @@ -301,7 +267,7 @@ replace_instruction_table_sections (abfd, sec) if (! replace_insn_sec_with_prop_sec (abfd, insn_sec_name, prop_sec_name, &message)) { - einfo (_("%P: warning: failed to convert %s table in %B (%s); subsequent disassembly may be incomplete\n"), + einfo (_("%P: warning: failed to convert %s table in %pB (%s); subsequent disassembly may be incomplete\n"), insn_sec_name, abfd, message); } } @@ -317,17 +283,13 @@ replace_instruction_table_sections (abfd, sec) static void elf_xtensa_after_open (void) { - bfd *abfd; - /* First call the ELF version. */ gld${EMULATION_NAME}_after_open (); - + /* Now search the input files looking for instruction table sections. */ - for (abfd = link_info.input_bfds; - abfd != NULL; - abfd = abfd->link_next) + LANG_FOR_EACH_INPUT_STATEMENT (f) { - asection *sec = abfd->sections; + asection *sec = f->the_bfd->sections; asection *next_sec; /* Do not use bfd_map_over_sections here since we are removing @@ -335,20 +297,122 @@ elf_xtensa_after_open (void) while (sec != NULL) { next_sec = sec->next; - replace_instruction_table_sections (abfd, sec); + replace_instruction_table_sections (f->the_bfd, sec); sec = next_sec; } } } +static bfd_boolean +xt_config_info_unpack_and_check (char *data, + bfd_boolean *pmismatch, + char **pmsg) +{ + char *d, *key; + unsigned num; + + *pmismatch = FALSE; + + d = data; + while (*d) + { + key = d; + d = strchr (d, '='); + if (! d) + goto error; + + /* Overwrite the equal sign. */ + *d++ = 0; + + /* Check if this is a quoted string or a number. */ + if (*d == '"') + { + /* No string values are currently checked by LD; + just skip over the quotes. */ + d++; + d = strchr (d, '"'); + if (! d) + goto error; + /* Overwrite the trailing quote. */ + *d++ = 0; + } + else + { + if (*d == 0) + goto error; + num = strtoul (d, &d, 0); + + if (! strcmp (key, "ABI")) + { + if (num != XSHAL_ABI) + { + *pmismatch = TRUE; + *pmsg = "ABI does not match"; + } + } + else if (! strcmp (key, "USE_ABSOLUTE_LITERALS")) + { + if (num != XSHAL_USE_ABSOLUTE_LITERALS) + { + *pmismatch = TRUE; + *pmsg = "incompatible use of the Extended L32R option"; + } + } + } + + if (*d++ != '\n') + goto error; + } + + return TRUE; + + error: + return FALSE; +} + + +#define XTINFO_NAME "Xtensa_Info" +#define XTINFO_NAMESZ 12 +#define XTINFO_TYPE 1 + +static void +check_xtensa_info (bfd *abfd, asection *info_sec) +{ + char *data, *errmsg = ""; + bfd_boolean mismatch; + + data = xmalloc (info_sec->size); + if (! bfd_get_section_contents (abfd, info_sec, data, 0, info_sec->size)) + einfo (_("%F%P: %pB: cannot read contents of section %pA\n"), abfd, info_sec); + + if (info_sec->size > 24 + && info_sec->size >= 24 + bfd_get_32 (abfd, data + 4) + && bfd_get_32 (abfd, data + 0) == XTINFO_NAMESZ + && bfd_get_32 (abfd, data + 8) == XTINFO_TYPE + && strcmp (data + 12, XTINFO_NAME) == 0 + && xt_config_info_unpack_and_check (data + 12 + XTINFO_NAMESZ, + &mismatch, &errmsg)) + { + if (mismatch) + einfo (_("%P: %pB: warning: incompatible Xtensa configuration (%s)\n"), + abfd, errmsg); + } + else + einfo (_("%P: %pB: warning: cannot parse .xtensa.info section\n"), abfd); + + free (data); +} + + /* This is called after the sections have been attached to output sections, but before any sizes or addresses have been set. */ static void elf_xtensa_before_allocation (void) { - bfd *in_bfd; + asection *info_sec, *first_info_sec; + bfd *first_bfd; bfd_boolean is_big_endian = XCHAL_HAVE_BE; /* Check that the output endianness matches the Xtensa @@ -358,43 +422,109 @@ elf_xtensa_before_allocation (void) required to process relocations) for the selected Xtensa configuration. */ - if (is_big_endian && output_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE) + if (is_big_endian + && link_info.output_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE) { einfo (_("%F%P: little endian output does not match " "Xtensa configuration\n")); } - if (!is_big_endian && output_bfd->xvec->byteorder == BFD_ENDIAN_BIG) + if (!is_big_endian + && link_info.output_bfd->xvec->byteorder == BFD_ENDIAN_BIG) { einfo (_("%F%P: big endian output does not match " "Xtensa configuration\n")); } - /* Check that the endianness for each input file matches the output. - The merge_private_bfd_data hook has already reported any mismatches - as errors, but those errors are not fatal. At this point, we - cannot go any further if there are any mismatches. */ + /* Keep track of the first input .xtensa.info section, and as a fallback, + the first input bfd where a .xtensa.info section could be created. + After the input .xtensa.info has been checked, the contents of the + first one will be replaced with the output .xtensa.info table. */ + first_info_sec = 0; + first_bfd = 0; + + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + /* Check that the endianness for each input file matches the output. + The merge_private_bfd_data hook has already reported any mismatches + as errors, but those errors are not fatal. At this point, we + cannot go any further if there are any mismatches. */ + if ((is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE) + || (!is_big_endian && f->the_bfd->xvec->byteorder == BFD_ENDIAN_BIG)) + einfo (_("%F%P: cross-endian linking for %pB not supported\n"), + f->the_bfd); + + if (! first_bfd) + first_bfd = f->the_bfd; + + info_sec = bfd_get_section_by_name (f->the_bfd, ".xtensa.info"); + if (! info_sec) + continue; + + if (! first_info_sec) + first_info_sec = info_sec; + + /* Unpack the .xtensa.info section and check it against the current + Xtensa configuration. */ + check_xtensa_info (f->the_bfd, info_sec); + + /* Do not include this copy of .xtensa.info in the output. */ + info_sec->size = 0; + info_sec->flags |= SEC_EXCLUDE; + } - for (in_bfd = link_info.input_bfds; - in_bfd != NULL; - in_bfd = in_bfd->link_next) + /* Reuse the first .xtensa.info input section to hold the output + .xtensa.info; or, if none were found, create a new section in the + first input bfd (assuming there is one). */ + info_sec = first_info_sec; + if (! info_sec && first_bfd) + { + info_sec = bfd_make_section_with_flags (first_bfd, ".xtensa.info", + SEC_HAS_CONTENTS | SEC_READONLY); + if (! info_sec) + einfo (_("%F%P: failed to create .xtensa.info section\n")); + } + if (info_sec) { - if ((is_big_endian && in_bfd->xvec->byteorder == BFD_ENDIAN_LITTLE) - || (!is_big_endian && in_bfd->xvec->byteorder == BFD_ENDIAN_BIG)) - einfo (_("%F%P: cross-endian linking not supported\n")); + int xtensa_info_size; + char *data; + + info_sec->flags &= ~SEC_EXCLUDE; + info_sec->flags |= SEC_IN_MEMORY; + + data = xmalloc (100); + sprintf (data, "USE_ABSOLUTE_LITERALS=%d\nABI=%d\n", + XSHAL_USE_ABSOLUTE_LITERALS, XSHAL_ABI); + xtensa_info_size = strlen (data) + 1; + + /* Add enough null terminators to pad to a word boundary. */ + do + data[xtensa_info_size++] = 0; + while ((xtensa_info_size & 3) != 0); + + info_sec->size = 12 + XTINFO_NAMESZ + xtensa_info_size; + info_sec->contents = xmalloc (info_sec->size); + bfd_put_32 (info_sec->owner, XTINFO_NAMESZ, info_sec->contents + 0); + bfd_put_32 (info_sec->owner, xtensa_info_size, info_sec->contents + 4); + bfd_put_32 (info_sec->owner, XTINFO_TYPE, info_sec->contents + 8); + memcpy (info_sec->contents + 12, XTINFO_NAME, XTINFO_NAMESZ); + memcpy (info_sec->contents + 12 + XTINFO_NAMESZ, data, xtensa_info_size); + free (data); } /* Enable relaxation by default if the "--no-relax" option was not specified. This is done here instead of in the before_parse hook because there is a check in main() to prohibit use of --relax and -r together and that combination should be allowed for Xtensa. */ + if (RELAXATION_DISABLED_BY_DEFAULT) + ENABLE_RELAXATION; - if (!disable_relaxation) - command_line.relax = TRUE; + xtensa_strip_inconsistent_linkonce_sections (stat_ptr); gld${EMULATION_NAME}_before_allocation (); xtensa_wild_group_interleave (stat_ptr->head); - if (command_line.relax) + + if (RELAXATION_ENABLED) xtensa_colocate_output_literals (stat_ptr->head); /* TBD: We need to force the page alignments to here and only do @@ -445,8 +575,7 @@ typedef void (*deps_callback_t) (asection *, /* src_sec */ extern bfd_boolean xtensa_callback_required_dependence (bfd *, asection *, struct bfd_link_info *, deps_callback_t, void *); -static void xtensa_ldlang_clear_addresses - (lang_statement_union_type *); +static void xtensa_ldlang_clear_addresses (lang_statement_union_type *); static bfd_boolean ld_local_file_relocations_fit (lang_statement_union_type *, const reloc_deps_graph *); static bfd_vma ld_assign_relative_paged_dot @@ -455,65 +584,11 @@ static bfd_vma ld_assign_relative_paged_dot static bfd_vma ld_xtensa_insert_page_offsets (bfd_vma, lang_statement_union_type *, reloc_deps_graph *, bfd_boolean); #if EXTRA_VALIDATION -static size_t ld_count_children - (lang_statement_union_type *); +static size_t ld_count_children (lang_statement_union_type *); #endif extern lang_statement_list_type constructor_list; -/* Begin verbatim code from ldlang.c: - the following are copied from ldlang.c because they are defined - there statically. */ - -static void -lang_for_each_statement_worker (void (*func) (lang_statement_union_type *), - lang_statement_union_type *s) -{ - for (; s != (lang_statement_union_type *) NULL; s = s->header.next) - { - func (s); - - switch (s->header.type) - { - case lang_constructors_statement_enum: - lang_for_each_statement_worker (func, constructor_list.head); - break; - case lang_output_section_statement_enum: - lang_for_each_statement_worker - (func, - s->output_section_statement.children.head); - break; - case lang_wild_statement_enum: - lang_for_each_statement_worker - (func, - s->wild_statement.children.head); - break; - case lang_group_statement_enum: - lang_for_each_statement_worker (func, - s->group_statement.children.head); - break; - case lang_data_statement_enum: - case lang_reloc_statement_enum: - case lang_object_symbols_statement_enum: - case lang_output_statement_enum: - case lang_target_statement_enum: - case lang_input_section_enum: - case lang_input_statement_enum: - case lang_assignment_statement_enum: - case lang_padding_statement_enum: - case lang_address_statement_enum: - case lang_fill_statement_enum: - break; - default: - FAIL (); - break; - } - } -} - -/* End of verbatim code from ldlang.c. */ - - static reloc_deps_section * xtensa_get_section_deps (const reloc_deps_graph *deps ATTRIBUTE_UNUSED, asection *sec) @@ -521,8 +596,12 @@ xtensa_get_section_deps (const reloc_deps_graph *deps ATTRIBUTE_UNUSED, /* We have a separate function for this so that we could in the future keep a completely independent structure that maps a section to its dependence edges. - For now, we place these in the sec->userdata field. */ - reloc_deps_section *sec_deps = sec->userdata; + For now, we place these in the sec->userdata field. + This doesn't clash with ldlang.c use of userdata for output + sections, and during map output for input sections, since the + xtensa use is only for input sections and only extant in + before_allocation. */ + reloc_deps_section *sec_deps = bfd_section_userdata (sec); return sec_deps; } @@ -531,7 +610,7 @@ xtensa_set_section_deps (const reloc_deps_graph *deps ATTRIBUTE_UNUSED, asection *sec, reloc_deps_section *deps_section) { - sec->userdata = deps_section; + bfd_set_section_userdata (sec, deps_section); } @@ -634,6 +713,7 @@ section_is_target (const reloc_deps_graph *deps ATTRIBUTE_UNUSED, return sec_deps && sec_deps->preds != NULL; } + static bfd_boolean section_is_source_or_target (const reloc_deps_graph *deps ATTRIBUTE_UNUSED, lang_statement_union_type *s) @@ -860,8 +940,7 @@ iter_stack_create (xtensa_ld_iter_stack **stack_p, static void -iter_stack_copy_current (xtensa_ld_iter_stack **stack_p, - xtensa_ld_iter *front) +iter_stack_copy_current (xtensa_ld_iter_stack **stack_p, xtensa_ld_iter *front) { *front = (*stack_p)->iterloc; } @@ -885,16 +964,6 @@ xtensa_colocate_literals (reloc_deps_graph *deps, if (deps->count == 0) return; -#if 0 - ld_assign_relative_paged_dot (0x100000, statement, deps, - xtensa_use_literal_pages); - - if (!ld_local_file_relocations_fit (statement, deps)) - fprintf (stderr, "initial relocation placement does not fit\n"); - - lang_for_each_statement_worker (xtensa_ldlang_clear_addresses, statement); -#endif - iter_stack_create (stack_p, statement); while (!iter_stack_empty (stack_p)) @@ -1027,9 +1096,7 @@ xtensa_move_dependencies_to_front (reloc_deps_graph *deps, static bfd_boolean -deps_has_sec_edge (const reloc_deps_graph *deps, - asection *src, - asection *tgt) +deps_has_sec_edge (const reloc_deps_graph *deps, asection *src, asection *tgt) { const reloc_deps_section *sec_deps; const reloc_deps_e *sec_deps_e; @@ -1071,9 +1138,7 @@ deps_has_edge (const reloc_deps_graph *deps, static void -add_deps_edge (reloc_deps_graph *deps, - asection *src_sec, - asection *tgt_sec) +add_deps_edge (reloc_deps_graph *deps, asection *src_sec, asection *tgt_sec) { reloc_deps_section *src_sec_deps; reloc_deps_section *tgt_sec_deps; @@ -1163,7 +1228,7 @@ ld_build_required_section_dependence (lang_statement_union_type *s) { lang_input_section_type *input; input = &l->input_section; - xtensa_callback_required_dependence (input->ifile->the_bfd, + xtensa_callback_required_dependence (input->section->owner, input->section, &link_info, /* Use the same closure. */ @@ -1194,6 +1259,151 @@ ld_count_children (lang_statement_union_type *s) #endif /* EXTRA_VALIDATION */ +/* Check if a particular section is included in the link. This will only + be true for one instance of a particular linkonce section. */ + +static bfd_boolean input_section_found = FALSE; +static asection *input_section_target = NULL; + +static void +input_section_linked_worker (lang_statement_union_type *statement) +{ + if ((statement->header.type == lang_input_section_enum + && (statement->input_section.section == input_section_target))) + input_section_found = TRUE; +} + +static bfd_boolean +input_section_linked (asection *sec) +{ + input_section_found = FALSE; + input_section_target = sec; + lang_for_each_statement_worker (input_section_linked_worker, stat_ptr->head); + return input_section_found; +} + + +/* Strip out any linkonce property tables or XCC exception tables where the + associated linkonce text is from a different object file. Normally, + a matching set of linkonce sections is taken from the same object file, + but sometimes the files are compiled differently so that some of the + linkonce sections are not present in all files. Stripping the + inconsistent sections like this is not completely robust -- a much + better solution is to use comdat groups. */ + +static int linkonce_len = sizeof (".gnu.linkonce.") - 1; + +static bfd_boolean +is_inconsistent_linkonce_section (asection *sec) +{ + bfd *abfd = sec->owner; + const char *sec_name = bfd_section_name (sec); + const char *name; + + if ((bfd_section_flags (sec) & SEC_LINK_ONCE) == 0 + || strncmp (sec_name, ".gnu.linkonce.", linkonce_len) != 0) + return FALSE; + + /* Check if this is an Xtensa property section or an exception table + for Tensilica's XCC compiler. */ + name = sec_name + linkonce_len; + if (CONST_STRNEQ (name, "prop.")) + name = strchr (name + 5, '.') ? strchr (name + 5, '.') + 1 : name + 5; + else if (name[1] == '.' + && (name[0] == 'p' || name[0] == 'e' || name[0] == 'h')) + name += 2; + else + name = 0; + + if (name) + { + char *dep_sec_name = xmalloc (strlen (sec_name) + 1); + asection *dep_sec; + + /* Get the associated linkonce text section and check if it is + included in the link. If not, this section is inconsistent + and should be stripped. */ + strcpy (dep_sec_name, ".gnu.linkonce.t."); + strcat (dep_sec_name, name); + dep_sec = bfd_get_section_by_name (abfd, dep_sec_name); + if (dep_sec == NULL || ! input_section_linked (dep_sec)) + { + free (dep_sec_name); + return TRUE; + } + free (dep_sec_name); + } + + return FALSE; +} + + +static void +xtensa_strip_inconsistent_linkonce_sections (lang_statement_list_type *slist) +{ + lang_statement_union_type **s_p = &slist->head; + while (*s_p) + { + lang_statement_union_type *s = *s_p; + lang_statement_union_type *s_next = (*s_p)->header.next; + + switch (s->header.type) + { + case lang_input_section_enum: + if (is_inconsistent_linkonce_section (s->input_section.section)) + { + s->input_section.section->output_section = bfd_abs_section_ptr; + *s_p = s_next; + continue; + } + break; + + case lang_constructors_statement_enum: + xtensa_strip_inconsistent_linkonce_sections (&constructor_list); + break; + + case lang_output_section_statement_enum: + if (s->output_section_statement.children.head) + xtensa_strip_inconsistent_linkonce_sections + (&s->output_section_statement.children); + break; + + case lang_wild_statement_enum: + xtensa_strip_inconsistent_linkonce_sections + (&s->wild_statement.children); + break; + + case lang_group_statement_enum: + xtensa_strip_inconsistent_linkonce_sections + (&s->group_statement.children); + break; + + case lang_data_statement_enum: + case lang_reloc_statement_enum: + case lang_object_symbols_statement_enum: + case lang_output_statement_enum: + case lang_target_statement_enum: + case lang_input_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + + default: + FAIL (); + break; + } + + s_p = &(*s_p)->header.next; + } + + /* Reset the tail of the list, in case the last entry was removed. */ + if (s_p != slist->tail) + slist->tail = s_p; +} + + static void xtensa_wild_group_interleave_callback (lang_statement_union_type *statement) { @@ -1226,7 +1436,7 @@ xtensa_wild_group_interleave_callback (lang_statement_union_type *statement) struct wildcard_list *l; for (l = w->section_list; l != NULL; l = l->next) { - if (l->spec.sorted == TRUE) + if (l->spec.sorted == by_name) { no_reorder = TRUE; break; @@ -1295,8 +1505,7 @@ xtensa_wild_group_interleave (lang_statement_union_type *s) static void -xtensa_layout_wild (const reloc_deps_graph *deps, - lang_wild_statement_type *w) +xtensa_layout_wild (const reloc_deps_graph *deps, lang_wild_statement_type *w) { /* If it does not fit initially, we need to do this step. Move all of the wild literal sections to a new list, then move each of @@ -1402,7 +1611,6 @@ xtensa_layout_wild (const reloc_deps_graph *deps, static void xtensa_colocate_output_literals_callback (lang_statement_union_type *statement) { - lang_output_section_statement_type *os; reloc_deps_graph *deps; if (statement->header.type == lang_output_section_statement_enum) { @@ -1424,8 +1632,6 @@ xtensa_colocate_output_literals_callback (lang_statement_union_type *statement) #endif bfd_boolean no_reorder = FALSE; - os = &statement->output_section_statement; - #if EXTRA_VALIDATION old_child_count = ld_count_children (statement); #endif @@ -1608,8 +1814,10 @@ ld_local_file_relocations_fit (lang_statement_union_type *statement, bfd_vma target_addr = e->tgt->output_offset & ~3; if (l32r_addr < target_addr) { + fflush (stdout); fprintf (stderr, "Warning: " "l32r target section before l32r\n"); + fflush (stderr); return FALSE; } @@ -1676,25 +1884,22 @@ ld_xtensa_insert_page_offsets (bfd_vma dot, etree_type *name_op = exp_nameop (NAME, "."); etree_type *addend_op = exp_intop (1 << xtensa_page_power); etree_type *add_op = exp_binop ('+', name_op, addend_op); - etree_type *assign_op = exp_assop ('=', ".", add_op); + etree_type *assign_op = exp_assign (".", add_op, FALSE); lang_assignment_statement_type *assign_stmt; lang_statement_union_type *assign_union; lang_statement_list_type tmplist; - lang_statement_list_type *old_stat_ptr = stat_ptr; /* There is hidden state in "lang_add_assignment". It appends the new assignment statement to the stat_ptr list. Thus, we swap it before and after the call. */ - tmplist.head = NULL; - tmplist.tail = &tmplist.head; - - stat_ptr = &tmplist; + lang_list_init (&tmplist); + push_stat_ptr (&tmplist); /* Warning: side effect; statement appended to stat_ptr. */ assign_stmt = lang_add_assignment (assign_op); assign_union = (lang_statement_union_type *) assign_stmt; - stat_ptr = old_stat_ptr; + pop_stat_ptr (); assign_union->header.next = l; *(*stack_p)->iterloc.loc = assign_union; @@ -1716,8 +1921,7 @@ EOF # PARSE_AND_LIST_PROLOGUE=' #define OPTION_OPT_SIZEOPT (300) -#define OPTION_NO_RELAX (OPTION_OPT_SIZEOPT + 1) -#define OPTION_LITERAL_MOVEMENT (OPTION_NO_RELAX + 1) +#define OPTION_LITERAL_MOVEMENT (OPTION_OPT_SIZEOPT + 1) #define OPTION_NO_LITERAL_MOVEMENT (OPTION_LITERAL_MOVEMENT + 1) extern int elf32xtensa_size_opt; extern int elf32xtensa_no_literal_movement; @@ -1725,23 +1929,20 @@ extern int elf32xtensa_no_literal_movement; PARSE_AND_LIST_LONGOPTS=' { "size-opt", no_argument, NULL, OPTION_OPT_SIZEOPT}, - { "no-relax", no_argument, NULL, OPTION_NO_RELAX}, { "literal-movement", no_argument, NULL, OPTION_LITERAL_MOVEMENT}, { "no-literal-movement", no_argument, NULL, OPTION_NO_LITERAL_MOVEMENT}, ' PARSE_AND_LIST_OPTIONS=' - fprintf (file, _(" --size-opt\t\tWhen relaxing longcalls, prefer size optimization\n\t\t\t over branch target alignment\n")); - fprintf (file, _(" --no-relax\t\tDo not relax branches or coalesce literals\n")); + fprintf (file, _("\ + --size-opt When relaxing longcalls, prefer size\n\ + optimization over branch target alignment\n")); ' PARSE_AND_LIST_ARGS_CASES=' case OPTION_OPT_SIZEOPT: elf32xtensa_size_opt = 1; break; - case OPTION_NO_RELAX: - disable_relaxation = TRUE; - break; case OPTION_LITERAL_MOVEMENT: elf32xtensa_no_literal_movement = 0; break; @@ -1755,6 +1956,4 @@ PARSE_AND_LIST_ARGS_CASES=' LDEMUL_BEFORE_PARSE=elf_xtensa_before_parse LDEMUL_AFTER_OPEN=elf_xtensa_after_open LDEMUL_CHOOSE_TARGET=elf_xtensa_choose_target -LDEMUL_PLACE_ORPHAN=elf_xtensa_place_orphan LDEMUL_BEFORE_ALLOCATION=elf_xtensa_before_allocation -