diff options
author | Bob Wilson <bob.wilson@acm.org> | 2006-04-14 21:31:16 +0000 |
---|---|---|
committer | Bob Wilson <bob.wilson@acm.org> | 2006-04-14 21:31:16 +0000 |
commit | a255b6c7b0414ef186a9455620cb8079046ba21b (patch) | |
tree | a34b274b60ab82071744349af65c403ec4e1f6b3 /ld | |
parent | cd852561d00500299820918556b829ff016a6d8d (diff) | |
download | fsf-binutils-gdb-a255b6c7b0414ef186a9455620cb8079046ba21b.zip fsf-binutils-gdb-a255b6c7b0414ef186a9455620cb8079046ba21b.tar.gz fsf-binutils-gdb-a255b6c7b0414ef186a9455620cb8079046ba21b.tar.bz2 |
* emultempl/xtensaelf.em (elf_xtensa_before_allocation): Call new
function to strip inconsistent linkonce sections.
(input_section_linked_worker, input_section_linked): New.
(is_inconsistent_linkonce_section): New.
(xtensa_strip_inconsistent_linkonce_sections): New.
Diffstat (limited to 'ld')
-rw-r--r-- | ld/ChangeLog | 9 | ||||
-rw-r--r-- | ld/emultempl/xtensaelf.em | 145 |
2 files changed, 153 insertions, 1 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog index bbadba4..f8b1e9f 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,12 @@ +2006-04-14 David Heine <dlheine@tensilica.com> + Bob Wilson <bob.wilson@acm.org> + + * emultempl/xtensaelf.em (elf_xtensa_before_allocation): Call new + function to strip inconsistent linkonce sections. + (input_section_linked_worker, input_section_linked): New. + (is_inconsistent_linkonce_section): New. + (xtensa_strip_inconsistent_linkonce_sections): New. + 2006-04-11 Diego Pettenò <flameeyes@gentoo.org> * emultempl/elf32.em: Add support for elf-hints.h on FreeBSD diff --git a/ld/emultempl/xtensaelf.em b/ld/emultempl/xtensaelf.em index 16feed1..f5d2ba9 100644 --- a/ld/emultempl/xtensaelf.em +++ b/ld/emultempl/xtensaelf.em @@ -1,5 +1,5 @@ # This shell script emits a C file. -*- C -*- -# Copyright 2003, 2004, 2005 +# Copyright 2003, 2004, 2005, 2006 # Free Software Foundation, Inc. # # This file is part of GLD, the Gnu Linker. @@ -32,6 +32,8 @@ cat >>e${EMULATION_NAME}.c <<EOF static void xtensa_wild_group_interleave (lang_statement_union_type *); static void xtensa_colocate_output_literals (lang_statement_union_type *); +static void xtensa_strip_inconsistent_linkonce_sections + (lang_statement_list_type *); /* Flag for the emulation-specific "--no-relax" option. */ @@ -370,6 +372,8 @@ elf_xtensa_before_allocation (void) 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); @@ -1157,6 +1161,145 @@ 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 literal sections or property 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_get_section_name (abfd, sec); + char *prop_tag = 0; + + if ((bfd_get_section_flags (abfd, sec) & SEC_LINK_ONCE) == 0 + || strncmp (sec_name, ".gnu.linkonce.", linkonce_len) != 0) + return FALSE; + + /* Check if this is an Xtensa property section. */ + if (strncmp (sec_name + linkonce_len, "p.", 2) == 0) + prop_tag = "p."; + else if (strncmp (sec_name + linkonce_len, "prop.", 5) == 0) + prop_tag = "prop."; + if (prop_tag) + { + int tag_len = strlen (prop_tag); + char *dep_sec_name = xmalloc (strlen (sec_name)); + 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."); + strcat (dep_sec_name, sec_name + linkonce_len + tag_len); + 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_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) { |