+
+void
+_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
+{
+ flagword flags;
+ const char *name, *p;
+ struct bfd_section_already_linked *l;
+ struct bfd_section_already_linked_hash_entry *already_linked_list;
+ asection *group;
+
+ /* A single member comdat group section may be discarded by a
+ linkonce section. See below. */
+ if (sec->output_section == bfd_abs_section_ptr)
+ return;
+
+ flags = sec->flags;
+
+ /* Check if it belongs to a section group. */
+ group = elf_sec_group (sec);
+
+ /* Return if it isn't a linkonce section nor a member of a group. A
+ comdat group section also has SEC_LINK_ONCE set. */
+ if ((flags & SEC_LINK_ONCE) == 0 && group == NULL)
+ return;
+
+ if (group)
+ {
+ /* If this is the member of a single member comdat group, check if
+ the group should be discarded. */
+ if (elf_next_in_group (sec) == sec
+ && (group->flags & SEC_LINK_ONCE) != 0)
+ sec = group;
+ else
+ return;
+ }
+
+ /* FIXME: When doing a relocatable link, we may have trouble
+ copying relocations in other sections that refer to local symbols
+ in the section being discarded. Those relocations will have to
+ be converted somehow; as of this writing I'm not sure that any of
+ the backends handle that correctly.
+
+ It is tempting to instead not discard link once sections when
+ doing a relocatable link (technically, they should be discarded
+ whenever we are building constructors). However, that fails,
+ because the linker winds up combining all the link once sections
+ into a single large link once section, which defeats the purpose
+ of having link once sections in the first place.
+
+ Also, not merging link once sections in a relocatable link
+ causes trouble for MIPS ELF, which relies on link once semantics
+ to handle the .reginfo section correctly. */
+
+ name = bfd_get_section_name (abfd, sec);
+
+ if (strncmp (name, ".gnu.linkonce.", sizeof (".gnu.linkonce.") - 1) == 0
+ && (p = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL)
+ p++;
+ else
+ p = name;
+
+ already_linked_list = bfd_section_already_linked_table_lookup (p);
+
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ {
+ /* We may have 3 different sections on the list: group section,
+ comdat section and linkonce section. SEC may be a linkonce or
+ group section. We match a group section with a group section,
+ a linkonce section with a linkonce section, and ignore comdat
+ section. */
+ if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
+ && strcmp (name, l->sec->name) == 0
+ && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
+ {
+ /* The section has already been linked. See if we should
+ issue a warning. */
+ switch (flags & SEC_LINK_DUPLICATES)
+ {
+ default:
+ abort ();
+
+ case SEC_LINK_DUPLICATES_DISCARD:
+ break;
+
+ case SEC_LINK_DUPLICATES_ONE_ONLY:
+ (*_bfd_error_handler)
+ (_("%B: ignoring duplicate section `%A'"),
+ abfd, sec);
+ break;
+
+ case SEC_LINK_DUPLICATES_SAME_SIZE:
+ if (sec->size != l->sec->size)
+ (*_bfd_error_handler)
+ (_("%B: duplicate section `%A' has different size"),
+ abfd, sec);
+ break;
+
+ case SEC_LINK_DUPLICATES_SAME_CONTENTS:
+ if (sec->size != l->sec->size)
+ (*_bfd_error_handler)
+ (_("%B: duplicate section `%A' has different size"),
+ abfd, sec);
+ else if (sec->size != 0)
+ {
+ bfd_byte *sec_contents, *l_sec_contents;
+
+ if (!bfd_malloc_and_get_section (abfd, sec, &sec_contents))
+ (*_bfd_error_handler)
+ (_("%B: warning: could not read contents of section `%A'"),
+ abfd, sec);
+ else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec,
+ &l_sec_contents))
+ (*_bfd_error_handler)
+ (_("%B: warning: could not read contents of section `%A'"),
+ l->sec->owner, l->sec);
+ else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0)
+ (*_bfd_error_handler)
+ (_("%B: warning: duplicate section `%A' has different contents"),
+ abfd, sec);
+
+ if (sec_contents)
+ free (sec_contents);
+ if (l_sec_contents)
+ free (l_sec_contents);
+ }
+ break;
+ }
+
+ /* Set the output_section field so that lang_add_section
+ does not create a lang_input_section structure for this
+ section. Since there might be a symbol in the section
+ being discarded, we must retain a pointer to the section
+ which we are really going to use. */
+ sec->output_section = bfd_abs_section_ptr;
+ sec->kept_section = l->sec;
+
+ if (flags & SEC_GROUP)
+ {
+ asection *first = elf_next_in_group (sec);
+ asection *s = first;
+
+ while (s != NULL)
+ {
+ s->output_section = bfd_abs_section_ptr;
+ /* Record which group discards it. */
+ s->kept_section = l->sec;
+ s = elf_next_in_group (s);
+ /* These lists are circular. */
+ if (s == first)
+ break;
+ }
+ }
+
+ return;
+ }
+ }
+
+ if (group)
+ {
+ /* If this is the member of a single member comdat group and the
+ group hasn't be discarded, we check if it matches a linkonce
+ section. We only record the discarded comdat group. Otherwise
+ the undiscarded group will be discarded incorrectly later since
+ itself has been recorded. */
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ if ((l->sec->flags & SEC_GROUP) == 0
+ && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL
+ && bfd_elf_match_symbols_in_sections (l->sec,
+ elf_next_in_group (sec)))
+ {
+ elf_next_in_group (sec)->output_section = bfd_abs_section_ptr;
+ elf_next_in_group (sec)->kept_section = l->sec;
+ group->output_section = bfd_abs_section_ptr;
+ break;
+ }
+ if (l == NULL)
+ return;
+ }
+ else
+ /* There is no direct match. But for linkonce section, we should
+ check if there is a match with comdat group member. We always
+ record the linkonce section, discarded or not. */
+ for (l = already_linked_list->entry; l != NULL; l = l->next)
+ if (l->sec->flags & SEC_GROUP)
+ {
+ asection *first = elf_next_in_group (l->sec);
+
+ if (first != NULL
+ && elf_next_in_group (first) == first
+ && bfd_elf_match_symbols_in_sections (first, sec))
+ {
+ sec->output_section = bfd_abs_section_ptr;
+ sec->kept_section = l->sec;
+ break;
+ }
+ }
+
+ /* This is the first section with this name. Record it. */
+ bfd_section_already_linked_table_insert (already_linked_list, sec);
+}
+
+/* Set NAME to VAL if the symbol exists and is undefined. */
+
+void
+_bfd_elf_provide_symbol (struct bfd_link_info *info, const char *name,
+ bfd_vma val)
+{
+ struct elf_link_hash_entry *h;
+ h = elf_link_hash_lookup (elf_hash_table (info), name, FALSE, FALSE,
+ FALSE);
+ if (h != NULL && h->root.type == bfd_link_hash_undefined)
+ {
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = bfd_abs_section_ptr;
+ h->root.u.def.value = val;
+ h->def_regular = 1;
+ h->type = STT_OBJECT;
+ h->other = STV_HIDDEN | (h->other & ~ ELF_ST_VISIBILITY (-1));
+ h->forced_local = 1;
+ }
+}