From: Bob Wilson Date: Fri, 14 Apr 2006 21:31:16 +0000 (+0000) Subject: * emultempl/xtensaelf.em (elf_xtensa_before_allocation): Call new X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a255b6c7b0414ef186a9455620cb8079046ba21b;p=binutils-gdb.git * 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. --- diff --git a/ld/ChangeLog b/ld/ChangeLog index bbadba41d82..f8b1e9f3c38 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,12 @@ +2006-04-14 David Heine + Bob Wilson + + * 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ò * emultempl/elf32.em: Add support for elf-hints.h on FreeBSD diff --git a/ld/emultempl/xtensaelf.em b/ld/emultempl/xtensaelf.em index 16feed1f797..f5d2ba9ceae 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 <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) {