static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **, int));
static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));
static char *elf_read PARAMS ((bfd *, file_ptr, bfd_size_type));
+static const char *group_signature PARAMS ((bfd *, Elf_Internal_Shdr *));
static boolean setup_group PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
static void merge_sections_remove_hook PARAMS ((bfd *, asection *));
static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
unsigned int flags;
} Elf_Internal_Group;
+/* Return the name of the group signature symbol. Why isn't the
+ signature just a string? */
+
+static const char *
+group_signature (abfd, ghdr)
+ bfd *abfd;
+ Elf_Internal_Shdr *ghdr;
+{
+ struct elf_backend_data *bed;
+ file_ptr pos;
+ unsigned char ename[4];
+ unsigned long iname;
+
+ /* First we need to ensure the symbol table is available. */
+ if (! bfd_section_from_shdr (abfd, ghdr->sh_link))
+ return NULL;
+
+ /* Fortunately, the name index is at the same place in the external
+ symbol for both 32 and 64 bit ELF. */
+ bed = get_elf_backend_data (abfd);
+ pos = elf_tdata (abfd)->symtab_hdr.sh_offset;
+ pos += ghdr->sh_info * bed->s->sizeof_sym;
+ if (bfd_seek (abfd, pos, SEEK_SET) != 0
+ || bfd_bread (ename, (bfd_size_type) 4, abfd) != 4)
+ return NULL;
+ iname = H_GET_32 (abfd, ename);
+ return elf_string_from_elf_strtab (abfd, iname);
+}
+
/* Set next_in_group list pointer, and group name for NEWSECT. */
static boolean
if (src == shdr->contents)
{
dest->flags = idx;
+ if (shdr->bfd_section != NULL && (idx & GRP_COMDAT))
+ shdr->bfd_section->flags
+ |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
break;
}
if (idx >= shnum)
}
else
{
- struct elf_backend_data *bed;
- file_ptr pos;
- unsigned char ename[4];
- unsigned long iname;
const char *gname;
- /* Humbug. Get the name from the group signature
- symbol. Why isn't the signature just a string?
- Fortunately, the name index is at the same
- place in the external symbol for both 32 and 64
- bit ELF. */
- bed = get_elf_backend_data (abfd);
- pos = elf_tdata (abfd)->symtab_hdr.sh_offset;
- pos += shdr->sh_info * bed->s->sizeof_sym;
- if (bfd_seek (abfd, pos, SEEK_SET) != 0
- || bfd_bread (ename, (bfd_size_type) 4, abfd) != 4)
+ gname = group_signature (abfd, shdr);
+ if (gname == NULL)
return false;
- iname = H_GET_32 (abfd, ename);
- gname = elf_string_from_elf_strtab (abfd, iname);
elf_group_name (newsect) = gname;
/* Start a circular list with one element. */
elf_next_in_group (newsect) = newsect;
}
+
if (shdr->bfd_section != NULL)
elf_next_in_group (shdr->bfd_section) = newsect;
+
i = num_group - 1;
break;
}
return true;
}
+void
+bfd_elf_discard_group (abfd, group)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *group;
+{
+ asection *first = elf_next_in_group (group);
+ asection *s = first;
+
+ while (s != NULL)
+ {
+ s->output_section = bfd_abs_section_ptr;
+ s = elf_next_in_group (s);
+ /* These lists are circular. */
+ if (s == first)
+ break;
+ }
+}
+
/* Make a BFD section from an ELF section. We store a pointer to the
BFD section in the bfd_section field of the header. */
The symbols will be defined as weak, so that multiple definitions
are permitted. The GNU linker extension is to actually discard
all but one of the sections. */
- if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
+ if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0
+ && elf_next_in_group (newsect) == NULL)
flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
bed = get_elf_backend_data (abfd);
return true;
case SHT_GROUP:
- /* Make a section for objcopy and relocatable links. */
+ /* We need a BFD section for objcopy and relocatable linking,
+ and it's handy to have the signature available as the section
+ name. */
+ name = group_signature (abfd, hdr);
+ if (name == NULL)
+ return false;
if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name))
return false;
if (hdr->contents != NULL)
unsigned int n_elt = hdr->sh_size / 4;
asection *s;
+ if (idx->flags & GRP_COMDAT)
+ hdr->bfd_section->flags
+ |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+
while (--n_elt != 0)
if ((s = (++idx)->shdr->bfd_section) != NULL
&& elf_next_in_group (s) != NULL)
while (elt != elf_next_in_group (l->u.indirect.section));
loc -= 4;
- H_PUT_32 (abfd, 0, loc);
+ H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
BFD_ASSERT (loc == sec->contents);
}